Codebase list libjdom2-intellij-java / upstream/2.0.6+git20180529
Import upstream snapshot 2.0.6+git20180529 Andrej Shadura 5 years ago
423 changed file(s) with 114823 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 #FindBugs User Preferences
1 #Tue Sep 20 20:18:08 EDT 2011
2 detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true
3 detectorBadAppletConstructor=BadAppletConstructor|false
4 detectorBadResultSetAccess=BadResultSetAccess|true
5 detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true
6 detectorBadUseOfReturnValue=BadUseOfReturnValue|true
7 detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true
8 detectorBooleanReturnNull=BooleanReturnNull|true
9 detectorCallToUnsupportedMethod=CallToUnsupportedMethod|false
10 detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true
11 detectorCheckTypeQualifiers=CheckTypeQualifiers|true
12 detectorCloneIdiom=CloneIdiom|true
13 detectorComparatorIdiom=ComparatorIdiom|true
14 detectorConfusedInheritance=ConfusedInheritance|true
15 detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true
16 detectorCrossSiteScripting=CrossSiteScripting|true
17 detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true
18 detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true
19 detectorDontIgnoreResultOfPutIfAbsent=DontIgnoreResultOfPutIfAbsent|true
20 detectorDontUseEnum=DontUseEnum|true
21 detectorDroppedException=DroppedException|true
22 detectorDumbMethodInvocations=DumbMethodInvocations|true
23 detectorDumbMethods=DumbMethods|true
24 detectorDuplicateBranches=DuplicateBranches|true
25 detectorEmptyZipFileEntry=EmptyZipFileEntry|true
26 detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true
27 detectorFinalizerNullsFields=FinalizerNullsFields|true
28 detectorFindBadCast2=FindBadCast2|true
29 detectorFindBadForLoop=FindBadForLoop|true
30 detectorFindCircularDependencies=FindCircularDependencies|false
31 detectorFindDeadLocalStores=FindDeadLocalStores|true
32 detectorFindDoubleCheck=FindDoubleCheck|true
33 detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true
34 detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true
35 detectorFindFinalizeInvocations=FindFinalizeInvocations|true
36 detectorFindFloatEquality=FindFloatEquality|true
37 detectorFindHEmismatch=FindHEmismatch|true
38 detectorFindInconsistentSync2=FindInconsistentSync2|true
39 detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true
40 detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true
41 detectorFindMaskedFields=FindMaskedFields|true
42 detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true
43 detectorFindNakedNotify=FindNakedNotify|true
44 detectorFindNonSerializableStoreIntoSession=FindNonSerializableStoreIntoSession|true
45 detectorFindNonSerializableValuePassedToWriteObject=FindNonSerializableValuePassedToWriteObject|true
46 detectorFindNonShortCircuit=FindNonShortCircuit|true
47 detectorFindNullDeref=FindNullDeref|true
48 detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true
49 detectorFindOpenStream=FindOpenStream|true
50 detectorFindPuzzlers=FindPuzzlers|true
51 detectorFindRefComparison=FindRefComparison|true
52 detectorFindReturnRef=FindReturnRef|true
53 detectorFindRunInvocations=FindRunInvocations|true
54 detectorFindSelfComparison=FindSelfComparison|true
55 detectorFindSelfComparison2=FindSelfComparison2|true
56 detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true
57 detectorFindSpinLoop=FindSpinLoop|true
58 detectorFindSqlInjection=FindSqlInjection|true
59 detectorFindTwoLockWait=FindTwoLockWait|true
60 detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true
61 detectorFindUnconditionalWait=FindUnconditionalWait|true
62 detectorFindUninitializedGet=FindUninitializedGet|true
63 detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true
64 detectorFindUnreleasedLock=FindUnreleasedLock|true
65 detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true
66 detectorFindUnsyncGet=FindUnsyncGet|true
67 detectorFindUselessControlFlow=FindUselessControlFlow|true
68 detectorFormatStringChecker=FormatStringChecker|true
69 detectorHugeSharedStringConstants=HugeSharedStringConstants|true
70 detectorIDivResultCastToDouble=IDivResultCastToDouble|true
71 detectorIncompatMask=IncompatMask|true
72 detectorInconsistentAnnotations=InconsistentAnnotations|true
73 detectorInefficientMemberAccess=InefficientMemberAccess|false
74 detectorInefficientToArray=InefficientToArray|true
75 detectorInfiniteLoop=InfiniteLoop|true
76 detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true
77 detectorInfiniteRecursiveLoop2=InfiniteRecursiveLoop2|false
78 detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true
79 detectorInitializationChain=InitializationChain|true
80 detectorInstantiateStaticClass=InstantiateStaticClass|true
81 detectorInvalidJUnitTest=InvalidJUnitTest|true
82 detectorIteratorIdioms=IteratorIdioms|true
83 detectorLazyInit=LazyInit|true
84 detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true
85 detectorLostLoggerDueToWeakReference=LostLoggerDueToWeakReference|true
86 detectorMethodReturnCheck=MethodReturnCheck|true
87 detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true
88 detectorMutableLock=MutableLock|true
89 detectorMutableStaticFields=MutableStaticFields|true
90 detectorNaming=Naming|true
91 detectorNumberConstructor=NumberConstructor|true
92 detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true
93 detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true
94 detectorPublicSemaphores=PublicSemaphores|false
95 detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true
96 detectorReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass=ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass|true
97 detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true
98 detectorRedundantInterfaces=RedundantInterfaces|true
99 detectorRepeatedConditionals=RepeatedConditionals|true
100 detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true
101 detectorSerializableIdiom=SerializableIdiom|true
102 detectorStartInConstructor=StartInConstructor|true
103 detectorStaticCalendarDetector=StaticCalendarDetector|true
104 detectorStringConcatenation=StringConcatenation|true
105 detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true
106 detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true
107 detectorSwitchFallthrough=SwitchFallthrough|true
108 detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true
109 detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true
110 detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true
111 detectorURLProblems=URLProblems|true
112 detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true
113 detectorUnnecessaryMath=UnnecessaryMath|true
114 detectorUnreadFields=UnreadFields|true
115 detectorUseObjectEquals=UseObjectEquals|false
116 detectorUselessSubclassMethod=UselessSubclassMethod|false
117 detectorVarArgsProblems=VarArgsProblems|true
118 detectorVolatileUsage=VolatileUsage|true
119 detectorWaitInLoop=WaitInLoop|true
120 detectorWrongMapIterator=WrongMapIterator|true
121 detectorXMLFactoryBypass=XMLFactoryBypass|true
122 detector_threshold=2
123 effort=default
124 excludefilter0=FindBugsExcludeFilter.xml
125 filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,MT_CORRECTNESS,PERFORMANCE,STYLE|false
126 filter_settings_neg=MALICIOUS_CODE,NOISE,I18N,SECURITY,EXPERIMENTAL|
127 includefilter0=FindBugsIncludeFilter.xml
128 run_at_full_build=false
0 /.classpath
1 /.project
2 /.idea/inspectionProfiles
3 /ebuild
4 /.settings
5 /build
6 /cobertura.ser
7 /build.properties
8 /bin
0 <?xml version="1.0" encoding="UTF-8"?>
1 <project version="4">
2 <component name="CompilerConfiguration">
3 <wildcardResourcePatterns>
4 <entry name="!?*.java" />
5 <entry name="!?*.form" />
6 <entry name="!?*.class" />
7 <entry name="!?*.groovy" />
8 <entry name="!?*.scala" />
9 <entry name="!?*.flex" />
10 <entry name="!?*.kt" />
11 <entry name="!?*.clj" />
12 </wildcardResourcePatterns>
13 </component>
14 </project>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <project version="4">
2 <component name="Encoding">
3 <file url="PROJECT" charset="UTF-8" />
4 </component>
5 </project>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <project version="4">
2 <component name="GradleSettings">
3 <option name="linkedExternalProjectsSettings">
4 <GradleProjectSettings>
5 <option name="distributionType" value="WRAPPED" />
6 <option name="externalProjectPath" value="$PROJECT_DIR$" />
7 <option name="modules">
8 <set>
9 <option value="$PROJECT_DIR$" />
10 <option value="$PROJECT_DIR$/contrib" />
11 <option value="$PROJECT_DIR$/core" />
12 <option value="$PROJECT_DIR$/test" />
13 </set>
14 </option>
15 <option name="useAutoImport" value="true" />
16 </GradleProjectSettings>
17 </option>
18 </component>
19 </project>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <project version="4">
2 <component name="ExternalStorageConfigurationManager" enabled="true" />
3 <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
4 <output url="file://$PROJECT_DIR$/classes" />
5 </component>
6 </project>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <project version="4">
2 <component name="VcsDirectoryMappings">
3 <mapping directory="" vcs="Git" />
4 </component>
5 </project>
0 !!! This file is no longer maintained. Please see the GitHub Commits !!!
1 https://github.com/hunterhacker/jdom/commits/master
2
3
4 * * * * * * JDOM 1.1.1 (tag: jdom_1_1_1) from JDOM 1.1 * * * * * *
5
6 Fixed a synchronization issue in the Namespace class that could cause a
7 hang when doing concurrent builds.
8
9 Added output support for Unicode surrogate pairs.
10
11 Added a new flag on SAXBuilder named setFastReconfigure() which, when set,
12 can speed reconfiguration by skipping repeated attempts to set features that
13 are determined not to be present on a parser. Useful when doing many builds
14 per second.
15
16 Updated the provided Jaxen library from a modified Jaxen 1.0 to the latest
17 which is Jaxen 1.1.1.
18
19 Added reflection code in the error reporting system to support Android's
20 Dalvik VM which doesn't have the java.rmi.* classes.
21
22
23 * * * * * * JDOM 1.1 (tag: jdom_1_1) from JDOM 1.0 * * * * * *
24
25 Added an additional constructor to JDOMSource with an EntityResolver which is
26 passed to the internal DocumentReader allowing the SAXOutputter to properly
27 resolve DTDs.
28
29 Added a forceNamespaceAware property to DOMOutputter which specifies you want
30 a DOM constructed with namespaces even if the source JDOM document has no
31 namespaces.
32
33 Added support for attribute "INF" and "-INF" values, to indicate positive and
34 negative infinity, as XML Schema allows.
35
36 Moved isXMLWhitespace() method from private in XMLOutputter to public in
37 Verifier.
38
39 Clarified XMLOutputter behavior with newlines and indents:
40 setIndent(" ") means newlines and " " indents
41 setIndent("") means newlines and "" indents
42 setIndent(null) means no newlines and no indents
43
44 Added set/getIgnoringBoundaryWhitespace() methods and features to SAXBuilder
45 and SAXHandler.
46
47 Added a setFactory() method on XSLTransformer to control the object types
48 built by the transform.
49
50 Added a string constant for the JDOM_OBJECT_MODEL_URI used by JAXP 1.3. It
51 deserves being part of the public API.
52
53 Fixed bug in SAXOutputter where default namespaces would be declared as
54 xmlns:="" with a spurious colon.
55
56 Fixed bug when using attributes without a namespace and outputting to a
57 JDOMResult.
58
59 Removing check that a comment not start with a hyphen. A careful reading of
60 production 15 in the XML 1.0 spec indicates leading hyphens are in fact
61 allowed.
62
63 Fixed bug where outputFragment() on SAXOutputter could cause a
64 NullPointerException because the locator would be null during the call.
65
66 Fixed bug where serializing ElementFilter causes a NullPointerException if the
67 filter has no assigned namespace
68
69 Fixed some subtle bad behaviors in listIterator.add() logic, using brand new
70 iterator logic.
71
72 Allowed a String to be passed to ContentList.add(int, Object).
73
74 Simplified JDOMAbout and renamed info.xml to jdom-info.xml, so
75 getResourceAsStream() won't suffer any name collision.
76
77 Fixed tiny issue where CDATA could be set with illegal character content.
78
79 Added logic to escape some special characters in namespace URIs.
80
81 Fixed bug where the attribute type would change on a setAttribute() call.
82
83 Improved performance on Namespace handling.
84
85 Improved and clarified Javadocs.
86
87
88 * * * * * * JDOM 1.0 (tag: jdom_1_0) from JDOM Beta10 * * * * * *
89
90 Added a new lib/jaxen-jdom.jar that solves some XPath ancestry problems
91 introduced by the Parent interface. See the new lib/jaxen.readme for
92 details.
93
94 Moved the addContent() and setContent() methods from Parent into Element and
95 Document directly. This re-enables method chaining that some people missed.
96
97 Fixed a few bugs in SAXOutputter: start/endPrefixMapping was not being fired
98 for no namespace, DocType was being improperly constructed, changed to use a
99 DefaultHandler with the dtd parser to better suppress unimportant problems.
100
101 Added SAXOutputter support for outputting fragments of documents with the
102 new methods:
103 output(Content)
104 outputFragment(List)
105 outputFragment(Content)
106
107 Added support in XMLOutputter for ignoring the JAXP processing instructions
108 <?javax.xml.transform.enable-output-escaping?> and
109 <?javax.xml.transform.disable-output-escaping?>. Respect for these PIs is
110 toggled by the Format.set/getIgnoreTrAXEscapingPIs() feature, default false.
111
112 Added to JDOMFactory the methods document(Element rootElement, DocType
113 docType, String baseURI) and entityRef(String elementName, String systemID).
114 These match constructors that were previously overlooked. Also added
115 implementations to DefaultJDOMFactory and UnverifiedJDOMFactory.
116
117 Added to Element the method getParentElement() that returns the parent element
118 or null if the object is unattached or the root element.
119
120 Fixed bug in FilterIterator that affected next() calls.
121
122 Fixed bug in DOMOutputter regarding extraneous namespace declarations
123 appearing under certain conditions.
124
125 Changed XMLOutputter to clone the Format objects when they're set/get
126
127 Fixed bug in JDOMResult where the result list could include incomplete
128 results in certain situations, fixed by forcing a flush.
129
130 Made SAXHandler.flushCharacters() protected again after being private. It's
131 needed for the above fix.
132
133 Changed Verifier.isXXX() methods from private to public as it was well
134 argued that they're based on unchanging spec productions and can be
135 generally useful even apart from JDOM.
136
137 Added support for surrogate pairs in the Verifier. (Surrogate pairs don't
138 yet have any special output support.)
139
140 Fixed bug in SAXBuilder to avoid an IllegalStateException when apps access
141 the partial document when parse failure occurs right after the beginning of
142 the parse.
143
144 Updated JaxenXPath to avoid the deprecated XPath.valueOf().
145
146 Brought the jdom-contrib ElementScanner up to date.
147
148 Fixed various Javadoc typos.
149
150 Removed the build-time dependence on saxpath.jar.
151
152 Removed all deprecated methods.
153
154 Fixed bug where in "pretty print" output EntityRef instances would erroneously
155 print on their own line.
156
157 Added character encoding rules to improve whitespace round tripping:
158 http://lists.denveronline.net/lists/jdom-interest/2003-July/013227.html
159
160 Added DOMBuilder.getFactory() method to match what we added to SAXBuilder.
161
162 Removed Parent.canContain() and the Document and Element implementations.
163 Moved the logic directly into ContentList. No reason to expose a public
164 method unless it has a general purpose.
165
166 Reduced the visibility on some XMLOutputter internals that we don't want to
167 guarantee support for over the long term. Some people who want custom output
168 formatting may need to copy some code blocks. That's OK since JDOM is open
169 source and while it's less than ideal, it's better than our exposing protected
170 internal variables and methods that we may have reason to change later.
171 Now marked private:
172 userFormat
173 printString()
174 printContentRange()
175 printTextRange()
176 Now static final:
177 preserveFormat
178
179 Removed some unnecessary casts.
180
181 Made a few private methods static where it made sense. Also a select
182 few protected methods.
183
184 Made the Format constructor private. It used to be pkg protected which
185 doesn't make a lot of sense.
186
187 Removed equals() from AbstractFilter since it's better to let concrete
188 subclasses define that, as they already were.
189
190 Removed some unnecessary instanceof and != null checks.
191
192 --
193 Added an UncheckedJDOMFactory class which builds without doing any
194 content or structure checks, letting you gain speed in a situation
195 where you have 100% confidence in your parser. The Javadocs for
196 the class naturally includes a serious warning.
197
198 It's not used by default, but you can select it with a
199 builder.setFactory(new UncheckedJDOMFactory()) call.
200
201 I also added to JDOMFactory a few methods:
202 addContent(Parent, Content)
203 setAttribute(Element, Attribute)
204 addNamespaceDeclaration(Element, Namespace)
205
206 These are called during the build to do the adds. The default builder
207 just calls parent.addContent(Content) while the "unchecked" factory does
208 the work without checks using package protected methods on ContentList
209 and AttributeList.
210
211 A perk of having these methods in the factory and used by the builder
212 is you can write a custom factory to do certain things during the adds.
213 Like you could ignore all elements named "foo" by not doing the add if
214 the Content was an Elt foo. That's not perfect since the elements
215 underneath foo would still be built into a subtree that got ignored,
216 but it's an easy solution to save memory in the resulting document.
217 --
218
219 * * * * * * Beta10 (tag: jdom_1_0_b10) from Beta9 * * * * * *
220
221 PARENT AND CONTENT
222 ------------------
223
224 Added a new Parent interface and a new Content abstract class. Parent is
225 implemented by Document and Element. Content is extended by Element, Comment,
226 DocType, EntityRef, ProcessingInstruction, and Text (CDATA).
227
228 Parent has methods (* means new):
229 Parent addContent(Content child);
230 * Parent addContent(Collection collection);
231 * Parent addContent(int index, Content child);
232 * Parent addContent(int index, Collection collection);
233 * List cloneContent();
234 * void canContain(Content, int);
235 List getContent();
236 List getContent(Filter filter);
237 * Content getContent(int index);
238 * int getContentSize();
239 * Iterator getDescendants()
240 * Iterator getDescendants(Filter)
241 * Document getDocument()
242 * Parent getParent()
243 * int indexOf(Content)
244 * List removeContent();
245 boolean removeContent(Content child);
246 * List removeContent(Filter filter);
247 * Content removeContent(int index);
248 Parent setContent(Content child);
249 Parent setContent(Collection collection);
250 * Parent setContent(int index, Content child);
251 * Parent setContent(int index, Collection collection);
252 Object clone();
253
254 Content has public methods:
255 Content detach();
256 Document getDocument();
257 Parent getParent();
258 * String getValue();
259 Object clone();
260
261 The new methods on Parent are pretty self explanatory. A few methods that used
262 to require getting the content List now work on Parent itself for convenience
263 (tired of all those FAQs). The cloneContent() and removeContent() calls
264 should be especially helpful. The getDescendants() methods is great in
265 providing a mechanism to walk the entire tree from this item down using an
266 optional filter.
267
268 The getValue() method in Content is defined to return the XPath 1.0 string
269 value of the element. The getText() methods in Element are left unchanged.
270
271 A subtle change is that getParent() now returns a Parent type which is its
272 immediate parent. Previously an item at the document level would return null
273 and you'd use getDocument() to get its Document. Parent has getParent() as
274 well to make repeated getParent() calls easier.
275
276 The protected setDocument() methods have been removed in favor of just using
277 setParent(). getDocument() remains as a potentially recursive lookup method.
278
279
280 NEW CLASSES
281 -----------
282
283 Added an org.jdom.transform.XSLTransformer class to help with simple
284 transformations. It's a one-liner now, the way it should be. Also added an
285 XSLTransformException class to support the XSLTransformer.
286
287 Added an org.jdom.output.Format class to control XMLOutputter behavior.
288 Format has convenience methods .getRawFormat(), .getPrettyFormat(), and
289 .getCompactFormat() to use in lieu of people having to remember when to trim,
290 set indents, and such. The old XMLOutputter.set*() methods are now deprecated
291 and should be called on a Format instance. The XMLOutputter constructors that
292 took indents and so on are also deprecated.
293
294 Added an EscapeStrategy plug-in interface for XMLOutputter to determine which
295 chars to escape. A user can set a strategy and go, no need to subclass.
296
297 Created a DefaultEscapeStrategy which tries to be generally smart. It quickly
298 says no escaping is necessary for UTF-8 (our default) and UTF-16. It escapes
299 everything above 255 for ISO-8859-1/Latin1. It escapes everything above 127
300 for ASCII. For the other charsets, it tries to use the JDK 1.4 CharsetEncoder
301 to determine if the char needs escaping. Reflection is used for this so JDOM
302 isn't dependent on JDK 1.4. That means if you run on JDK 1.3 there's no
303 escaping unless JDOM knows about the charset itself or you plug in your own.
304
305 Added a Format.TextMode inner class with values: PRESERVE, TRIM, NORMALIZE,
306 and TRIM_FULL_WHITE. Removed the methods setTextTrim(), setTextNormalize(),
307 and setTrimAllWhite(). Replaced them with setTextMode(Format.TextMode) and
308 getTextMode().
309
310 Moved org.jdom.input.JDOMFactory and org.jdom.input.DefaultJDOMFactory into
311 the org.jdom package.
312
313
314 NEW METHODS
315 -----------
316
317 Added Document.setBaseURI(String) and getBaseURI() to record the effective URI
318 from which the document was loaded (against which relative URLs in the
319 document should be resolved). The builders record the URI when possible.
320
321 Added a Document(Element, DocType, String baseURI) constructor.
322
323
324 ENHANCEMENTS
325 ------------
326
327 Incorporated Jaxen 1.0 and Xerces 2.6.1.
328
329 Enhanced the filter classes so they extend a new AbstractFilter class and
330 inherit its and(), or(), and negate() methods.
331
332 Added proper hashCode() methods to the filters.
333
334 Changed the Document's DocType storage so it's part of the ContentList now and
335 has a location that can be preserved. This helps with round tripping. The
336 getDocType() and setDocType() methods remain for convenience but just operate
337 based on searches through the ContentList. Adding logic to ensure the DOCTYPE
338 isn't added after the root, or vice-versa.
339
340 The Attribute class now trims its value before attempted conversion to a
341 double, float, or boolean values. Also "1" and "0" are legal boolean values
342 following the lead of Schema.
343
344 Added better support for loading from files whose names have special
345 characters like #.
346
347 Added a protected SAXHandler.flushCharacters(String) method to allow
348 subclassers to have more control over strings.
349
350
351 BUG FIXES
352 ---------
353
354 Fixed bug in AttributeList.clear() where the cleared list did not reset its
355 size to 0, causing NullPointerException when the list was reused.
356
357 Fixed bug where serializing a content list using a filter. It wouldn't work
358 because FilterList wasn't serializable. It is now.
359
360 Fixed bug in ContentList that could theoretically cause problems during
361 reverse iteration.
362
363 Changed JDOMException.initCause() to return "this" instead of "cause"
364 since that's what Throwable says it should do.
365
366 Fixed bug with elt.isAncestor() where it had been acting like "is descendant".
367
368 Fixed bug in DOMOutputter where it could have problems outputting documents
369 with a DocType.
370
371
372 DEPRECATED METHODS
373 ------------------
374
375 Deprecated the Document(List, DocType) constructor because it doesn't make
376 sense if the DocType should be part of the content list rather than separate.
377
378 Deprecated the XMLOutputter.set*() methods that now reside in Format.
379
380 Deprecated the XMLOutputter constructors that took format parameters. Use the
381 constructor that accepts a Format now instead.
382
383 Deprecated the Attribute constants:
384 Attribute.CDATA_ATTRIBUTE
385 Attribute.ID_ATTRIBUTE
386 Attribute.IDREFS_ATTRIBUTE, etc.
387 Their new names are simpler:
388 Attribute.CDATA_TYPE
389 Attribute.ID_TYPE
390 Attribute.IDREFS_TYPE, etc.
391
392 Renamed methods from the PI class to be more consistent and explanatory.
393 Deprecating:
394 getNames()
395 getValue()
396 setValue()
397 removeValue()
398 New names:
399 getPseudoAttributeNames()
400 getPseudoAttributeValue()
401 setPseudoAttribute()
402 removePseudoAttribute()
403
404 Deprecated the methods setTextTrim(), setTextNormalize(), and
405 setTrimAllWhite(). Replaced them with setTextMode(Format.TextMode) and
406 getTextMode().
407
408 Changed the protected method SAXHandler.setAlternateRoot() to pushElement().
409
410
411 REMOVED CLASSES
412 ---------------
413
414 None.
415
416
417 REMOVED METHODS
418 ---------------
419
420 Removed everything deprecated in b9. (JDOM deprecates for one beta cycle,
421 then removes.)
422
423 Made the DOMOutputter output(Element, ...) and output(Attribute, ...) private.
424 They used to be protected. Skipped the deprecation step because you couldn't
425 actually extend them because of the NamespaceStack visibility, and we don't
426 usually deprecate protected methods.
427
428
429 SPECIAL NOTE
430 ------------
431
432 Reduced the visibility on many items from protected to private. Anything
433 protected or public must be supported in the future, and we don't want to
434 promise that for anything unless it's absolutely necessary. If your JDOM
435 extension has problems with the reduced visibility that can't be overcome,
436 write to jdom-interest-AT-jdom.org with your issue. We'll crack open the
437 visibility as proven necessary.
438
439
440 * * * * * * Beta9 (tag: jdom_1_0_b9) from Beta8 * * * * * *
441
442 NEW PACKAGES
443 ------------
444
445 Added org.jdom.xpath package for XPath manipulations.
446
447
448 NEW CLASSES
449 -----------
450
451 Added the XPath and JaxenXPath classes to the new org.jdom.xpath package.
452
453 Added org.jdom.input.JDOMParseException, a subclass of JDOMException, to be
454 thrown by the builders to convey whatever information could be gathered from
455 the parser about the error. It has a getPartialDocument() that gives access
456 to whatever part of the input document that was successfully parsed before the
457 parser fired a SAXParseException.
458
459 Added org.jdom.output.JDOMLocator, an implementation of org.xml.sax.Locator
460 which a ContentHandler could use to determine the document object on which an
461 error occurred.
462
463
464 NEW METHODS
465 -----------
466
467 Added the the getResult()/setResult() methods to JDOMResult to support
468 transformations that return results other than a document.
469
470 Added saxBuilder.setReuseParser(boolean) with a default of false. Turning it
471 on allows reuse and faster performance for parsers that support reuse.
472
473 Added a ProcessingInstruction.setTarget(String newTarget) method. Once we
474 decided to allow elt.setName() we should allow pi.setTarget().
475
476 Added a SAXOutputter.getLocator() method to make the locator available outside
477 the ContentHandler. For example, this allows you to have ErrorHandlers not
478 implementing XMLFilters.
479
480
481 ENHANCEMENTS
482 ------------
483
484 Fixed the TextBuffer performance problem that made performance terrible on
485 certain JVMs in beta8.
486
487 Changed CDATA to extend Text so now you can look just for Text nodes
488 in content and don't need to differentiate CDATA sections if you don't
489 want to. This does require "instanceof CDATA" to come before "instanceof
490 Text" now. Watch out for that potential subtle bug.
491
492 Changed the exception types that may be thrown from the SAXBuilder. The idea
493 is that SAXBuilder should throw an IOException for an I/O error, a
494 JDOMException for an XML problem, and that unexpected runtime exceptions
495 should not be hidden. Previously it could only throw a JDOMException, so this
496 will break existing code! Builders will now need to catch IOException.
497
498 Changed the DOM adapter classes to throw either IOException, a JDOMException
499 wrapped around a parser-specific exception, or a subtype of RuntimeException.
500 Previously they might throw any Exception.
501
502 Changing doctype.equals() to be == instead of comparing its elt name, system
503 id, and public id. Did this because someone may not care about the elt name
504 in comparing doc types, while someone else might care about the internal DTD
505 subset. This lets the default behavior be == and lets users write their own
506 equality check.
507
508 Added a feature to prevent firing DTD events by setting the SAX core feature
509 "http://xml.org/sax/features/validation" to false.
510
511 Removed the special namespace treatment of xml:space and xml:lang so they are
512 now treated as any other attributes in a namespace.
513
514 Enhanced SAXOutputter to notify of entities through ContentHandler's
515 skippedEntity() and notify of some errors to the registered SAX ErrorHandler,
516 Added support to output Comments as Element children. Added support for CDATA
517 (i.e. distinguish CDATA from plain text and use of the start/endCDATA
518 callbacks of LexicalHandler). Removed support for CDATA as children of the
519 document node.
520
521 Added CVS_ID and @version tags to source files that were missing them.
522
523 Added JDOM_FEATURE constants to JDOMSource and JDOMResult which can be used
524 with TransformerFactory.getFeature() to determine if the transformer natively
525 supports JDOM.
526
527 Moved the printing of the line seperator after the doctype up to
528 output(Document, Writer). This allows someone who doesn't want a newline
529 after the decl to kludge it away.
530
531 Improved the Verifier's checking of Comment contents. Added logic to ensure
532 you can't have two default namespace declarations on the same element.
533
534 Numerous performance improvements.
535
536 Many Javadoc improvements.
537
538 Numerous build script enhancements.
539
540 Moved samples into the default package, building to build/samples.
541
542
543 BUG FIXES
544 ---------
545
546 Fixed Document.clone() to set the new DocType.
547
548 Fixed a bug where the JDOMException.printStackTrace(PrintWriter) method would
549 print some data to System.err instead of to the writer.
550
551 Fixed bug in PI map parse logic which could be confused when there was a lot
552 of whitespace surrounding the = signs.
553
554 Fixed bug where AttributeList.set() would not set parentage in one situation.
555
556 Fixed bug where namespace prefixes were being lost on DOM builds.
557
558 Fixed bug in PI.toString() which could cause funny output on PIs without data.
559
560 Fixed a problem with the CDATA.clone() method that would result in CDATA
561 sections being cloned as Text objects rather than CDATA objects.
562
563 Fixed the SAXOutputter so elementContent() fires a comment() event.
564
565 Fixed bug where mapping a value to an attribute wouldn't happen if the
566 attribute was renamed.
567
568 Fixed bug in XMLOutputter where \n was used instead of
569 currentFormat.lineSeparator at one location.
570
571 Fixed a whitespace output bug where whitespace-only content would be treated
572 as empty.
573
574 Fixed bug where the "xml" prefix wasn't available in Element's
575 getNamespace(String) call.
576
577
578 DEPRECATED METHODS
579 ------------------
580
581 Deprecated the XMLOutputter.setIndent* methods except setIndent(String).
582
583 Deprecated DOMBuilder(boolean validate), DOMBuilder(String adapter, boolean
584 validate), and DOMBuilder.setValidation(boolean validate) because validation
585 only matters when building from files, and those methods have already been
586 deprecated.
587
588 Deprecated the DOMOutputter output methods that return a DOM Element or Attr,
589 because they aren't truly useful and the DOM contract is that every Attr and
590 Element (and every other Node too) always belongs to exactly one Document or
591 DocumentFragment object.
592
593 Deprecated element.removeChildren() because it's a nearly useless method.
594 Call element.getChildren().clear() in the very rare case you want to remove
595 only the children but leave other content.
596
597 Deprecated element.hasChildren() because it's not a performance optimization
598 anymore. This helps simplify the most complicated class around.
599
600 Deprecated element.setChildren(List) since element.setContent(List) suffices.
601
602 Deprecated xmlOutputter.outputString(String) since outputString(Text) handles
603 the Text nodes that now really reside within documents.
604
605
606 REMOVED CLASSES
607 ---------------
608
609 Removed ProjectXDOMAdapter since the parser is no longer important.
610
611
612 REMOVED METHODS
613 ---------------
614
615 Removed element.addContent(CDATA) and removeContent(CDATA) since
616 addContent(Text) and removeContent(Text) do the job now that CDATA extends
617 Text.
618
619 Removed canAdd() and canRemove() from Filter. matches() is sufficient.
620
621 Removed the methods deprecated in beta7.
622
623
624 SPECIAL NOTE
625 ------------
626
627 Beginning with this release JDK 1.1 is no longer supported. You'll need JDK
628 1.2 or later.
629
630
631 * * * * * * Beta8 (tag: jdom_1_0_b8) from Beta7 (tag: jdom_1_0_b7) * * * * * *
632
633 NEW CLASSES
634 -----------
635
636 Added a Text class. This class is primarily for internal use to store String
637 data, so strings can now have parentage. A getText() will still return a
638 String. The Text nodes themselves can be retrieved through a getContent()
639 call.
640
641 Added the public interface org.jdom.filter.Filter to support the "FilterList"
642 functionality.
643
644 Added org.jdom.filter.ContentFilter, a standard filter for Content. And added
645 org.jdom.filter.ElementFilter, a standard filter for Element data.
646
647 Added two non-public support classes to support the "FilterList"
648 functionality: ContentList and AttributeList.
649
650
651 NEW METHODS
652 -----------
653
654 Added to Element and Document the method getContent(Filter) that takes a
655 Filter instance.
656
657 Added to CDATA the methods getTextTrim(), getTextNormalize(), append(String),
658 append(CDATA), getParent(), getDocument(), and detach(). This brings CDATA
659 close in line with the Text class. They'll may become the same class with a
660 flag differentiator in the next beta.
661
662 Added to Element the methods addContent(Text) and removeContent(Text). These
663 methods support the new Text class.
664
665 Also added to Element the method removeAttribute(Attribute). This method was
666 simply overlooked before.
667
668 Also added to Element the method getChildTextNormalize(). This method is
669 similar to getChildTextTrim().
670
671 Also added to Element two new styles of getAttributeValue() which let the
672 programmer specify default values if the attribute doesn't exist.
673
674 Added to SAXBuilder the methods setFeature() and setProperty(). These methods
675 to allow programmers to customize the underlying parser.
676
677 Added to SAXOutputter the new method setLexicalHandler(LexicalHandler). Also
678 added a new SAXOutputter constructor that takes a LexicalHandler as its last
679 argument.
680
681 Added to ProcessingInstruction the method getNames(). This method returns the
682 pseudo-attribute names in the PI's data.
683
684 Added to DocType the methods setInternalDTDSubset(String) and
685 getInternalDTDSubset(). These methods support new functionality where a
686 DocType can store and alter the internal DTD subset information.
687
688 Also added to DocType the method setElementName().
689
690 Added a no-arg SAXOutputter constructor.
691
692 Added to SAXOutputter the methods getContentHandler(), getErrorHandler(),
693 getDTDHandler(), getEntityResolver(), getLexicalHandler(), setDeclHandler(),
694 getDeclHandler(), setFeature(), setProperty(), getFeature(), and
695 getProperty().
696
697 Added to Attribute the methods getAttributeType() and setAttributeType().
698 Also added various constructors that take an int type. These methods and
699 constructors support the new functionality where attributes can record their
700 type information. Note: this is something DOM can't do!
701
702 Added to Document the method detachRootElement().
703
704 Added to XMLOutputter the methods outputString(List list), outputString(String
705 str), outputString(Text text), output(List list, OutputStream out), and
706 output(List list, Writer out).
707
708 Added to EntityRef the constructor EntityRef(String name, String systemID).
709 This supports building an EntityRef without a public ID.
710
711 Added to Verifier the methods checkSystemLiteral() and checkPublicID().
712
713
714 NEW CONSTANTS
715 -------------
716
717 Attribute has new constants for each attribute type:
718 UNDECLARED_ATTRIBUTE, CDATA_ATTRIBUTE, ID_ATTRIBUTE, IDREF_ATTRIBUTE,
719 IDREFS_ATTRIBUTE, ENTITY_ATTRIBUTE, ENTITIES_ATTRIBUTE, NMTOKEN_ATTRIBUTE,
720 NMTOKENS_ATTRIBUTE, NOTATION_ATTRIBUTE, and ENUMERATED_ATTRIBUTE.
721
722
723 NEW SIGNATURES
724 --------------
725
726 The XMLOutputter escape*() methods are now public.
727
728 The Verifier checkXMLName() method is now public.
729
730 Changed the protected "Element parent" variable for classes to be "Object
731 parent", with the object capable of serving double duty as either a Document
732 parent or Element parent. Saves noticeable memory.
733
734 Changed the no-arg Document constructor to be public, along with Javadocs
735 explaining how the method is to be used.
736
737
738 REMOVED CLASSES
739 ---------------
740
741 None.
742
743
744 REMOVED METHODS
745 ---------------
746
747 Removed the methods deprecated in beta7.
748
749
750 DEPRECATED METHODS
751 ------------------
752
753 Deprecated the DOMBuilder.build() methods that build from a File, URL, or
754 InputStream. This helps people understand those methods are for testing only.
755 DOMBuilder.build(org.w3c.dom.Document) and such are still undeprecated.
756
757
758 ENHANCEMENTS
759 ------------
760
761 Added the long-awaited "FilterList" functionality! This improves the
762 reliability and performance of the lists returned by getContent() and
763 getChildren() calls. These lists are now fully live, they fully enforce
764 well-formedness constraints, and they don't require in-memory copying before
765 returning. A huge improvement!
766
767 Integrated the Text class for wrapping strings behind the scenes and thus
768 allowing strings to have parentage.
769
770 Added the ability for the DocType to have an internal DTD subset, and changed
771 the SAX and DOM builders and outputters to support this change.
772
773 Added the ability for a Document to have a detached root to make elt.detach()
774 work easily. There will be an IllegalStateException thrown in case of read
775 from such a Document.
776
777 Added support for "attribute types". Typing is now recorded within the
778 attribute object and fully managed during build and output.
779
780 Rearchitected the internals of SAXBuilder and SAXHandler to be more extensible
781 via subclassing. Also exposed more of the internals of SAXHandler to make
782 subclassing easier.
783
784 Made SAXOutputter much more robust, and made JDOMSource (used for
785 transformations) more robust along with it.
786
787 Changed setContent(null) to now clear the content list and does not throw an
788 exception. Same for setChildren(null).
789
790 Improved XMLOutputter to respect the xml:space attribute.
791
792 Improved reporting behavior of build error messages.
793
794 Improved how JDOMException reports on nested exceptions.
795
796 Updated the Ant build system to version 1.4.
797
798 Improved JDOM build versioning so we have versions like "1.0beta8-dev" for
799 work after Beta8, and "1.0beta8" will only be the actual Beta8 code.
800
801 Changed the Javadocs to use CVS Revision and Date tags for @version.
802
803 Many Javadoc clarifications.
804
805 Improved the Verifier error message when adding a PI with an "xml" target,
806 since parsers and/or people have been trying to add it as a PI.
807
808 Added verification of the system and public ID's in both DocType and
809 EntityRef, the root element name in DocType, and the entity name in EntityRef.
810
811 Added ability for DocType and EntityRef to differentiate a missing ID from the
812 empty string ID.
813
814 Changed the MANIFEST.MF to no longer list Xerces in the Class-Path entry, nor
815 to have JDOMAbout as its Main-Class. This helps applet deployment, but does
816 remove the ability to do the cool "java -jar jdom.jar".
817
818 Added support for skipped entities in SAXHandler in the event that the parser
819 is not resolving external entities.
820
821 Added well-formedness checking to ensure there are never duplicate attributes.
822
823 Many, many performance optimizations throughout.
824
825 Made Xerces 1.4.4 the default parser in "lib/xerces.jar".
826
827
828 BUG FIXES
829 ---------
830
831 Fixed XMLOutputter to no longer add spurious newlines after closing element
832 tags.
833
834 Fixed SAXBuilder to work better with XML filters.
835
836 Fixed SAXHandler bug where attributes that had a namespace were being added to
837 the Document, but did not have the Namespace correctly reported.
838
839 Fixed bug where a ProcessingInstruction or DocType removed from a Document did
840 not have its parentage set to null.
841
842 Fixed bug where SAXBuilder would cache the class name even when using JAXP to
843 create the parser, causing problems for parsers without no-arg constructors.
844
845 Fixed bug where Namespace collision checking could generate false positives.
846
847 Fixed bug where a document containing a huge number of character entities
848 would cause JDOM builds to slow down exponentially.
849
850 Fixed the many bugs caused by the old PartialList code, by replacing it with
851 FilterList code.
852
853
854 * * * * * * Beta7 (tag: jdom_1_0_b7) from Beta6 (tag: jdom_1_0_b6) * * * * * *
855
856 NEW CLASSES
857 -----------
858
859 Added JDOMSource and JDOMResult to the org.jdom.transform package. These
860 support XSLT transforms using the JAXP TrAX model. Added Crimson, JAXP, and
861 Xalan JARs to the lib directory to support the transform functionality.
862
863 Added org.jdom.EntityRef to replace org.jdom.Entity. Changed methods taking
864 Entity to take EntityRef.
865
866 Made org.jdom.input.SAXHandler a public class. It used to be package
867 protected. This is helpful to classes that want to build JDOM from a SAX
868 source, such as JDOMResult.
869
870 Added org.jdom.input.JDOMFactory/DefaultJDOMFactory to support the builder
871 factory model.
872
873 Added org.jdom.adapters.JAXPDOMAdapter to contain all the logic for
874 interacting with JAXP. Most people will never use this class.
875
876 Added org.jdom.Text to the repository. It's not yet used.
877
878
879 NEW METHODS
880 -----------
881
882 Added a new detach() method to each of the classes Attribute, Comment,
883 Element, EntityRef, and ProcessingInstruction. It removes the node from its
884 parent.
885
886 Added setName(String) and setNamespace(Namespace) to Element and Attribute.
887
888 Added elt.setAttribute() method, to replace elt.addAttribute(). It replaces
889 any existing attribute by the same name, instead of throwing an exception as
890 addAttribute() did.
891
892 Added elt.getContent() and elt.setContent() methods, to replace
893 elt.getMixedContent() and elt.setMixedContent(). Did the same on Document.
894
895 Added SAXBuilder.setExpandEntitities(boolean) method to indicate if entities
896 should be expanded, or if EntityRef objects should appear within the document.
897
898 Added two new Document constructors to support constructing with a list of
899 content:
900 Document(List)
901 Document(List, DocType)
902
903 Added elt.removeNamespaceDeclaration(Namespace). It removes a namespace
904 declaration, the counterpart to addNamespaceDeclaration(Namespace).
905
906 Added a new constructor in IllegalAddException to account for a Namespace
907 illegally added:
908 IllegalAddException(Element base, Namespace added, String reason)
909
910 Added getDocument() method to DocType. Added a protected setDocument() method
911 also.
912
913 Added setFactory() method to SAXBuilder/DOMBuilder to support the factory
914 build model.
915
916 Added elt.getTextNormalize() to return a normalized string (external
917 whitespace trimmed, internal whitespace reduced to a single space). The
918 getTextTrim() method now does a true trim.
919
920 Added a SAXBuilder.setIgnoringElementContentWhitespace(boolean) method with
921 behavior that matches the method by the same name in JAXP's
922 DocumentBuilderFactory. Setting the value to true causes
923 ignorableWhitespace() to operate like a no-op. By default its value is false.
924
925 Added getCause() to JDOMException, replacing getRootCause(). This new name
926 matches JDK 1.4.
927
928 Added setOmitDeclaration on XMLOutputter, replacing the now-deprecated
929 setSuppressDeclaration().
930
931 Added elt.removeContent(CDATA) which was previously overlooked.
932
933 Added protected methods in SAXBuilder to make it easier to extend:
934 protected XMLReader createParser()
935 protected SAXHandler createContentHandler()
936 protected void configureContentHandler(SAXHandler)
937
938 Added getDocument() method to Attribute.
939
940
941 NEW SIGNATURES
942 --------------
943
944 DOMAdapter methods now may throw Exception instead of IOException. DOMBuilder
945 and DOMOutputter have the same API as always.
946
947 Changed XMLOutputter's protected printXXX() methods to have a new signature
948 without the "int indentLevel" final parameter. Didn't bother with
949 deprecation.
950
951 Changed XMLOutputter's printEntity() method to printEntityRef().
952
953 Made SAXBuilder's build(InputSource) method public. It used to be protected.
954
955
956 REMOVED CLASSES
957 ---------------
958
959 Removed org.jdom.Entity; it's replaced by EntityRef.
960
961
962 REMOVED METHODS
963 ---------------
964
965 Removed various methods that were previously deprecated in beta6:
966 Document.addContent(Element)
967 Namespace.getNamespace(String prefix, Element context)
968 CDATA.setText(String)
969
970 Removed Document's protected rootElement variable.
971
972
973 DEPRECATED METHODS
974 ------------------
975
976 Deprecated constructor Attribute(String name, String prefix, String uri,
977 String value). Its parameter order was non-standard and it was not a useful
978 method.
979
980 Deprecated XMLOutputter's setIndentLevel() method. Having a global indent is
981 better done with a stacked FilterOutputStream. The method is now empty.
982
983 Deprecated XMLOutputter's setPadText() method. It's not needed with the
984 current output mechanism. The method is now empty.
985
986 Deprecated Element's getCopy(String) and getCopy(String, Namespace). These
987 can better be done now with a clone() and setName()/setNamespace().
988
989 Deprecated elt.addAttribute(). It's replaced by elt.setAttribute().
990
991 Deprecated getMixedContent() and setMixedContent() on Element and Document.
992 They're replaced by getContent() and setContent() versions.
993
994 Deprecated getSerializedForm() methods on all objects, and moved the logic
995 into XMLOutputter.
996
997 Deprecated the various xxxProcessingInstruction() methods in Document:
998 List getProcessingInstructions()
999 List getProcessingInstructions(String target)
1000 ProcessingInstruction getProcessingInstruction(String target)
1001 boolean removeProcessingInstruction(String target)
1002 boolean removeProcessingInstructions(String target)
1003 Document setProcessingInstructions(List pis)
1004
1005 Deprecated the SAXHandler constructor SAXHandler(Document document) since now
1006 the handler constructs the document itself.
1007
1008 Deprecated elt.hasMixedContent() because it's of little use and its behavior
1009 isn't well defined.
1010
1011 Deprecated getRootCause() on JDOMException in favor of getCause(). This new
1012 name matches JDK 1.4.
1013
1014 Deprecated XMLOutputter's setSuppressDeclaration() in favor of
1015 setOmitDeclaration() to better match setOmitEncoding().
1016
1017 Deprecated elt.addAttribute(String name, String prefix, String value).
1018 Instead, setAttribute() should be used.
1019
1020
1021 ENHANCEMENTS
1022 ------------
1023
1024 Clarified and improved many, many javadocs.
1025
1026 Performance enhancement for files with namespaces. This improves build times
1027 on one test from 13000ms to 580ms.
1028
1029 Added support for the DOM DocumentType object when constructing documents
1030 using DOMOutputter.
1031
1032 Added a check that only one element is allowed in the document list as the
1033 root.
1034
1035 Added informational XML files in the jdom.jar META-INF directory storing
1036 things like the version, credits, description, etc. These can be accessed
1037 with a "java -jar jdom.jar" command which uses JDOM to read the info about
1038 JDOM.
1039
1040 Added JDOM version info to the MANIFEST.MF so servlets and such can depend on
1041 it using http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html
1042
1043 Made elt.setMixedContent() check object types and parentage, and set
1044 parentage.
1045
1046 For the JDK 1.1 build, added a replace target so @throws is replaced by
1047 @exception, which is the old JDK 1.1 javadoc keyword.
1048
1049 Improved XMLOutputter internals so it no longer uses list.get(i) and instead
1050 uses an Iterator. Should lighten the burden on outputting large documents.
1051
1052 Added CVS Id variable to the top of each file for better tracking.
1053
1054 Changed pi.getValue("nonexistant") to return null instead of "". Also made it
1055 so that any parse error aborts and clears the parse results.
1056
1057 Created a new implementations of clone() without any constructor calls.
1058
1059 Revamped XMLOutputter's output logic to better match expectations.
1060
1061 Changed XMLOutputter flushing logic so output() methods handle their own
1062 flush() at the end of writing so user flush() calls should no longer be
1063 necessary.
1064
1065 Made elt.setMixedContent() and doc.setMixedContent() appear atomic, even in
1066 case of failure.
1067
1068 Optimized attr.getQualifiedName() implementation for speed.
1069
1070 Added logic to setAttribute() to ensure well-formedness by verifying the
1071 attribute namespace prefix doesn't collide with an existing prefix on that
1072 element (either on the element's own ns, an additional ns, or another
1073 attribute's ns).
1074
1075 Added logic to addNamespaceDeclaration() to ensure the prefix doesn't collide
1076 with an existing prefix on the element.
1077
1078 Changed DocType.equals() to check for equivalency and not reference equality.
1079 Now two DocTypes are equals() if their constituent strings are equals(). This
1080 makes general sense because if you want to compare the doctypes of two docs
1081 you want to do an equivalency check.
1082
1083 Added a private CVS_ID variable to the core classes containing RCS variables.
1084 This allows you to examine the compiled class to determine the source from
1085 which it was compiled. See jdom-contrib's Ident.java.
1086
1087 Performance optimization in setAttribute() so that removeAttribute() on a
1088 pre-existing attribute is only called when necessary, as determined by an
1089 earlier scan through the attributes. This was submitted by Phil Nelson who
1090 says it gave an 8% time savings during a fresh build.
1091
1092 Integrated the factory model for SAXBuilder. See the new classes
1093 DefaultJDOMFactory and JDOMFactory.
1094
1095 Changed Element.getTextTrim() behavior to truly be only a trim(). It used to
1096 do normalization.
1097
1098 Changed Document and Element internal LinkedList implementation to ArrayList.
1099 This change of list gives us a remarkable reduction in memory sizes for all
1100 large documents tested, and gives a speed boost too.
1101
1102 Changed Element parentage so only one variable is used for the parent. It may
1103 be of type Element or Document depending on where the elt is placed in the
1104 tree. This saves one instance variable's worth of memory for each element in
1105 the tree.
1106
1107 Added a new line after the DocType always, for better formatting.
1108
1109 Made the SAXHandler smart enough to ignore xmlns attributes. They shouldn't
1110 appear when SAXHandler is used with SAXBuilder but sometimes appear with
1111 driven by a different parser, such as with JDOMResult.
1112
1113 Made note that elt.getAdditionalNamespaces() returns an unmodifiable list, and
1114 made the implementation enforce the rule. This change allows
1115 Namespace.equals() to be implemented to compare URIs instead of resorting to
1116 ==, and more importantly it avoids having XMLOutputter trigger a new List
1117 object creation for every element with an empty additional namespace list
1118 (which is 99.9% of elements).
1119
1120 Refactored SAXBuilder to make it easier to extend.
1121 * The parser is created in a separate createParser() method, and
1122 configured in a separate configureParser() method.
1123 * The content handler is created in a separate createContentHandler()
1124 method, and configured in a separate configureContentHandler() method.
1125
1126 Improved builder exception handling to if anything in the build process throws
1127 a JDOMException, we no longer wrap it in another JDOMException; we just
1128 rethrow as-is.
1129
1130 Made XMLOutputter expose its NamespaceStack using an inner class, so
1131 subclassers could have access to the stack.
1132
1133
1134 BUG FIXES
1135 ---------
1136
1137 Fixed bug where Element.clone() didn't copy over PIs.
1138
1139 Made DOMOutputter check if there was a pre-existing root element on a new
1140 document, and if so call replaceChild() instead of appendChild(). This is
1141 necessary for Xerces 1.3 where new documents are created with a default
1142 <root/> element.
1143
1144 Fixed a bug where Attr output(Attribute) wasn't using JAXP.
1145
1146 Improved the logic by which ProcessingInstruction parses attribute-style
1147 values. The old logic was confused by whitespace, nested quotes, etc.
1148
1149 Added sanity check in DOMBuilder to ignores null NodeList and Node entries.
1150 Per the DOM2 spec neither should ever be null, but that doesn't mean some DOM
1151 implementations don't return null.
1152
1153 Fixed bug in Namespace.getNamespace() where the lookup for a pre-existing
1154 identical namespaces would fail even if there was a pre-existing identical
1155 namespace. This caused new Namespaces to be created on all
1156 Namespace.getNamespace() calls!
1157
1158 Fixed bug where elt.clone() would concatenate adjacent strings.
1159
1160 Fixed bug in elt.hasChildren() where the logic could be confused if there was
1161 a subclass of Element in the tree.
1162
1163 Fixed the Javadoc on Element.getAdditionalNamespaces() to say it returns an
1164 empty list if empty. It used to say null. Empty is consistent with JDOM
1165 elsewhere.
1166
1167 Fixed bug where adding a null to a setMixedContent() method would cause an NPE
1168 while constructing the error message.
1169
1170 Fixed bug in SAXHandler where namespaces weren't being removed from the
1171 available list, causing memory bloat.
1172
1173 Fixed DOMBuilder so it works better on non-namespace-aware documents. Now if
1174 getLocalName() returns null we look for a specific tagname/attname.
1175
1176 Added ignorableWhitespace() method to SAXHandler to capture ignorable
1177 whitespace. It can be turned off with
1178 builder.setIgnoringElementContentWhitespace(true).
1179
1180 Changed Namespace.equals() to check equivalency based only on URI. It used to
1181 be both URI and prefix. This new behavior is more in line with standard XML.
1182 It's unlikely but possible that existing code might break because of this, if
1183 any code puts Namespace objects into a collection and doesn't expect
1184 namespaces with different prefixes to be treated identically. No deprecation
1185 is possible though. Also fixed behavior of Namespace.hashCode() to depend
1186 solely on the URI.
1187
1188 Fixed bug where DOMOutputter creates nodes with "" as their
1189 node.getNamespaceURI() even if the node is not in a namespace.
1190
1191 Changed attribute value escaping to not escape single-quotes because it's not
1192 necessary as attribute values are always surrounded by double-quotes.
1193
1194 Made sure XMLOutputter doesn't print the newline after the decl if the decl is
1195 suppressed.
1196
1197 Fixed SAXOutputter to declare namespaces using start/endPrefixMapping methods.
1198 Also added optional ability for SAXOutputter to report namespace declarations
1199 (the xmlns: attributes) if setReportNamespaceDeclarations() is true.
1200
1201 Fixed performance bug where namespaces were continuously being added to the
1202 availableNamespaces list unnecessarily, causing roughly as many entries to be
1203 added as there were elements with namespaces. In simple testing, memory usage
1204 for representing a namespace-intensive file went from 1.4 Megs to 460K.
1205
1206 Fixed addFirst() and addLast() in PartialList to work correctly.
1207
1208 Fixed a bug in PartialList where addAll() added *before* the last element
1209 instead of after.
1210
1211 Made PartialList's addAll() method work OK if the backing list is non-empty
1212 while the PartialList is empty.
1213
1214 Fixed build scripts to work OK on Windows with spaces in directory paths.
1215
1216
1217 NEW ARCHIVES
1218 ------------
1219
1220 Added new *searchable* mailing list archives at
1221 http://www.servlets.com/archive/servlet/SummarizeList?listName=jdom-interest
1222
1223
1224 * * * * * * * * * * Beta6 from Beta5 * * * * * * * * * *
1225
1226 NEW CLASSES
1227 -----------
1228
1229 Added new class org.jdom.input.BuilderErrorHandler as a default error handler
1230 for JDOM builders. It ignores warnings but throws on errors and fatal errors.
1231
1232 Added a Crimson adapter CrimsonDOMAdapter.java, to support the parser slated
1233 to come with JAXP 1.1.
1234
1235
1236 NEW METHODS
1237 -----------
1238
1239 Added parentage for Attribute, Comment, Element, Entity, and PI! They all now
1240 have getParent() methods. All but Attribute have getDocument() methods also.
1241 The addContent() and addAttribute() methods now check parentage and don't
1242 allow an item to be added if it's already held by another.
1243
1244 Added to Element the method Namespace getNamespace(String prefix). It returns
1245 the Namespace in scope with the given prefix. It helps with attributes whose
1246 values include namespaces, like <xsl:template match="sg:title">.
1247
1248 Added DOMBuilder.setValidation(boolean) to set the validate flag after
1249 construction, to match SAXBuilder.
1250
1251 Added DOMOutputter.output(Attribute) methods.
1252
1253 Added XMLOutputter.setExpandEmptyElements() to choose between <empty/> and
1254 <empty></empty>.
1255
1256 Many new XMLOutputter methods for outputting document fragments.
1257
1258 SAXBuilder now has a setXMLFilter() method to allow setting of XMLFilter
1259 objects to operate during the build.
1260
1261 Added to Element a hasChildren() method.
1262
1263 Added various removeContent() methods on Element. They were deprecated and
1264 scheduled for removal, but they're now being kept.
1265
1266 Added various removeContent() methods on Document. These are brand new.
1267
1268
1269 NEW SIGNATURES
1270 --------------
1271
1272 Made clone() methods no longer final.
1273
1274 Made toString() methods no longer final.
1275
1276 Changed all outputter output() signatures to throw JDOMException in case of
1277 problem.
1278
1279 Changed DOMAdapter signature so getDocument(String filename, ...) is now
1280 getDocument(File filename, ...) to match the standard builder model. I did
1281 not do a deprecation because no one should be using this internal API
1282 directly, and if they are, I want to hear from them.
1283
1284
1285 REMOVED METHODS
1286 ---------------
1287
1288 Removed all methods marked deprecated in beta5.
1289
1290
1291 DEPRECATED METHODS
1292 ------------------
1293
1294 Marked Namespace.getNamespace(String prefix, Element context) deprecated
1295 because it had been replaced by the more elegant elt.getNamespace(String
1296 prefix).
1297
1298 Marked Document.addContent(Element) deprecated because there can be only one
1299 element and it's properly set with setMixedContent().
1300
1301 Marked CDATA.setText() as deprecated. This is because CDATA doesn't have
1302 parentage, and without parentage an object should be immutable.
1303
1304
1305 ENHANCEMENTS
1306 ------------
1307
1308 Added JAXP 1.1 support to SAXBuilder, DOMBuilder, and DOMOutputter. The
1309 default parser for all these is now the JAXP parser, with a fallback of Xerces
1310 if JAXP isn't available.
1311
1312 Added improved Verifier checks of well-formedness throughout all of JDOM.
1313 Among the most likely to be noticed:
1314 - Added Verifier detection of wrongly places "xmlns" attributes.
1315 - Added check in Attribute that a namespace with "" prefix must be
1316 NO_NAMESPACE.
1317 - Added Verifier checks so CDATA text cannot contain ">>]"
1318
1319 Upgraded provided parser to Xerces 1.2.
1320
1321 Improved SAXBuilder and DOMBuilder to be *much* smarter about namespaces.
1322 Most likely to be noticed:
1323 - DOMBuilder now keeps xmlns namespaces declaration location, and it now
1324 relies on the parser to handle namespaces (necessary for importing a
1325 document that has nodes moved around).
1326
1327 Made SAXBuilder and DOMBuilder much more specific on error reporting.
1328
1329 Brought DOMOutputter up to DOM Level 2 compliance.
1330 - Added logic to DOMOutputter to add xmlns attributes to the DOM tree
1331 where appropriate.
1332
1333 Added SAXOutputter to generate SAX events.
1334
1335 Improved documentation on clone() methods.
1336
1337 Changed XMLOutputter.escape*Entities() to protected from private to help
1338 subclasses.
1339
1340 Improved removeContent() to solve a Crimson performance problem regarding
1341 duplicate string entries.
1342
1343 Added logic to prevent an element from being added as a child or descendent of
1344 itself.
1345
1346 Optimized SAXBuilder list handling so retrievals and removes will most likely
1347 hit on their first try instead of their last try.
1348
1349 Added Namespace output to Element.toString() to help debugging element
1350 namespace issues.
1351
1352 Improved the Verifier.isXML*() methods to operate much faster.
1353
1354 XMLOutputter now prints new lines after the declaration, even if newlines are
1355 turned off for the rest of the document.
1356
1357 Made PI's getSerializedForm() smarter about spacing between target and data.
1358 Now if there is no data, there's no space added.
1359
1360 Guarantee XMLOutputter prints a new line at the end of each document, for
1361 better formatting, esp when printing to System.out.
1362
1363 Put samples in the "samples" package.
1364
1365
1366 BUG FIXES
1367 ---------
1368
1369 Fixed bug in XMLOutputter where "additional namespace" declarations would be
1370 output even if they were already declared by an ancestor.
1371
1372 Fixed bug where an element not in any namespace will still inherit the default
1373 namespace from an ancestor.
1374
1375 Added fix to recognize implicit "xml" namespace during
1376 Namespace.getNamespace() call.
1377
1378 Added fix so XMLOutputter no longer outputs XML_NAMESPACE.
1379
1380 Fixed Element.getDocument() behavior to work reliably.
1381
1382 Fixed Verifier to not see "xmlnsfoo" attributes as invalid.
1383
1384 Fixed Verifier to allow attribute names xml:lang and xml:space as special
1385 cases.
1386
1387 Improved all adapters to throw exceptions on error instead of printing stack
1388 traces.
1389
1390 Fixed Element.clone() to be a true deep copy.
1391
1392 Fixed bug in SAXBuilder that would throw an EmptyStackException if a PI
1393 appeared after the root element.
1394
1395 Fixed bug in doc.setMixedContent(List) so it now stores the new data
1396 correctly.
1397
1398 Made removeChildren() properly set parents to null, and to return true only if
1399 children were actually deleted.
1400
1401 Changed SAXBuilder's endPrefixMapping(String, String) to be
1402 endPrefixMapping(String) as it should have been so we now get the callback and
1403 can remove namespaces.
1404
1405 Fixed PartialList.addAll() to behave as specified.
1406
0 The following people are committers on the "jdom" repo.
1
2 DO NOT WRITE THESE PEOPLE FOR TECH SUPPORT. THEY WILL NOT ANSWER.
3 WRITE THE jdom-interest MAILING LIST AT http://jdom.org.
4
5 Jason Hunter <jhunter_AT_jdom_DOT_org> is project maintainer.
6
7 Rolf Lear <jdom_AT_tuis_DOT_net> is leading the JDOM 2.0 work.
8
0 <FindBugsFilter>
1
2 <Match>
3 <Package name="~org\.jdom2\.test\..*" />
4 </Match>
5 <Match>
6 <Class name="~Test.*" />
7 </Match>
8 <Match>
9 <Package name="~.*\.contrib\..*" />
10 </Match>
11
12 </FindBugsFilter>
0 <FindBugsFilter>
1
2 <Match>
3 <Package name="~org\.jdom2" />
4 </Match>
5 <Match>
6 <Package name="~org\.jdom2\..*" />
7 </Match>
8
9
10 </FindBugsFilter>
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
0 This is a patched versions of JDOM project which is used in IntelliJ Platform.
1 It's based on JDOM 2.0.x version and patched to restore compatibility with JDOM 1.1.
2
3 Introduction to the JDOM project
4 ================================
5
6 Please see the JDOM web site at http://jdom.org/
7 and GitHub repository at https://github.com/hunterhacker/jdom/
8
9 Quick-Start for JDOM
10 =====================
11 See the github wiki for a Primer on using JDOM:
12 https://github.com/hunterhacker/jdom/wiki/JDOM2-A-Primer
13
14 Also see the web site http://jdom.org/downloads/docs.html. It has links to
15 numerous articles and books covering JDOM.
16
17
18 Installing the build tools
19 ==========================
20
21 The JDOM build system is based on Apache Ant. Ant is a little but very
22 handy tool that uses a build file written in XML (build.xml) as building
23 instructions. For more information refer to "http://ant.apache.org".
24
25 The only thing that you have to make sure of is that the "JAVA_HOME"
26 environment property is set to match the top level directory containing the
27 JVM you want to use. For example:
28
29 C:\> set JAVA_HOME=C:\jdk1.6
30
31 or on Mac:
32
33 % setenv JAVA_HOME /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
34 (csh)
35 > JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home; export JAVA_HOME
36 (ksh, bash)
37
38 or on Unix:
39
40 % setenv JAVA_HOME /usr/local/java
41 (csh)
42 > JAVA_HOME=/usr/java; export JAVA_HOME
43 (ksh, bash)
44
45 That's it!
46
47
48 Building instructions
49 =====================
50
51 If you do not have the full source code it can be cloned from GitHub. The JDOM
52 project at https://github.com/hunterhacker/jdom has the instructions and source
53 URL to make the git clone easy.
54
55 You will need to have Apache Ant 1.8.2 or later, and you will need Java JDK 1.6
56 or later.
57
58 Ok, let's build the code. First, make sure your current working directory is
59 where the build.xml file is located. Then run "ant".
60
61 If everything is right and all the required packages are visible, this action
62 will generate a file called "jdom-2.x-20yy.mm.dd.HH.MM.zip" in the
63 "./build/package" directory. This is the same 'zip' file that is distributed
64 as the official JDOM distribution.
65
66 The name of the zip file (and the jar names inside the zip) is controlled by
67 the two ant properties 'name' and 'version'. The package is called
68 "${name}-${version}.zip". The 'official' JDOM Build process is done by
69 creating a file 'build.properties' in the 'top' folder of the JDOM code, and
70 it contains the single line (or whatever the appropriate version is):
71
72 version=2.0.0
73
74 If your favourite Java IDE happens to be Eclipse, you can run the 'eclipse' ant
75 target, and that will configure your Eclipse project to have all the right
76 'source' folders, and 'Referenced Libraries'. After running the 'ant eclipse'
77 target, you should refresh your Eclipse project, and you should have a project
78 with no errors or warnings.
79
80
81 Build targets
82 =============
83
84 The build system is not only responsible for compiling JDOM into a jar file,
85 but is also responsible for creating the HTML documentation in the form of
86 javadocs.
87
88 These are the meaningful targets for this build file:
89
90 - package [default] -> generates ./build/package/jdom*.zip
91 - compile -> compiles the source code
92 - javadoc -> generates the API documentation in ./build/javadocs
93 - junit -> runs the JUnit tests
94 - coverage -> generates test coverage metrics
95 - eclipse -> generates an Eclipse project (source folders, jars, etc)
96 - clean -> restores the distribution to its original and clean state
97 - maven -> generates the package, and makes a 'bundle' for maven-central
98
99 To learn the details of what each target does, read the build.xml file. It is
100 quite understandable.
101
102
103 Bug Reports
104 ===========
105
106 Bug reports go to the jdom-interest list at jdom.org. But *BEFORE YOU POST*
107 make sure you've tested against the LATEST code available from GitHub (or the
108 daily snapshot). Odds are good your bug has already been fixed. If it hasn't
109 been fixed in the latest version, then when posting *BE SURE TO SAY* which
110 code version you tested against. For example, "GitHub from October 3rd". Also
111 be sure to include enough information to reproduce the bug and full exception
112 stack traces. You might also want to read the FAQ at http://jdom.org to find
113 out if your problem is not really a bug and just a common misunderstanding
114 about how XML or JDOM works.
115
116
117 Searching for Information
118 =========================
119
120 The JDOM mailing lists are archived and easily searched at
121 http://jdom.markmail.org.
0 Items that need to be done:
1
2 --- ITEMS REMAINING BEFORE 1.1 ---
3
4 None!
5
6 --- ITEMS TO CONSIDER FOR 1.2 ---
7
8 * Integrate the contributed StAXBuilder.
9
10 * Rusty's "base uri" support for Element and the rest.
11
12 * Investigate a way to do in-memory validation. First step is probably
13 to get an in-memory representation of a DTD as per
14 http://xmlhack.com/read.php?item=626
15 http://www.wutka.com/dtdparser.html
16 http://lists.denveronline.net/lists/jdom-interest/2000-July/001431.html
17 http://lists.denveronline.net/lists/jdom-interest/2001-February/004661.html
18 Maybe new DTDValidator(dtd).validate(doc);
19 Then later new SchemaValidator(schema).validate(doc);
20 Could instead do doc.validate(dtd/schema) but then we'd have to dynamically
21 switch between recognizing DTDs and the various schemas.
22 The method would probably either throw InvalidDocumentException or might
23 take an ErrorHandler-style interface implementation if there are non-fatal
24 errors possible.
25 It'd also be possible to have a programmatic verifier, that determined for
26 example if an orderid="100" entry was valid against a database entry.
27 http://dcb.sun.com/practices/devnotebook/xml_msv.jsp
28 http://www.sun.com/software/xml/developers/multischema/
29
30 * Create an HTMLOutputter to handle the HTML specific aspects (closing tags,
31 escaped characters like &eacute;, etc).
32
33 --- FUTURE IDEAS ---
34
35 * Utility methods for comparing nodes by content instead of reference.
36 Hopefully base this on whatever standard emerges in this area.
37
38 * Note in the docs where necessary our multithreading policy.
39
40 * Create a JDOM logo.
41
42 * Look at http://www.sosnoski.com/opensrc/xmls/format.html.
43
44 * Look at interfaces for the core classes, Element with ConcreteElement being
45 our code. Base on the factory model. Allow no access between objects
46 except using the public API, to avoid the import node problem. Do the big
47 switchover using javax.xml.jdom as interfaces and default impl, use org.jdom
48 for the concretes. May not need to break existing code (sick and wrong).
49 - read-only? Experimentation happening in jdom-javax module.
50
51 * Ensure JDOM is appropriately tweaked for subclassing, per the threads
52 started by Joe Bowbeer.
53 http://www.servlets.com/archive/servlet/ReadMsg?msgId=7601 begins it
54
55 * Ensure JDOM is flawless regarding clone semantics, per more threads by
56 Joe Bowbeer.
57 http://www.servlets.com/archive/servlet/ReadMsg?msgId=7602 begins it
58
59 * Joe summarizes his issues at
60 http://www.servlets.com/archive/servlet/ReadMsg?msgId=7697
61
62 * Add in attribute type support to DOM to match what's in SAX.
63
64 * Look into implementing an id() method now that we have attribute types.
65
66 * Look into how the factory builder model could support giving the factory
67 extra knowledge about the context (line number, element stack, etc), and
68 allow it to report errors or to return a code indicating the element should
69 be ignored.
70 (Laurent Bihanic wrote JH a private email about this on Dec 28 2001.)
71
72 * Write a "GNU JAXP (i.e. AElfred) DOM adapter" (elharo looking into this).
73
74 * Create "build dist" for distribution
75 Use fixcrlf in dist (instead of package as currently done)
76 Probably include source with jdom.jar built
77
78 * Populate jdom-test. Hong Zhang <Hong.Zhang AT Sun.COM> once volunteered to
79 help with the J2EE CTS.
80
81 * Add setIgnoringAllWhitespace(boolean) method.
82
83 * Consider a listener interface so you could listen to doc changes.
84 (Probably after 1.1 honestly; this can be done through manual subclasses
85 already.) Some pertinent messages on this topic:
86 http://lists.denveronline.net/lists/jdom-interest/2000-July/001586.html
87 http://lists.denveronline.net/lists/jdom-interest/2000-July/001587.html
88 http://lists.denveronline.net/lists/jdom-interest/2000-July/001600.html
89
90 * Consider a "locator" ability for nodes to remember the line number on which
91 they were declared, to help debug semantic errors.
92 http://lists.denveronline.net/lists/jdom-interest/2000-October/003422.html
93
94 * Consider an XMLOutputter flag or feature to convert characters with well
95 known named character entities to their named char entity form instead of
96 numeric.
97
98 * Determine if DOMBuilder and DOMOutputter should transparently support DOM1.
99
100 * Create a builder based on Xerces' XNI, which will be more featureful and
101 probably faster than the one based on SAX.
102 See http://lists.denveronline.net/lists/jdom-interest/2001-July/007362.html
103 Some existing SAX limitations which hurt round-tripping:
104 * Can't tell if attribute values are included from the DTD, because SAX
105 doesn't tell if attributes are standalone/implicit
106 (See http://www.saxproject.org/apidoc/org/xml/sax/ext/Attributes2.html)
107 (Thought: could use a bit in the type value to save memory)
108 * Can't get access to retain the internal dtd subset unless entity
109 expansion is off
110 * Can't get access to whitespace outside the root element.
111
112 * Write a guide for contributors. Short summary:
113 Follow Sun's coding guidelines, use 4-space (no tab) indents, no lines
114 longer than 80 characters
115
116 * Consider a builder for a read-only document. It could "intern" objects to
117 reduce memory consumption. In fact, interning may be good for String
118 objects regardless.
119
120 * Consider having the license be clear org.jdom is a protected namespace.
121
122 * Think about the idea of using more inheritance in JDOM to allow
123 lightweight but not XML 1.0 complete implementations. For example Element
124 could have a superclass "CommonXMLElement" that supported only what Common
125 XML requires. Builders could build such elements to be faster and lighter
126 than full elements -- perfect for things like reading config files. Lots
127 of difficulties with this design though.
128
129 * Create a Verifier lookup table as an int[256] growable to int[64K] where
130 bits in the returned value indicate that char's ability to be used for a
131 task. So "lookup[(int)'x'] & LETTER_MASK" tells us if it's a letter
132 or not.
133
134 * Consider an HTMLBuilder that reads not-necessarily-well-formed HTML and
135 produces a JDOM Document. The approach I'd suggest is to build on top of
136 JTidy first. That gives a working implementation fast, at the cost of a
137 157K Tidy.jar in the distribution. After that, perhaps someone would lead
138 an effort to change the JTidy code to build a JDOM Document directly,
139 instead of making a DOM Document or XML stream first. That would be a lot
140 faster, use less memory, and make our dist smaller. See
141 http://www.sourceforge.net/projects/jtidy for Tidy.
142 See post by Jacob.Robertson@argushealth.com on 2/13/2002.
143
144 * Look at a (contrib?) outputter option using SAX filters per
145 http://lists.denveronline.net/lists/jdom-interest/2000-October/003303.html
146 http://lists.denveronline.net/lists/jdom-interest/2000-October/003304.html
147 http://lists.denveronline.net/lists/jdom-interest/2000-October/003318.html
148 http://lists.denveronline.net/lists/jdom-interest/2000-October/003535.html
149
150 * Look at event-based parsing as per the following thread:
151 http://lists.denveronline.net/lists/jdom-interest/2000-November/003613.html
152 and replies.
153 Also see posts with the subject "streamdom".
154
155 * Considering that local vars are considerably faster that instance vars, test
156 if using local vars can speed building.
157
158 * Consider using a List of instance data so elements only use what they really
159 need (saving attrib list, namespace list)
160
161 * Investigate doc.getDescription() to let people add doc descriptions. It's
162 an idea from IBM's parser suggested by andyk.
163
164 * Work on creating a deferred builder that parses only what's necessary to
165 satisfy the programmer's requests. See Ayal Spitz' post at
166 http://lists.denveronline.net/lists/jdom-interest/2001-April/005685.html
167
168 * Change the various setAttributeValue() methods in Element and
169 Attribute to check the attribute type and normalize the string
170 according to the attribute type. i.e. normalize the white space if
171 the attribute has any type other than CDATA or UNDECLARED.
172
173 * Give attributes the "specified" flag like in DOM. This probably isn't
174 receivable from SAXBuilder, but it would be from DOMBuilder and other
175 builders. Then give XMLOutputter the ability to avoid outputting
176 "unspecified" attributes.
177
178 * Should there be XPath support within Element, Document, etc?
179
0 allprojects {
1 apply plugin: 'java'
2
3 repositories {
4 mavenCentral()
5 }
6 }
0 <!-- $Id: build.xml,v 1.57 2009/07/23 06:48:27 jhunter Exp $ -->
1
2 <!--
3 For instructions on how to build JDOM, please view the README.txt file.
4 -->
5
6 <project default="package" basedir=".">
7
8 <!-- =================================================================== -->
9 <!-- Initialization target -->
10 <!-- =================================================================== -->
11 <tstamp >
12 <format property="snapshot.time" pattern="yyyy.MM.dd.HH.mm" />
13 <format property="year" pattern="yyyy" />
14 </tstamp>
15
16 <!--
17 Give user a chance to override without editing this file
18 (and without using -D arguments each time they build).
19 The build properties a user is likely to override include:
20 - lib.dir The directory where to look for the default JAR
21 files. Defaults to ./lib
22 - xml-apis.jar The JAR containing the DOM, SAX and JAXP classes.
23 Defaults to ${lib.dir}/xml-apis.jar
24 - parser.jar The JAR containing the XML parser to use.
25 Defaults to ${lib.dir}/xerces.jar
26 - jaxen.lib.dir The directory containing the Jaxen JAR libraries.
27 Defaults to ${lib.dir}
28 -->
29 <property file="${user.home}/jdom.build.properties" />
30 <property file="${basedir}/build.properties" />
31
32 <property name="Name" value="JDOM"/>
33 <property name="name" value="jdom"/>
34 <property name="version" value="2.x-${snapshot.time}"/>
35 <property name="version.impl" value="${version}"/>
36 <property name="version.spec" value="2.0.0"/>
37
38 <property name="gpg" value="gpg"
39 description="Path to the GNU gpg program for maven target"/>
40
41 <property name="jarbase" value="${name}-${version}" />
42
43 <property name="instrument" value="true" />
44
45 <echo message="----------- ${Name} ${version} ------------"/>
46
47 <property name="compile.debug" value="true" />
48 <property name="compile.optimize" value="true" />
49 <property name="compile.target" value="1.5" />
50 <property name="compile.source" value="1.5" />
51 <property name="compile.deprecation" value="true" />
52
53 <property name="build" value="./build"/>
54
55 <property name="core" value="./core" />
56 <property name="core.src" value="${core}/src/java" />
57 <property name="core.build" value="${build}/core" />
58
59 <property name="about" value="./core/package" />
60 <property name="about.src" value="${about}" />
61 <property name="about.build" value="${build}/about" />
62
63 <property name="metainf" value="./core/package/META-INF" />
64 <property name="metainf.build" value="${build}/META-INF" />
65
66 <property name="contrib" value="./contrib" />
67 <property name="contrib.src" value="${contrib}/src/java" />
68 <property name="contrib.build" value="${build}/contrib" />
69
70 <property name="junit" value="./test" />
71 <property name="junit.src" value="${junit}/src/java" />
72 <property name="junit.resources" value="${junit}/src/resources" />
73 <property name="junit.build" value="${build}/junit" />
74 <property name="junit.xml" value="${build}/junit.xml" />
75 <property name="junit.report" value="${build}/junit.report" />
76 <property name="junit.instrumented" value="${build}/instrumented" />
77
78
79 <property name="samples" value="./core/samples/" />
80 <property name="samples.src" value="${samples}/" />
81 <property name="samples.build" value="${build}/samples"/>
82
83 <!-- Do not set a stax.dir
84 but it is available for override (for Java5 for example) -->
85 <property name="stax.dir" value="dummy" />
86
87 <property name="lib.dir" value="./lib"/>
88 <property name="packages" value="org.jdom.*"/>
89
90 <property name="build.javadocs" value="${build}/apidocs"/>
91
92 <property name="package" value="${build}/package"/>
93
94 <property name="coverage.out" value="${build}/coverage" />
95
96 <property name="mavendir" value="${build}/maven" />
97
98 <filter token="year" value="${year}"/>
99 <filter token="version" value="${version}"/>
100 <filter token="date" value="${TODAY}"/>
101 <filter token="jdk" value="${compile.target}" />
102
103 <!-- Default JAR libraries -->
104 <property name="parser.jar" value="${lib.dir}/xercesImpl.jar" />
105 <property name="xmlapi.jar" value="${lib.dir}/xml-apis.jar" />
106 <property name="jaxen.jar" value="${lib.dir}/jaxen-1.1.6.jar" />
107 <property name="junit.jar" value="${lib.dir}/junit-4.8.2.jar" />
108 <property name="isorelax.jar" value="${contrib}/lib/isorelax.jar" />
109 <property name="xalan.jar" value="${lib.dir}/xalan/xalan-2.7.2.jar" />
110 <property name="xalanser.jar" value="${lib.dir}/xalan/serializer-2.7.2.jar" />
111
112 <!-- Compilation class path -->
113 <path id="base.class.path">
114 <pathelement location="${jaxen.jar}" />
115 <pathelement location="${parser.jar}" />
116 <pathelement location="${xmlapi.jar}" />
117 <pathelement location="${junit.jar}" />
118 <pathelement location="${isorelax.jar}" />
119 <pathelement location="${xalan.jar}" />
120 <pathelement location="${xalanser.jar}" />
121 <!-- normally these stax jars will not be found -->
122 <!-- this is used for testing Java5 (the test sets stax.dir) -->
123 <pathelement location="${stax.dir}/jsr173_1.0_api.jar" />
124 <pathelement location="${stax.dir}/sjsxp.jar" />
125 </path>
126
127 <path id="core.class.path">
128 <path refid="base.class.path"/>
129 <pathelement location="${core.build}"/>
130 </path>
131
132 <path id="contrib.class.path">
133 <path refid="core.class.path"/>
134 <pathelement location="${contrib.build}"/>
135 </path>
136
137 <path id="junit.class.path">
138 <pathelement location="${junit.instrumented}" />
139 <pathelement location="${junit.build}"/>
140 <path refid="contrib.class.path"/>
141 <fileset dir="${lib.dir}/cobertura" includes="*.jar" />
142 </path>
143
144
145 <!-- =================================================================== -->
146 <!-- Help on usage -->
147 <!-- =================================================================== -->
148 <target name="usage">
149 <echo message=""/>
150 <echo message=""/>
151 <echo message="JDOM Build file"/>
152 <echo message="-------------------------------------------------------------"/>
153 <echo message=""/>
154 <echo message=" available targets are:"/>
155 <echo message=""/>
156 <echo message=" - package [default] -> generates ./build/jdom2.jar and other supporting files"/>
157 <echo message=" - compile -> compiles the source code"/>
158 <echo message=" - javadoc -> generates the API documentation in ./build/javadocs"/>
159 <echo message=" - junit -> runs the JUnit tests"/>
160 <echo message=" - coverage -> generates test coverage metrics"/>
161 <echo message=" - eclipse -> generates an Eclipse project (source folders, jars, etc)"/>
162 <echo message=" - clean -> restores the distribution to its original and clean state"/>
163 <echo message=" - maven -> Prepares a package-upload for maven-central"/>
164 <echo message=""/>
165 <echo message=" See the comments inside the build.xml file for more details."/>
166 <echo message="-------------------------------------------------------------"/>
167 <echo message=""/>
168 <echo message=""/>
169 </target>
170
171 <!-- =================================================================== -->
172 <!-- Prepares the build directory -->
173 <!-- =================================================================== -->
174 <target name="prepare">
175 <mkdir dir="${build}"/>
176 <mkdir dir="${core.build}"/>
177 <mkdir dir="${about.build}"/>
178 <mkdir dir="${samples.build}"/>
179 <mkdir dir="${junit.build}"/>
180 <mkdir dir="${contrib.build}"/>
181 <mkdir dir="${metainf.build}"/>
182 </target>
183
184 <!-- =================================================================== -->
185 <!-- Compiles the source directory -->
186 <!-- =================================================================== -->
187 <target name="compile.core" depends="prepare"
188 description="Compiles the core source code">
189
190 <!-- Copy resources and stuff - everything except Java code -->
191 <copy todir="${core.build}" >
192 <fileset dir="${core.src}" excludes="**/*.java" />
193 </copy>
194
195 <javac srcdir="${core.src}"
196 destdir="${core.build}"
197 debug="${compile.debug}"
198 optimize="${compile.optimize}"
199 target="${compile.target}"
200 source="${compile.source}"
201 deprecation="${compile.deprecation}"
202 includeantruntime="false">
203 <classpath refid="base.class.path"/>
204 </javac>
205 </target>
206
207 <target name="compile.samples" depends="compile.core, compile.contrib"
208 description="Compiles the sample source code">
209
210 <!-- Copy resources and stuff - everything except Java code -->
211 <copy todir="${samples.build}" >
212 <fileset dir="${samples.src}" excludes="**/*.java" />
213 </copy>
214
215 <javac srcdir="${samples.src}"
216 destdir="${samples.build}"
217 debug="${compile.debug}"
218 optimize="${compile.optimize}"
219 target="${compile.target}"
220 source="${compile.source}"
221 deprecation="${compile.deprecation}"
222 includeantruntime="false">
223 <classpath refid="contrib.class.path" />
224 </javac>
225 </target>
226
227 <target name="compile.contrib" depends="compile.core"
228 description="Compiles the contrib source code">
229
230 <!-- Copy resources and stuff - everything except Java code -->
231 <copy todir="${contrib.build}" >
232 <fileset dir="${contrib.src}" excludes="**/*.java" />
233 </copy>
234
235 <javac srcdir="${contrib.src}"
236 destdir="${contrib.build}"
237 debug="${compile.debug}"
238 optimize="${compile.optimize}"
239 target="${compile.target}"
240 source="${compile.source}"
241 deprecation="${compile.deprecation}"
242 includeantruntime="false">
243 <classpath refid="core.class.path" />
244 </javac>
245 </target>
246
247 <target name="compile.junit" depends="compile.core, compile.contrib"
248 description="Compiles the junit source code">
249
250 <!-- Copy resources and stuff - everything except Java code -->
251 <copy todir="${junit.build}" >
252 <fileset dir="${junit.src}" excludes="**/*.java" />
253 <fileset dir="${junit.resources}" />
254 </copy>
255
256 <!-- ignore deprecation warnings in jUnit -->
257 <javac srcdir="${junit.src}"
258 destdir="${junit.build}"
259 debug="${compile.debug}"
260 optimize="${compile.optimize}"
261 target="${compile.target}"
262 source="${compile.source}"
263 deprecation="no"
264 includeantruntime="false">
265 <classpath refid="contrib.class.path" />
266 </javac>
267 </target>
268
269 <target name="compile" depends="compile.core, compile.junit, compile.contrib, compile.samples"
270 description="Compiles all JDOM code (core, samples, junit, contrib)" />
271
272 <!-- =================================================================== -->
273 <!-- Creates the API documentation -->
274 <!-- =================================================================== -->
275 <target name="javadoc" depends="prepare"
276 description="Creates the API documentation">
277 <mkdir dir="${build.javadocs}"/>
278 <javadoc packagenames="${packages}"
279 sourcepath="${core.src}"
280 destdir="${build.javadocs}"
281 author="true"
282 version="true"
283 use="true"
284 splitindex="true"
285 noindex="false"
286 windowtitle="${Name} v${version}"
287 doctitle="${Name} v${version}&lt;br&gt;API Specification"
288 header="&lt;b&gt;${Name}&lt;br&gt;&lt;font size='-1'&gt;${version}&lt;/font&gt;&lt;/b&gt;"
289 bottom="Copyright &#169; ${year} Jason Hunter, Brett McLaughlin. All Rights Reserved.">
290 <classpath refid="base.class.path"/>
291 </javadoc>
292 </target>
293
294
295 <!-- =================================================================== -->
296 <!-- Creates the jars -->
297 <!-- =================================================================== -->
298 <target name="jars" depends="compile, javadoc"
299 description="Builds the Jars">
300 <fixcrlf srcdir="." includes="**/*.bat" excludes="build*.*" eol="crlf"/>
301 <fixcrlf srcdir="." includes="**/*.sh" excludes="build*.*" eol="lf"/>
302
303 <!-- Filters defined specifically for updating the manifest -->
304 <filter token="version.spec" value="${version.spec}"/>
305 <filter token="version.impl" value="${version.impl}"/>
306
307 <copy todir="${metainf.build}/META-INF" filtering="yes">
308 <fileset dir="${metainf}"/>
309 <fileset dir=".">
310 <include name="LICENSE.txt"/>
311 </fileset>
312 </copy>
313
314 <jar jarfile="${package}/${jarbase}.jar" manifest="${metainf.build}/META-INF/MANIFEST.MF">
315 <fileset dir="${core.build}" includes="**/*.class" />
316 <fileset dir="${metainf.build}" excludes="**/MANIFEST.MF" />
317 </jar>
318 <jar jarfile="${package}/${jarbase}-contrib.jar" >
319 <fileset dir="${contrib.build}" includes="**/*" />
320 <fileset dir="${metainf.build}" excludes="**/MANIFEST.MF" />
321 </jar>
322 <jar jarfile="${package}/${jarbase}-junit.jar" >
323 <fileset dir="${junit.build}" includes="**/*" />
324 <fileset dir="${metainf.build}" excludes="**/MANIFEST.MF" />
325 </jar>
326 <jar destfile="${package}/${jarbase}-javadoc.jar"
327 basedir="${build.javadocs}" includes="**/*" />
328
329 <jar jarfile="${package}/${jarbase}-sources.jar" >
330 <fileset dir="${core.src}" includes="**/*" />
331 </jar>
332 <jar jarfile="${package}/${jarbase}-junit-sources.jar" >
333 <fileset dir="${junit.src}" includes="**/*" />
334 </jar>
335 <jar jarfile="${package}/${jarbase}-contrib-sources.jar" >
336 <fileset dir="${contrib.src}" includes="**/*" />
337 </jar>
338
339 </target>
340
341 <target name="androidtests" depends="jars">
342
343 <property name="android.project" value="JUT" />
344 <property name="android" value="${build}/android" />
345 <property name="android.libs" value="${android}/${android.project}/libs" />
346 <mkdir dir="${android}" />
347 <mkdir dir="${android.libs}" />
348
349 <path id="at.class.path">
350 <pathelement location="${package}/${jarbase}.jar" />
351 <pathelement location="${package}/${jarbase}-contrib.jar" />
352 <pathelement location="${package}/${jarbase}-junit.jar" />
353 <path refid="base.class.path"/>
354 </path>
355
356 <!-- Convert the test cases from JUnit4 to a JUnit3 format -->
357 <!-- This also copies the resources only. -->
358 <java classname="org.jdom.contrib.android.TranslateTests"
359 classpathref="at.class.path" >
360 <arg value="${package}/${jarbase}-junit.jar" />
361 <arg value="${android}/${android.project}Test/src" />
362 </java>
363
364 <copy todir="${android.libs}">
365 <fileset dir="${package}"
366 includes="${jarbase}.jar, ${jarbase}-contrib.jar ${jarbase}-junit.jar" />
367 </copy>
368
369 <copy todir="${android.libs}" file="${jaxen.jar}"/>
370 <copy todir="${android.libs}" file="${xalan.jar}"/>
371 <copy todir="${android.libs}" file="${xalanser.jar}"/>
372 <copy todir="${android.libs}" file="${junit.jar}"/>
373 </target>
374
375 <!-- =================================================================== -->
376 <!-- Creates the class package -->
377 <!-- =================================================================== -->
378 <target name="package" depends="coverage, jars"
379 description="Creates the class package">
380 <zip destfile="${package}/${jarbase}.zip">
381 <fileset dir="${package}" includes="${jarbase}*.jar" />
382 <fileset dir="${basedir}" includes="lib/xerces* lib/jaxen* lib/xml* lib/xalan/**" />
383 <fileset dir="${basedir}" includes="LICENSE.txt README.txt" />
384 </zip>
385 </target>
386
387 <!-- =================================================================== -->
388 <!-- Clean targets -->
389 <!-- =================================================================== -->
390 <target name="clean" description="Removes build files">
391 <delete dir="${build}" failonerror="false"/>
392 </target>
393
394 <!-- =================================================================== -->
395 <!-- JUnit and Test Coverage targets -->
396 <!-- =================================================================== -->
397 <target name="coverage.setup" description="Set up code-coverage metrics" depends="compile.core">
398 <taskdef classpathref="junit.class.path" resource="tasks.properties"/>
399
400 <delete dir="${junit.instrumented}"/>
401 <mkdir dir="${junit.instrumented}" />
402 <property name="cobertura.datafile" value="${junit.instrumented}/cobertura.ser"/>
403 <cobertura-instrument todir="${junit.instrumented}" datafile="${cobertura.datafile}">
404 <fileset dir="${core.build}">
405 <include name="**/*.class"/>
406 <!-- exclude name="**/**/jaxen/**/*.class"/ -->
407 </fileset>
408 </cobertura-instrument>
409
410 <property name="forkjunit" value="true" />
411
412 </target>
413
414
415 <target name="junit.nodeps"
416 description="Run all the JUnit tests, but do not compile anything first">
417
418 <delete dir="${junit.report}" />
419 <mkdir dir="${junit.report}" />
420
421 <delete dir="${junit.xml}" />
422 <mkdir dir="${junit.xml}" />
423
424 <!-- We need to fork to get the resources on the classpath -->
425 <!-- Otherwise we rely on ant's ClassLoader which does not do resources nicely -->
426 <junit fork="true" forkmode="once" haltonerror="false" haltonfailure="false"
427 failureproperty="junit.failed" printsummary="true" timeout="100000"
428 showoutput="true" includeantruntime="true" >
429
430 <sysproperty key="net.sourceforge.cobertura.datafile"
431 file="${cobertura.datafile}" />
432 <classpath refid="junit.class.path" />
433
434 <formatter type="xml"/>
435
436 <batchtest haltonerror="false" haltonfailure="false"
437 failureproperty="junit.failed" todir="${junit.xml}" >
438 <sort>
439 <name />
440 <fileset dir="${junit.src}">
441 <include name="**/Test*.java"/>
442 <exclude name="**/generate/**" />
443 </fileset>
444 </sort>
445 </batchtest>
446
447 </junit>
448
449 <junitreport todir="${junit.report}">
450 <fileset dir="${junit.xml}">
451 <include name="TEST-*.xml"/>
452 </fileset>
453
454 <report format="frames" todir="${junit.report}"/>
455 </junitreport>
456 </target>
457
458 <target name="junit" depends="compile.core, compile.junit, junit.nodeps"
459 description="Compile code required for JUnit, then run JUnit tests"/>
460
461 <target name="coverage" depends="coverage.setup, junit"
462 description="Run the code coverage tool.">
463 <delete dir="${coverage.out}"/>
464 <mkdir dir="${coverage.out}" />
465 <cobertura-report srcdir="${core.src}" destdir="${coverage.out}" datafile="${cobertura.datafile}"/>
466 <echo message="See ${coverage.out}/index.html for results." />
467 </target>
468
469 <!-- =================================================================== -->
470 <!-- Eclipse targets -->
471 <!-- =================================================================== -->
472 <target name="eclipse" description="Set up your eclipse project (source folders, jars, etc.)">
473 <echo file="./.classpath" xml:space="preserve"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
474 <classpath>
475 <classpathentry kind="src" path="core/src/java"/>
476 <classpathentry kind="src" path="core/package"/>
477 <classpathentry kind="src" path="core/samples"/>
478 <classpathentry kind="src" path="test/src/java"/>
479 <classpathentry kind="src" path="test/src/resources"/>
480 <classpathentry kind="src" path="contrib/src/java" excluding="org/jdom/contrib/ids/doc-files/|org/jdom/contrib/input/scanner/doc-files/|org/jdom2/contrib/ids/doc-files/|org/jdom2/contrib/ids/doc-files/|org/jdom2/contrib/input/scanner/doc-files/|org/jdom2/contrib/input/scanner/doc-files/"/>
481 <classpathentry kind="src" path="contrib/samples"/>
482 <classpathentry kind="src" path="contrib/src/java/org/jdom2/contrib/ids/doc-files"/>
483 <classpathentry kind="src" path="contrib/src/java/org/jdom2/contrib/input/scanner/doc-files"/>
484 <classpathentry kind="lib" path="${junit.jar}"/>
485 <classpathentry kind="lib" path="${parser.jar}"/>
486 <classpathentry kind="lib" path="${xmlapi.jar}"/>
487 <classpathentry kind="lib" path="${jaxen.jar}"/>
488 <classpathentry kind="lib" path="${isorelax.jar}"/>
489 <classpathentry kind="lib" path="${xalanser.jar}"/>
490 <classpathentry kind="lib" path="${xalan.jar}"/>
491 <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
492 <classpathentry kind="output" path="ebuild"/>
493 </classpath>
494 ]]>
495 </echo>
496 </target>
497
498 <!-- =================================================================== -->
499 <!-- Maven targets -->
500 <!-- =================================================================== -->
501
502
503 <target name="maven.clean">
504 <delete dir="${mavendir}" includes="**/*" failonerror="false"/>
505 </target>
506
507 <target name="maven" depends="maven.clean, package"
508 description="Prepares Maven bundle to load on to Sonatype Nexus for Maven-Central">
509 <mkdir dir="${mavendir}" />
510 <mkdir dir="${mavendir}/core" />
511 <mkdir dir="${mavendir}/test" />
512 <mkdir dir="${mavendir}/contrib" />
513
514 <property name="mavenartifact" value="jdom2" />
515 <property name="mavenbase" value="${mavenartifact}-${version}" />
516
517 <!-- copy the build jar -->
518 <copy tofile="${mavendir}/core/${mavenbase}.jar" file="${package}/${jarbase}.jar"/>
519 <copy tofile="${mavendir}/core/${mavenbase}-javadoc.jar" file="${package}/${jarbase}-javadoc.jar"/>
520 <copy tofile="${mavendir}/core/${mavenbase}-sources.jar" file="${package}/${jarbase}-sources.jar"/>
521
522 <!-- load the license in to the ${license} property -->
523 <loadfile property="license" srcfile="LICENSE.txt" />
524
525 <!-- copy/rename the pom template -->
526 <copy filtering="true" file="maven/maven.pom" tofile="${mavendir}/core/${mavenbase}.pom">
527 <filterset>
528 <filter token="artifactID" value="${mavenartifact}"/>
529 <filter token="version" value="${version}" />
530 <filter token="jdk" value="${compile.target}" />
531 <filter token="license" value="${license}" />
532 </filterset>
533 </copy>
534
535 <exec dir="${mavendir}/core" executable="${gpg}">
536 <arg value="-abv"/>
537 <arg value="${mavenbase}.pom"/>
538 </exec>
539 <exec dir="${mavendir}/core" executable="${gpg}">
540 <arg value="-abv"/>
541 <arg value="${mavenbase}.jar"/>
542 </exec>
543 <exec dir="${mavendir}/core" executable="${gpg}">
544 <arg value="-abv"/>
545 <arg value="${mavenbase}-sources.jar"/>
546 </exec>
547 <exec dir="${mavendir}/core" executable="${gpg}">
548 <arg value="-abv"/>
549 <arg value="${mavenbase}-javadoc.jar"/>
550 </exec>
551
552 <jar destfile="${mavendir}/${mavenbase}-maven-bundle.jar"
553 basedir="${mavendir}/core"
554 includes="${mavenbase}*" excludes="*maven-bundle*" />
555
556 </target>
557
558 </project>
559
560 <!-- End of file -->
0 /build
1 /out
0 Introduction
1 ============
2
3 jdom-contrib is a place for projects that increase the value of JDOM but
4 aren't (at least yet) in the core distribution. Contributed code is
5 placed under the org.jdom.contrib package hierarchy.
6
7 Currently we have org.jdom.contrib packages for beans, helpers, ids, input,
8 output, and schema. "beans" holds JDOMBean and can hold related bean
9 work. "helpers" holds certain helper functions. "ids" demonstrates how to
10 use the attribute type support provided by JDOM to create JDOM documents that
11 allow looking up elements using the value of their ID attribute. "input" and
12 "output" hold builders and outputters. "schema" has code for in-memory
13 schema validation.
14
15 Some code from contrib (or the equivalent functionality) has been migrated in
16 to the core code, The code has been left in contrib and been marked as
17 'deprecated', as example code of what can be done.
18
19 If you have an interesting contribution, or just ideas that someone else might
20 pick up on, post to jdom-interest.
0 dependencies {
1 compile project(':core')
2 compile 'junit:junit:4.12'
3 compile 'isorelax:isorelax:20030108'
4 compile 'xerces:xercesImpl:2.11.0'
5 compile 'xalan:xalan:2.7.2'
6 }
7
8 sourceSets {
9 main {
10 java {
11 srcDir 'src/java'
12 }
13 }
14 }
15
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modifica-
5 tion, are permitted provided that the following conditions are met:
6
7 1. Redistributions of source code must retain the above copyright notice,
8 this list of conditions, and the following disclaimer.
9
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions, the disclaimer that follows these conditions,
12 and/or other materials provided with the distribution.
13
14 3. The names "JDOM" and "Java Document Object Model" must not be used to
15 endorse or promote products derived from this software without prior
16 written permission. For written permission, please contact
17 license@jdom.org.
18
19 4. Products derived from this software may not be called "JDOM", nor may
20 "JDOM" appear in their name, without prior written permission from the
21 JDOM Project Management (pm@jdom.org).
22
23 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
24 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
25 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 JDOM PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34 This software consists of voluntary contributions made by many individuals
35 on behalf of the Java Document Object Model Project and was originally
36 created by Brett McLaughlin <brett@jdom.org> and
37 Jason Hunter <jhunter@jdom.org>. For more information on the JDOM
38 Project, please see <http://www.jdom.org/>.
39
40 */
41
42 import java.awt.*;
43 import java.awt.event.*;
44 import java.net.URL;
45 import javax.swing.*;
46 import javax.swing.tree.*;
47
48 import org.jdom.Document;
49 import org.jdom.input.SAXBuilder;
50 import org.jdom.contrib.output.JTreeOutputter;
51
52 /**
53 * <p><code>JTreeOutputterDemo</code> demonstrates how to
54 * build a JTree (in Swing) from a JDOM <code>{@link Document}</code>.
55 * </p>
56 *
57 * @author Jon Baer
58 * @author Brett McLaughlin
59 * @version 1.0
60 */
61 @SuppressWarnings("javadoc")
62 public class JTreeOutputterDemo implements ActionListener {
63
64 public JFrame frame;
65 public Document doc;
66 public DefaultMutableTreeNode root;
67 public JTreeOutputter outputter;
68 public JTree tree;
69 public JScrollPane scrollPane;
70 public SAXBuilder saxBuilder;
71 public JMenuItem openFile, openURL, openSQL, exitMenu;
72 public JButton openButton, reloadButton, exitButton, aboutButton;
73
74 public static void main(String[] args) {
75 new JTreeOutputterDemo();
76 }
77
78 public JTreeOutputterDemo() {
79
80 frame = new JFrame(" JDOM Viewer 1.0");
81 JMenuBar menuBar = new JMenuBar();
82 JMenu menu = new JMenu("File");
83 openFile = new JMenuItem("Open XML File");
84 openFile.addActionListener(this);
85 openURL = new JMenuItem("Open URL Stream");
86 openURL.addActionListener(this);
87 openSQL = new JMenuItem("Query Database");
88 openSQL.addActionListener(this);
89 exitMenu = new JMenuItem("Exit");
90 exitMenu.addActionListener(this);
91 menu.add(openFile);
92 menu.add(openURL);
93 menu.add(new JSeparator());
94 menu.add(openSQL);
95 menu.add(new JSeparator());
96 menu.add(exitMenu);
97 menuBar.add(menu);
98 frame.setJMenuBar(menuBar);
99
100 openButton = new JButton("Open");
101 openButton.addActionListener(this);
102 reloadButton = new JButton("Reload");
103 reloadButton.addActionListener(this);
104 exitButton = new JButton("Exit");
105 exitButton.addActionListener(this);
106 aboutButton = new JButton("About");
107 aboutButton.addActionListener(this);
108 JPanel buttonPanel = new JPanel();
109 buttonPanel.add(openButton);
110 buttonPanel.add(reloadButton);
111 buttonPanel.add(exitButton);
112 buttonPanel.add(aboutButton);
113
114 root = new DefaultMutableTreeNode("JDOM");
115
116 outputter = new JTreeOutputter(true);
117
118 tree = new JTree(root);
119
120 saxBuilder = new SAXBuilder();
121
122 scrollPane = new JScrollPane();
123 scrollPane.getViewport().add(tree);
124
125 frame.setSize(400,400);
126 frame.getContentPane().setLayout(new BorderLayout());
127 frame.getContentPane().add("Center", scrollPane);
128 frame.getContentPane().add("South", buttonPanel);
129
130 frame.addWindowListener(new WindowAdapter() {
131 @Override
132 public void windowClosing(WindowEvent evt) {
133 System.exit(0);
134 }
135 });
136
137 frame.setVisible(true);
138
139 }
140
141 @Override
142 public void actionPerformed(ActionEvent e) {
143 // Open File
144 if (e.getSource() == openButton || e.getSource() == openFile) {
145 doFile();
146 }
147 // Open URL
148 if (e.getSource() == openURL) {
149 doURL();
150 }
151 // Query Database
152 if (e.getSource() == openSQL) {
153 doSQL();
154 }
155 // Exit
156 if (e.getSource() == exitButton || e.getSource() == exitMenu) {
157 System.exit(0);
158 }
159 }
160
161 public void doFile() {
162 JFileChooser fc = new JFileChooser();
163 fc.setDialogTitle("Select an XML File");
164 int returnVal = fc.showDialog(frame, "Load XML");
165 if (returnVal == 0) {
166 try {
167 doc = saxBuilder.build(fc.getSelectedFile());
168 } catch (Exception e) {e.printStackTrace();}
169 outputter.output(doc, root);
170 }
171 }
172
173 public void doURL() {
174 URLDialog urlDialog = new URLDialog(frame);
175 if (urlDialog.getURL() != null) {
176 try {
177 doc = saxBuilder.build(new URL(urlDialog.getURL()));
178 } catch (Exception e) {
179 e.printStackTrace();
180 }
181 outputter.output(doc, root);
182 }
183 }
184
185 public void doSQL() {
186 // do nothing
187 }
188
189 }
190
191 class URLDialog extends JDialog implements ActionListener {
192
193 /**
194 * Default.
195 */
196 private static final long serialVersionUID = 1L;
197
198 public String url;
199 public JTextField urlField;
200 public JButton okButton, cancelButton;
201
202 public URLDialog(Frame frame) {
203 super(frame, "Enter A URL", true);
204 urlField = new JTextField("http://");
205 JPanel buttonPanel = new JPanel();
206 okButton = new JButton("OK");
207 okButton.addActionListener(this);
208 cancelButton = new JButton("Cancel");
209 cancelButton.addActionListener(this);
210 buttonPanel.add(okButton);
211 buttonPanel.add(cancelButton);
212 getContentPane().setLayout(new BorderLayout());
213 getContentPane().add("North", urlField);
214 getContentPane().add("South", buttonPanel);
215 setSize(400, 150);
216 setVisible(true);
217 }
218
219 public String getURL() {
220 return this.url;
221 }
222
223 @Override
224 public void actionPerformed(ActionEvent e) {
225 if (e.getSource() == okButton) {
226 this.url = urlField.getText(); setVisible(false);
227 }
228 if (e.getSource() == cancelButton) {
229 setVisible(false);
230 }
231 }
232
233 }
0 /*--
1
2 Copyright 2004 Jason Hunter. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modifica-
5 tion, are permitted provided that the following conditions are met:
6
7 1. Redistributions of source code must retain the above copyright notice,
8 this list of conditions, and the following disclaimer.
9
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions, the disclaimer that follows these conditions,
12 and/or other materials provided with the distribution.
13
14 3. The names "JDOM" and "Java Document Object Model" must not be used to
15 endorse or promote products derived from this software without prior
16 written permission. For written permission, please contact
17 license@jdom.org.
18
19 4. Products derived from this software may not be called "JDOM", nor may
20 "JDOM" appear in their name, without prior written permission from the
21 JDOM Project Management (pm@jdom.org).
22
23 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
24 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
25 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 JDOM PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34 This software consists of voluntary contributions made by many individuals
35 on behalf of the Java Document Object Model Project and was originally
36 created by Brett McLaughlin <brett@jdom.org> and
37 Jason Hunter <jhunter@jdom.org>. For more information on the JDOM
38 Project, please see <http://www.jdom.org/>.
39
40 */
41
42 import java.io.StringReader;
43 import java.util.Iterator;
44
45 import org.jdom.Document;
46 import org.jdom.input.SAXBuilder;
47 import org.jdom.filter2.*;
48
49 import org.jdom.contrib.input.*;
50
51 /**
52 * @author Per Norrman
53 *
54 */
55 @SuppressWarnings("javadoc")
56 public class LineNumberSAXBuilderDemo
57 {
58
59 public static void main(String[] args) throws Exception {
60 SAXBuilder builder = new SAXBuilder();
61 builder.setSAXHandlerFactory(LineNumberSAXHandler.SAXFACTORY);
62 Document doc = builder.build(new StringReader(xml));
63
64 for (Iterator<LineNumberElement> iter = doc.getDescendants(Filters.fclass(LineNumberElement.class));
65 iter.hasNext(); ) {
66 LineNumberElement e = iter.next();
67 System.out.println(
68 e.getName() + ": lines " + e.getStartLine() + " to " + e.getEndLine());
69 }
70
71 }
72
73 private static String xml =
74 "<a>\n<b/>\n<c/>\n<d>\n<e/>\n<f/>\n</d>\n</a>\n";
75
76 }
0 /*--
1
2 Copyright 2000 Brett McLaughlin & Jason Hunter. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without modifica-
5 tion, are permitted provided that the following conditions are met:
6
7 1. Redistributions of source code must retain the above copyright notice,
8 this list of conditions, and the following disclaimer.
9
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions, the disclaimer that follows these conditions,
12 and/or other materials provided with the distribution.
13
14 3. The names "JDOM" and "Java Document Object Model" must not be used to
15 endorse or promote products derived from this software without prior
16 written permission. For written permission, please contact
17 license@jdom.org.
18
19 4. Products derived from this software may not be called "JDOM", nor may
20 "JDOM" appear in their name, without prior written permission from the
21 JDOM Project Management (pm@jdom.org).
22
23 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
24 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
25 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 JDOM PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34 This software consists of voluntary contributions made by many individuals
35 on behalf of the Java Document Object Model Project and was originally
36 created by Brett McLaughlin <brett@jdom.org> and
37 Jason Hunter <jhunter@jdom.org>. For more information on the JDOM
38 Project, please see <http://www.jdom.org/>.
39
40 */
41
42 import java.sql.*;
43
44 import org.jdom.*;
45 import org.jdom.output.*;
46
47 import org.jdom.contrib.input.ResultSetBuilder;
48
49 @SuppressWarnings("javadoc")
50 public class ResultSetBuilderDemo {
51
52 // SQL tables copied from the Servlets.com ISP listing application
53
54 static final String PREP =
55 "create table rsbd ( " +
56 "id int PRIMARY KEY, " +
57 "name varchar(255) NOT NULL, " +
58 "home_url varchar(255) NULL, " +
59 "contact_email varchar(255) NULL, " +
60 "contact_phone varchar(255) NULL, " +
61 "location varchar(255) NULL, " +
62 "comments long varchar NULL, " +
63 "free_hosting boolean NULL, " +
64 "state_flag tinyint NOT NULL, " + // submitted, rejected, live, dead
65 "submitter_email varchar(255) NULL, " + // not displayed
66 "created_time timestamp NOT NULL, " +
67 "modified_time timestamp NOT NULL " +
68 ")";
69
70 static final String FILL =
71 "insert into rsbd (id, name, home_url, contact_email, " +
72 "contact_phone, comments, free_hosting, state_flag, created_time, " +
73 "modified_time) values (2, 'sphere', null, 'info@sphere', " +
74 "'1234', 'cool', true, 10, " +
75 "{ts '1999-02-09 20:11:11.123455'}, " +
76 "{ts '1999-03-21 22:11:11.123455'})";
77
78 public static void main(String[] args) throws Exception {
79 // Tested against Cloudscape database that comes with the J2EE ref impl
80 Class.forName("COM.cloudscape.core.JDBCDriver");
81 Connection con =
82 DriverManager.getConnection("jdbc:cloudscape:rsbd;create=true");
83
84 // Create and fill commands, needed only on the first run
85 Statement prep = con.createStatement();
86 prep.executeUpdate(PREP);
87
88 Statement fill = con.createStatement();
89 fill.executeUpdate(FILL);
90
91 Statement stmt = con.createStatement();
92 ResultSet rs = stmt.executeQuery(
93 "select id, name, home_url || contact_phone from rsbd");
94 ResultSetBuilder builder = new ResultSetBuilder(rs);
95 builder.setAsElement(3, "num3");
96 //builder.setNamespace(ns);
97 //builder.setAsElement("id", "newid");
98 //builder.setAsElement("home_url", "newhome_url");
99 //builder.setAsElement(4, "some4");
100 //builder.setAsAttribute(4, "some4");
101 //builder.setAsAttribute("state_flag");
102 builder.setAsAttribute("created_time", "ctime");
103 Document doc = builder.build();
104 XMLOutputter outputter = new XMLOutputter();
105 outputter.output(doc, System.out);
106 }
107 }
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 import java.sql.*;
55 import java.io.*;
56 import java.util.*;
57
58 import org.jdom.*;
59 import org.jdom.output.*;
60 import org.jdom.contrib.input.ResultSetBuilder;
61
62 /**
63 * A simple sample harness for JDOM ResultSetBuilder
64 *
65 * @author R.Sena (raff@aromatic.org)
66 */
67 @SuppressWarnings("javadoc")
68 public class sxql {
69
70 /**
71 * Return a connection (i.e. from a connection pool)
72 */
73 public static Connection getConnection(String driver, String jdbcURL,
74 String user, String pass)
75 throws Exception {
76 Class.forName(driver);
77 return DriverManager.getConnection(jdbcURL, user, pass);
78 }
79
80 /**
81 * Execute a SQL query and return the result as XML
82 * (as a String. But this can be changed to return a DOM/SAX/JDOM tree,
83 * to be used, for example, as input to an XSLT processor)
84 */
85 public static String query(Connection con, String query,
86 String root, String row,
87 String ns, int maxRows,
88 Vector<String> attributes, Vector<String> elements)
89 throws Exception {
90 // Execute SQL Query
91 Statement stmt = con.createStatement();
92 ResultSet rs = stmt.executeQuery(query);
93
94 // Create a ResultSetBuilder
95 ResultSetBuilder builder = new ResultSetBuilder(rs);
96
97 // Configure some parameters...
98
99 if (root != null) {
100 builder.setRootName(root);
101 }
102
103 if (row != null) {
104 builder.setRowName(row);
105 }
106
107 if (ns != null) {
108 String namespace = null;
109 String url = null;
110 int sep = ns.indexOf("/");
111
112 if (sep > 0) {
113 namespace = ns.substring(0, sep);
114 url = ns.substring(sep+1);
115 builder.setNamespace(Namespace.getNamespace(namespace, url));
116 }
117 }
118
119 if (maxRows > 0) {
120 builder.setMaxRows(maxRows);
121 }
122
123 for (int i=0; i < attributes.size(); i++) {
124 String colName = attributes.get(i);
125 String attrName = null;
126
127 if (colName.indexOf("/") >= 0) {
128 String col = colName;
129 int sep = col.indexOf("/");
130 colName = col.substring(0, sep);
131 attrName = col.substring(sep+1);
132 }
133
134 try { // If it looks like an integer, is the column number
135 int colNum = Integer.parseInt(colName);
136
137 if (attrName == null) {
138 builder.setAsAttribute(colNum); // attrName = column Name
139 }
140 else {
141 builder.setAsAttribute(colNum, attrName);
142 }
143 }
144 catch (NumberFormatException e) {
145 // Otherwise it's the column name
146 if (attrName == null) {
147 builder.setAsAttribute(colName); // attrName = column Name
148 }
149 else {
150 builder.setAsAttribute(colName, attrName);
151 }
152 }
153 }
154
155 // Rename element
156 for (int i=0; i < elements.size(); i++) {
157 String colName = elements.get(i);
158 String elemName = null;
159
160 if (colName.indexOf("/") >= 0) {
161 String col = colName;
162 int sep = col.indexOf("/");
163 colName = col.substring(0, sep);
164 elemName = col.substring(sep+1);
165 }
166
167 try { // If it looks like an integer, is the column number
168 int colNum = Integer.parseInt(colName);
169
170 if (elemName != null) { // It must have an element name
171 builder.setAsElement(colNum, elemName);
172 }
173 }
174 catch (NumberFormatException e) {
175 // Otherwise it's the column name
176 if (elemName != null) { // It must have an element name
177 builder.setAsElement(colName, elemName);
178 }
179 }
180 }
181
182 // Build a JDOM tree
183 Document doc = builder.build();
184
185 // Convert the result to XML (as String)
186 XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
187 ByteArrayOutputStream output = new ByteArrayOutputStream();
188 outputter.output(doc, output);
189 return output.toString();
190 }
191
192 /**
193 * Usage
194 */
195 public static void usage() {
196 System.err.println(
197 "usage: sxql [--root=root-element] [--row=row-element]");
198 System.err.println(
199 " [--namespace=namespace/url] [--maxrows=max-rows]");
200 System.err.println(
201 " [--attribute=column/attr] [--element=column/element]");
202 System.err.println(
203 " driver url user pass query");
204 System.err.println(
205 "where:");
206 System.err.println(
207 " --root: set root element name (root-element)");
208 System.err.println(
209 " --row: set row element name (root-element)");
210 System.err.println(
211 " --namespace: set namespace (namespace, url)");
212 System.err.println(
213 " --maxrows: set maximum number of rows (max-rows)");
214 System.err.println(
215 " --attribute: column as attribute (column name/number, attribute-name)");
216 System.err.println(
217 " --element: rename column (column name/number, element-name)");
218 System.err.println(
219 " driver: driver class name");
220 System.err.println(
221 " url: JDBC url");
222 System.err.println(
223 " user: database user");
224 System.err.println(
225 " pass: database password");
226 System.err.println(
227 " query: SQL query");
228 }
229
230 /**
231 * Main entry point
232 */
233 public static void main(String [] args) throws Exception {
234 String root = null;
235 String row = null;
236 String ns = null;
237 int maxRows = 0;
238 Vector<String> attributes = new Vector<String>();
239 Vector<String> elements = new Vector<String>();
240
241 int i;
242
243 // Read configuration parameters
244
245 for (i=0; i < args.length; i++) {
246 if (args[i].startsWith("--")) {
247 if (args[i].startsWith("--attribute="))
248 attributes.add(args[i].substring(12));
249 else
250 if (args[i].startsWith("--element="))
251 elements.add(args[i].substring(10));
252 else
253 if (args[i].startsWith("--root="))
254 root = args[i].substring(7);
255 else
256 if (args[i].startsWith("--row="))
257 row = args[i].substring(6);
258 else
259 if (args[i].startsWith("--namespace="))
260 ns = args[i].substring(12);
261 else
262 if (args[i].startsWith("--maxrows="))
263 maxRows = Integer.parseInt(args[i].substring(10));
264 }
265 else {
266 break;
267 }
268 }
269
270 if (args.length - i != 5) {
271 usage();
272 }
273 else {
274 System.out.println(
275 query(getConnection(args[i+0], args[i+1], args[i+2], args[i+3]),
276 args[i+4], root, row, ns, maxRows, attributes, elements));
277 }
278 }
279 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.android;
55
56 import java.io.File;
57 import java.io.FileWriter;
58 import java.io.IOException;
59 import java.lang.reflect.Method;
60 import java.util.ArrayList;
61 import java.util.Enumeration;
62 import java.util.Iterator;
63 import java.util.Set;
64 import java.util.TreeSet;
65 import java.util.regex.Matcher;
66 import java.util.regex.Pattern;
67 import java.util.zip.ZipEntry;
68 import java.util.zip.ZipFile;
69
70 import org.junit.After;
71 import org.junit.AfterClass;
72 import org.junit.Before;
73 import org.junit.BeforeClass;
74 import org.junit.Ignore;
75 import org.junit.Test;
76
77
78 /**
79 * This class is a translation layer that translates JUnit4 tests to
80 * JUnit3 tests suitable for running with the Android Test harness.
81 * <p/>
82 * This class is a small part of an automated process described in the
83 * wiki page https://github.com/hunterhacker/jdom/wiki/JDOM2-and-Android
84 *
85 * @author Rolf Lear
86 *
87 */
88
89 @SuppressWarnings("javadoc")
90 public class TranslateTests {
91
92 private static final String[] skipclasses = new String[] {".*StAX.*"};
93
94 private static final String[] skipmethods = new String[] {
95 ".*HighSurrogateAttPair.*", "bulkIntern", "testBuildString"};
96
97 private static final Pattern pat = Pattern.compile("^(.+/(\\w+))\\.class$");
98
99 private static String potentialTest(String zename) {
100 final Matcher mat = pat.matcher(zename);
101 if (mat.matches()) {
102 final String cname = mat.group(2);
103 if (cname.startsWith("Test") || cname.endsWith("Test")) {
104 for (String cm : skipclasses) {
105 if (Pattern.matches(cm, cname)) {
106 return null;
107 }
108 }
109 final String cp = mat.group(1);
110 return cp.replace('/', '.');
111 }
112 }
113 return null;
114 }
115
116 /**
117 * Convert the Jar file to a set of new JUnit3 tests.
118 * @param args The two args are expected to be a Jar file (unit tests), and an output directory
119 * @throws IOException
120 */
121 public static void main(String[] args) throws IOException {
122 if (args.length != 2) {
123 throw new IllegalArgumentException("Usage: Jar SrcOutDir");
124 }
125 final String jarname = args[0];
126
127 final File srcoutdir = new File(args[1]);
128 if (!srcoutdir.exists()) {
129 srcoutdir.mkdirs();
130 }
131 if (!srcoutdir.isDirectory()) {
132 throw new IllegalArgumentException("Could not create/use SrcOutput directory: " + srcoutdir);
133 }
134
135 final ArrayList<String> classes = new ArrayList<String>();
136
137 final ZipFile zfile = new ZipFile(jarname);
138 try {
139 final Enumeration<? extends ZipEntry> e = zfile.entries();
140 while (e.hasMoreElements()) {
141 final ZipEntry ze = e.nextElement();
142 if (ze.isDirectory()) {
143 continue;
144 }
145 final String zename = ze.getName();
146 if (zename.endsWith(".class")) {
147 final String classname = potentialTest(zename);
148 if (classname != null) {
149 TranslateTests tt = new TranslateTests(srcoutdir, classname);
150 classes.add(tt.translate());
151 }
152 }
153 }
154 } finally {
155 zfile.close();
156 }
157
158 }
159
160 private final Class<?> tclass;
161 private final File outf;
162
163 public TranslateTests(File outdir, String zename) {
164 System.out.println("Contemplating " + zename);
165 try {
166 tclass = Class.forName(zename);
167 } catch (Exception e) {
168 throw new IllegalStateException("Unable to load class " + zename, e);
169 }
170 final String path = zename.replace('.', '/') + "TT.java";
171 outf = new File(outdir,path);
172 }
173
174 /*
175
176
177 package com.example.android.skeletonapp.test;
178
179 import org.jdom.test.cases.TestElement;
180
181 import android.test.AndroidTestCase;
182
183 @SuppressWarnings("javadoc")
184 public class JDOMMainTest extends AndroidTestCase {
185
186
187 public void testElement() {
188 assertTrue(Integer.valueOf(1) > 0);
189 TestElement te = new TestElement();
190 te.testCoalesceTextNested();
191 }
192 }
193
194
195 */
196
197 private String translate() throws IOException {
198 final String sname = tclass.getSimpleName();
199 final StringBuilder sb = new StringBuilder();
200 final String ret = tclass.getPackage().getName() + "." + sname + "TT";
201
202 sb.append("package ").append(tclass.getPackage().getName()).append(";\n");
203 sb.append("@SuppressWarnings(\"javadoc\")\n");
204 sb.append("public class ").append(sname).append("TT extends android.test.AndroidTestCase {\n");
205
206 if (tclass.getAnnotation(Ignore.class) != null) {
207 sb.append("\n\n // Class has @Ignore set\n\n");
208 } else {
209
210 final Method[] methods = tclass.getMethods();
211
212 final ArrayList<Method> pretest = new ArrayList<Method>();
213 final ArrayList<Method> posttest = new ArrayList<Method>();
214 final TreeSet<String> excepts = new TreeSet<String>();
215
216 for (Method m : methods) {
217 if (m.getAnnotation(Before.class) != null) {
218 pretest.add(m);
219 excepts.addAll(getExceptions(m));
220 }
221 if (m.getAnnotation(After.class) != null) {
222 posttest.add(m);
223 excepts.addAll(getExceptions(m));
224 }
225 }
226
227 sb.append(" private final ").append(sname).append(" test = new ").append(sname).append("();\n");
228
229 sb.append("\n @Override\n");
230 sb.append(" public void setUp() throws Exception {\n");
231 sb.append(" super.setUp();\n");
232 sb.append(" // tests run when class starts...\n");
233 sb.append(" org.jdom.test.util.UnitTestUtil.setAndroid();\n");
234 sb.append(" System.setProperty(\"javax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema\",\n");
235 sb.append(" \"org.apache.xerces.jaxp.validation.XMLSchemaFactory\");\n");
236 for (Method m : methods) {
237 if (m.getAnnotation(BeforeClass.class) != null) {
238 sb.append(" test.").append(m.getName()).append("();\n");
239 }
240 }
241 sb.append(" }\n");
242
243 sb.append("\n @Override\n");
244 sb.append(" public void tearDown() throws Exception {\n");
245 sb.append(" super.tearDown();\n");
246 sb.append(" // tests run when class completes...\n");
247 for (Method m : methods) {
248 if (m.getAnnotation(AfterClass.class) != null) {
249 sb.append(" test.").append(m.getName()).append("();\n");
250 }
251 }
252 sb.append(" }\n");
253
254 for (Method m : methods) {
255 Test tanno = null;
256 if ((tanno = m.getAnnotation(Test.class)) != null && m.getAnnotation(Ignore.class) == null) {
257 final String tname = getTestName(m);
258 sb.append("\n");
259 sb.append(" public void ").append(tname).append("()").append(buildThrows(excepts, m)).append("{\n");
260 for (Method pre : pretest) {
261 sb.append(" // pre test\n");
262 sb.append(" test.").append(pre.getName()).append("();\n");
263 }
264 if (posttest.isEmpty()) {
265 sb.append(" // actual test\n");
266 if (tanno.expected() == Test.None.class) {
267 sb.append(" test.").append(m.getName()).append("();\n");
268 } else {
269 sb.append(" try {\n");
270 sb.append(" test.").append(m.getName()).append("();\n");
271 sb.append(" org.jdom.test.util.UnitTestUtil.failNoException(").append(tanno.expected().getName()).append(".class);\n");
272 sb.append(" } catch (").append(tanno.expected().getName()).append(" e) {\n");
273 sb.append(" org.jdom.test.util.UnitTestUtil.checkException(").append(tanno.expected().getName()).append(".class, e);\n");
274 sb.append(" }\n");
275 }
276 } else {
277 sb.append(" try {\n");
278 sb.append(" // actual test\n");
279 if (tanno.expected() == Test.None.class) {
280 sb.append(" test.").append(m.getName()).append("();\n");
281 } else {
282 sb.append(" try {\n");
283 sb.append(" test.").append(m.getName()).append("();\n");
284 sb.append(" org.jdom.test.util.UnitTestUtil.failNoException(").append(tanno.expected().getName()).append(".class);\n");
285 sb.append(" } catch (Exception e) {\n");
286 sb.append(" org.jdom.test.util.UnitTestUtil.checkException(").append(tanno.expected().getName()).append(".class, e);\n");
287 sb.append(" }\n");
288 }
289 sb.append(" } finally {\n");
290 for (Method post : posttest) {
291 sb.append(" // post test\n");
292 sb.append(" test.").append(post.getName()).append("();\n");
293 }
294 sb.append(" }\n");
295
296 }
297 sb.append(" }\n");
298 }
299 }
300
301 }
302
303 sb.append("\n}\n");
304 final File outd = outf.getParentFile().getAbsoluteFile();
305 if (!outd.isDirectory()) {
306 outd.mkdirs();
307 }
308 FileWriter fw = new FileWriter(outf);
309 fw.write(sb.toString());
310 fw.flush();
311 fw.close();
312 return ret;
313 }
314
315 private String getTestName(final Method m) {
316 final String mname = m.getName();
317 for (String mm : skipmethods) {
318 if (Pattern.matches(mm, mname)) {
319 return "/* Skip test on Android */ do_not_" + mname;
320 }
321 }
322 return mname.startsWith("test") ? mname : ("test_" + mname);
323 }
324
325 private Set<String> getExceptions(Method m) {
326 TreeSet<String> hs = new TreeSet<String>();
327 if (m != null) {
328 for (Class<?> ec : m.getExceptionTypes()) {
329 hs.add(ec.getName());
330 }
331 }
332 return hs;
333 }
334
335 private String buildThrows(Set<String> current, Method m) {
336 final Set<String> tothrow = getExceptions(m);
337 if (current != null) {
338 tothrow.addAll(current);
339 }
340 final Iterator<String> it = tothrow.iterator();
341 if (!it.hasNext()) {
342 return " ";
343 }
344 final StringBuilder sb = new StringBuilder();
345 sb.append(" throws ").append(it.next());
346 while (it.hasNext()) {
347 sb.append(", ").append(it.next());
348 }
349 sb.append(" ");
350 return sb.toString();
351 }
352
353 }
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin & Alex Chaffee.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.beans;
55
56 import java.lang.reflect.*;
57 import java.util.*;
58 import java.beans.*;
59 import org.jdom.Document;
60 import org.jdom.Element;
61 import org.jdom.Attribute;
62 import org.jdom.Namespace;
63
64 /**
65 * Maps a JavaBean to an XML tree and vice versa. (Yes, it's yet
66 * another XML Data Binding solution.) Given a JavaBean, it will
67 * produce a JDOM tree whose elements correspond to the bean's
68 * property values. Given a JDOM tree, it will return a new instance
69 * of that bean whose properties have been set using the corresponding
70 * values in the JDOM tree. <p>
71 *
72 * By default, it assumes each element maps to a property of the same
73 * name, subject to normal capitalization rules. That is, an element
74 * &lt;foo&gt; will map to the methods setFoo and getFoo. You can
75 * change this behavior by calling the various <code>addMapping</code>
76 * methods. For instance, to map a an element &lt;date&gt; to the
77 * property "birthDate" (using methods setBirthDate and getBirthDate),
78 * call <pre>mapper.addMapping("birthDate", "date");</pre> You can
79 * also map a property to an attribute, either of a child or of the
80 * parent (see JavaDoc for
81 * <a href="#addMapping(java.lang.String, java.lang.String, java.lang.String)">
82 * addMapping(String property, String element, String attribute)</a>
83 * for details). <p>
84 *
85 * During Bean -> JDOM conversion, if a BeanInfo object is found, it
86 * will be respected. See JavaDoc for java.beans.Introspector. <p>
87 *
88 * If a given property, element, or attribute is to be skipped
89 * (ignored) during conversion, call the appropriate ignore method
90 * (ignoreProperty, ignoreElement, or ignoreAttribute). This is also
91 * appropriate if your bean has multiple accessors (properties) for
92 * the same underlying data. <p>
93 *
94 * Support for Namespaces is rudimentary at best and has not been
95 * well-tested; if you specify a Namespace then all created elements
96 * and attributes will be in that namespace (or all elements not in
97 * that namespace will be skipped, for JDOM->Bean mapping). <p>
98 *
99 * If a bean property type is a Java array, its items will be mapped
100 * to multiple child elements of the bean element (multiple children
101 * at the base level, not one child). This is to provide an easier
102 * transition for XML documents whose elements contain multiple
103 * children with the same name.<p>
104 *
105 * Please try this out on your own beans. If there is a case that
106 * fails to do what you like (for instance, properties with custom
107 * class types), let me know and I'll try to work it out. <p>
108 *
109 * <pre>TODO:
110 * support list properties (collections other than Java arrays)
111 * allow lists/arrays to map to either scattered elements or a single nested element
112 * sort XML elements in some order other than random BeanInfo order
113 * support for BeanInfoSearchPaths
114 * multiple packages searched for beans
115 * better support for Namespaces (hard)
116 * allow stringconverter to map object -> string (not just string -> object)
117 * id/idref support for cyclical references
118 * more type converters
119 * custom property converters
120 * known issue: inner class bean can't be found jdom->bean (workaround: define mapping containing class name)
121 * </pre>
122 *
123 * <h2>Example:</h2>
124 * <h3>TestBean</h3>
125 * <pre>
126 * public class TestBean implements java.io.Serializable {
127 * public String getName() { ... }
128 * public int getAge() { ... }
129 * public Date getBirthdate() { ... }
130 * public TestBean getFriend() { ... }
131 * public void setName(String name) { ... }
132 * public void setAge(int age) { ... }
133 * public void setBirthdate(Date birthdate) { ... }
134 * public void setFriend(TestBean friend) { ... }
135 * public String toString() { ... }
136 * }
137 * </pre>
138 * <h3>XML Representation</h3>
139 * <pre>&nbsp;&lt;testBean&gt;
140 * &nbsp;&nbsp;&lt;dob age="31"&gt;Fri Aug 08 00:00:00 EDT 1969&lt;/dob&gt;
141 * &nbsp;&nbsp;&lt;name&gt;Alex&lt;/name&gt;
142 * &nbsp;&nbsp;&lt;friend&gt;
143 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;testBean&gt;
144 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;dob age="25"&gt;Thu May 01 00:00:00 EDT 1975&lt;/dob&gt;
145 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;name&gt;Amy&lt;/name&gt;
146 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;/testBean&gt;
147 * &nbsp;&nbsp;&lt;/friend&gt;
148 * &lt;/testBean&gt;
149 * </pre>
150 * <h3>Mapping code</h3>
151 * <pre> BeanMapper mapper = new BeanMapper();
152 * mapper.addMapping("birthdate", "dob"); // element mapping
153 * mapper.addMapping("age", "dob", "age"); // attribute mapping
154 * mapper.setBeanPackage("org.jdom.contrib.beans");
155 * </pre>
156 * <h3>Converting Bean to JDOM</h3>
157 * <pre>Document doc = mapper.toDocument(alex);</pre>
158 * <h3>Converting JDOM to Bean</h3>
159 * <pre>TestBean alex = mapper.toBean(doc);</pre>
160 *
161 * @author Alex Chaffee (alex@jguru.com)
162 **/
163
164 @SuppressWarnings("javadoc")
165 public class BeanMapper {
166
167 protected String beanPackage;
168 protected Namespace namespace;
169 protected boolean ignoreMissingProperties = false;
170 protected boolean ignoreNullProperties = true;
171 protected List<Mapping> mappings = new ArrayList<Mapping>();
172 protected StringConverter stringconverter = new StringConverter();
173
174 /**
175 * Default constructor. If you are only doing bean -> XML
176 * mapping, you may use the mapper immediately. Otherwise, you
177 * must call setBeanPackage.
178 **/
179 public BeanMapper()
180 {
181 }
182
183 // Properties
184
185 /**
186 * @param beanPackage the name of the package in which to find the
187 * JavaBean classes to instantiate
188 **/
189 public void setBeanPackage(String beanPackage)
190 {
191 this.beanPackage = beanPackage;
192 }
193
194 /**
195 * Use this namespace when creating the XML element and all
196 * child elements.
197 **/
198 public void setNamespace(Namespace namespace)
199 {
200 this.namespace = namespace;
201 }
202
203 /**
204 * Get the object responsible for converting a string to a known
205 * type. Once you get this, you can call its setFactory() method
206 * to add a converter for a custom type (for which toString() does
207 * not suffice). The default string converter has a factory that
208 * recognizes several date formats (including ISO8601 -
209 * e.g. "2000-09-18 18:51:22-0600" or some substring thereof).
210 **/
211 public StringConverter getStringConverter() {
212 return stringconverter;
213 }
214
215 /**
216 * Set a custom string converter.
217 **/
218 public void setStringConverter(StringConverter stringconverter) {
219 this.stringconverter = stringconverter;
220 }
221
222 /**
223 * In mapping from Bean->JDOM, if we encounter an property with a
224 * null value, should
225 * we ignore it or add an empty child element/attribute (default: true)?
226 * @param b true = ignore, false = empty element
227 **/
228 public void setIgnoreNullProperties(boolean b) {
229 ignoreNullProperties = b;
230 }
231
232 /**
233 * In mapping from JDOM->Bean, if we encounter an element or
234 * attribute without a corresponding property in the bean, should
235 * we ignore it or throw an exception (default: false)?
236 * @param b true = ignore, false = throw exception
237 **/
238 public void setIgnoreMissingProperties(boolean b) {
239 ignoreMissingProperties = b;
240 }
241
242
243 // Bean -> JDOM Mapping
244
245 /**
246 * Converts the given bean to a JDOM Document.
247 * @param bean the bean from which to extract values
248 **/
249 public Document toDocument(Object bean) throws BeanMapperException {
250 return toDocument(bean, null);
251 }
252
253 /**
254 * Converts the given bean to a JDOM Document.
255 * @param bean the bean from which to extract values
256 * @param name the name of the root element (null => use bean class name)
257 **/
258 public Document toDocument(Object bean, String elementName)
259 throws BeanMapperException {
260 Element root = toElement(bean, elementName);
261 Document doc = new Document(root);
262 return doc;
263 }
264
265 /**
266 * Converts the given bean to a JDOM Element.
267 * @param bean the bean from which to extract values
268 * @param elementName the name of the element (null => use bean class name)
269 **/
270 public Element toElement(Object bean) throws BeanMapperException
271 {
272 return toElement(bean, null);
273 }
274
275 /**
276 * Converts the given bean to a JDOM Element.
277 * @param bean the bean from which to extract values
278 * @param elementName the name of the element (null => use bean class name)
279 **/
280 public Element toElement(Object bean, String elementName)
281 throws BeanMapperException {
282 BeanInfo info;
283 try {
284 // cache this?
285 info = Introspector.getBeanInfo(bean.getClass());
286 }
287 catch (IntrospectionException e) {
288 throw new BeanMapperException("Mapping bean " + bean, e);
289 }
290
291 // create element
292 Element element;
293 String beanname;
294 if (elementName != null) {
295 element = createElement(elementName);
296 }
297 else {
298 Class<?> beanclass = info.getBeanDescriptor().getBeanClass();
299 beanname = unpackage(beanclass.getName());
300 element = createElement(beanname);
301 }
302
303 // get all properties, set as child-elements
304 PropertyDescriptor[] properties = info.getPropertyDescriptors();
305 for (int i=0; i<properties.length; ++i) {
306 PropertyDescriptor prop = properties[i];
307 String propertyName = prop.getName();
308
309 Method method = prop.getReadMethod();
310
311 // hack to skip Object.getClass
312 if (method.getName().equals("getClass") &&
313 prop.getPropertyType().getName().equals("java.lang.Class"))
314 continue;
315
316 // skip ignored properties
317 if (isIgnoredProperty(propertyName))
318 continue;
319
320 // do we have a mapping for this property?
321 Mapping mapping = getMappingForProperty(propertyName);
322
323 // get the value
324 if (method.getParameterTypes().length != 0)
325 // if this getter takes parameters, ignore it
326 continue;
327
328 Object valueObject = null;
329 try {
330 Object[] args = new Object[0]; // make static?
331 valueObject = method.invoke(bean, args);
332 }
333 catch (java.lang.IllegalAccessException e) {
334 throw new BeanMapperException("Mapping " + propertyName, e);
335 }
336 catch (java.lang.reflect.InvocationTargetException e) {
337 throw new BeanMapperException("Mapping " + propertyName, e);
338 }
339
340 // convert it to a string or element or list
341 Object value = convertValue(valueObject);
342
343 if (value == null && ignoreNullProperties) {
344 debug("Ignoring null " + propertyName);
345 continue;
346 }
347
348 String childElementName;
349
350 if (mapping == null) {
351 childElementName = propertyName;
352 }
353 else
354 childElementName = mapping.element;
355
356 // get existing element, or create it.
357
358 // we must look for an existing element even when setting
359 // an element value, since it may have been subject to an
360 // attribute mapping, and thus already created (without
361 // any content, but with an attribute).
362
363 Element child = null;
364 if (childElementName != null) {
365 if (namespace != null)
366 child = element.getChild(childElementName, namespace);
367 else {
368 child = element.getChild(childElementName);
369 }
370 if (child == null) {
371 child = createElement(childElementName);
372 element.addContent(child);
373 }
374 }
375
376 if (mapping == null || mapping.attribute == null) {
377 // set as element
378 setElementValue(propertyName, childElementName,
379 element, child, value);
380 }
381
382 else {
383 try {
384 // set as attribute
385 if (value == null)
386 value = ""; // no such thing as null attribute in XML
387 if (childElementName == null) // add attr to parent
388 element.setAttribute(mapping.attribute, (String)value);
389 else // add attr to child
390 child.setAttribute(mapping.attribute, (String)value);
391 }
392 catch (ClassCastException e) {
393 throw new BeanMapperException(
394 "Can't set type " + value.getClass() + " as attribute");
395 }
396 }
397 }
398
399 // todo: sort in mapping order
400 return element;
401 } // toElement
402
403 /**
404 * convert property value (returned from getter) to a string or
405 * element or list
406 **/
407 protected Object convertValue(Object value) throws BeanMapperException
408 {
409 if (value == null)
410 return null;
411 Object result;
412 Class<?> type = value.getClass();
413 String classname = type.getName();
414
415 // todo: allow per-type callback to convert (if toString() is
416 // inadequate) -- extend stringconverter?
417 if (classname.startsWith("java.lang.") ||
418 classname.equals("java.util.Date")
419 )
420 {
421 result = value.toString();
422 }
423 else if (type.isArray()) {
424 // it's an array - use java.lang.reflect.Array to extract
425 // items (or wrappers thereof)
426 List<Object> list = new ArrayList<Object>();
427 for (int i=0; i<Array.getLength(value); ++i) {
428 Object item = Array.get(value, i);
429 list.add( convertValue(item) ); // recurse
430 }
431 result = list;
432 }
433 else
434 {
435 // treat it like a bean
436 // recursive call to mapper
437 debug("Recurse on bean " + classname + "=" + value);
438 result = toElement(value);
439 }
440
441 return result;
442 } // convertValue
443
444 protected void setElementValue(String propertyName,
445 String elementName,
446 Element parent,
447 Element child,
448 Object value) throws BeanMapperException {
449 debug("setElementValue(" + propertyName + "," +
450 elementName + "," +
451 child.getName() + "," +
452 value + ")");
453
454 if (value == null) {
455 // do nothing
456 }
457 else if (value instanceof Element) {
458 child.addContent((Element)value);
459 }
460 else if (value instanceof String) {
461 child.setText((String)value);
462 }
463 else if (value instanceof List) {
464 for (Iterator<?> it = ((List<?>)value).iterator();
465 it.hasNext(); )
466 {
467 Object item = it.next();
468 if (child == null) {
469 child = createElement(elementName);
470 parent.addContent(child);
471 }
472 setElementValue(propertyName, elementName, parent, child, item);
473 // this'll be weird if it's an array of arrays
474 child = null;
475 }
476 }
477 else
478 throw new BeanMapperException(
479 "Unknown result type for property " + propertyName + ": " + value);
480 }
481
482 // JDOM -> Bean
483
484 /**
485 * Converts the given JDOM Document to a bean
486 * @param document the document from which to extract values
487 **/
488 public Object toBean(Document document) throws BeanMapperException {
489 return toBean(document.getRootElement());
490 }
491
492 public Object toBean(Element element) throws BeanMapperException {
493
494 Object bean = instantiateBean(element.getName());
495
496 Mapping mapping;
497 String propertyName;
498
499 Set<String> alreadySet = new HashSet<String>();
500
501 // map Attributes of parent first
502 if (element.hasAttributes()) {
503 for (Attribute attribute : element.getAttributes()) {
504 debug("Mapping " + attribute);
505 mapping = getMappingForAttribute(null, attribute.getName());
506 propertyName = (mapping==null) ?
507 attribute.getName() : mapping.property;
508 setProperty(bean, propertyName, attribute.getValue());
509 }
510 }
511
512 // map child Elements
513 //debug(element.toString() + " has " + children.size() + " children");
514 for (Element child : element.getChildren()) {
515 debug("Mapping " + child);
516
517 mapping = getMappingForElement(child.getName());
518 propertyName = (mapping==null) ? child.getName() : mapping.property;
519
520 // set bean property from element
521 PropertyDescriptor property =
522 findPropertyDescriptor(bean, propertyName);
523 if (property != null) {
524 if (!alreadySet.contains(child.getName())) {
525 if (property.getPropertyType().isArray())
526 setProperty(bean, property, element, child);
527 else
528 setProperty(bean, property, element, child);
529 }
530 }
531
532 // Now map all attributes of this child
533 for (Attribute attribute : child.getAttributes()) {
534 debug("Mapping " + attribute);
535 mapping = getMappingForAttribute(child.getName(),
536 attribute.getName());
537 propertyName = (mapping==null) ?
538 attribute.getName() : mapping.property;
539 setProperty(bean, propertyName, attribute.getValue());
540 } // for attributes
541
542 alreadySet.add(child.getName());
543
544 } // for children
545
546 return bean;
547 } // toBean
548
549
550 /**
551 * return a fresh new object of the appropriate bean type for
552 * the given element name.
553 * @return the bean
554 **/
555 protected Object instantiateBean(String elementName)
556 throws BeanMapperException {
557 // todo: search multiple packages
558 String className = null;
559 Class<?> beanClass;
560 try {
561 Mapping mapping = getMappingForElement(elementName);
562 if (mapping != null &&
563 mapping.type != null) {
564 beanClass = mapping.type;
565 }
566 else {
567 className = getBeanClassName(beanPackage, elementName);
568 beanClass = Class.forName(className);
569 }
570 Object bean = beanClass.newInstance();
571 return bean;
572 }
573 catch (ClassNotFoundException e) {
574 throw new BeanMapperException("Class " + className +
575 " not found instantiating " + elementName +
576 " - maybe you need to add a mapping, or add a bean package", e);
577 }
578 catch (Exception e) {
579 throw new BeanMapperException("Instantiating " + elementName, e);
580 }
581 }
582
583 protected String getBeanClassName(String pbeanPackage, String elementName) {
584 return (pbeanPackage == null ? "" : (pbeanPackage + ".")) +
585 Character.toUpperCase(elementName.charAt(0)) +
586 elementName.substring(1);
587 }
588
589 protected PropertyDescriptor findPropertyDescriptor(Object bean,
590 String propertyName)
591 throws BeanMapperException {
592 try {
593 // cache this?
594 BeanInfo info = Introspector.getBeanInfo(bean.getClass());
595 PropertyDescriptor[] properties = info.getPropertyDescriptors();
596 for (int i=0; i<properties.length; ++i) {
597 PropertyDescriptor prop = properties[i];
598 if (prop.getName().equals(propertyName))
599 return prop;
600 }
601 }
602 catch (Exception e) {
603 throw new BeanMapperException("Finding property " + propertyName +
604 " for bean " + bean.getClass(), e);
605 }
606 if (ignoreMissingProperties) {
607 return null;
608 }
609 throw new BeanMapperException("Missing property: " +
610 propertyName + " in bean " + bean.getClass() + ": " + bean);
611 } // findPropertyDescriptor
612
613
614 /**
615 * set a property in the bean
616 * @param bean the bean to modify
617 * @param propertyName the name of the property to set
618 * @param value the new value
619 * @return true if successful, false if property not found
620 **/
621 protected boolean setProperty(Object bean, String propertyName,
622 Object value) throws BeanMapperException {
623 return setProperty(bean, findPropertyDescriptor(bean, propertyName),
624 null, value);
625 }
626
627 /**
628 * set a property in the bean
629 * @param bean the bean to modify
630 * @param property the property to set
631 * @param value the new value
632 * @return true if successful, false if property not found
633 **/
634 protected boolean setProperty(Object bean, PropertyDescriptor property,
635 Element parent, Object value)
636 throws BeanMapperException {
637 if (property == null)
638 return false;
639
640 debug("setProperty: bean=" + bean + " property=" +
641 property.getName() + " value=" + value);
642 try {
643 // convert the value to the right type
644 Object valueObject;
645 if (property.getPropertyType().isArray()) {
646 // build array based on children of this name
647 Element child = (Element)value;
648 List<Element> children = parent.getChildren(child.getName());
649 valueObject = buildArray(property, children);
650 }
651 else {
652 // normal property
653 valueObject = convertJDOMValue(value,
654 property.getPropertyType());
655 }
656
657 // find and invoke the setter
658 Method setter = property.getWriteMethod();
659 Class<?>[] params = setter.getParameterTypes();
660 if (params.length > 1)
661 throw new BeanMapperException(
662 "Setter takes multiple parameters: " + bean.getClass() +
663 "." + setter.getName());
664
665 Class<?> param = params[0];
666 if (param != property.getPropertyType())
667 debug("Weird: setter takes " + param + ", property is " +
668 property.getPropertyType());
669
670 debug("Invoking setter: " + setter.getName() +
671 "(" + valueObject + ")");
672 setter.invoke(bean, new Object[] { valueObject });
673
674 return true;
675 }
676 catch (BeanMapperException e) {
677 throw e;
678 }
679 catch (Exception e) {
680 throw new BeanMapperException("Setting property " +
681 property.getName() + "=" + value + " in " + bean.getClass(), e);
682 }
683 }
684
685 protected Object convertString(String value, Class<?> type) {
686 if (value == null)
687 return null;
688 if (type == String.class)
689 return value;
690 return stringconverter.parse(value, type);
691 }
692
693 protected Object convertJDOMValue(Object value, Class<?> type)
694 throws BeanMapperException {
695 Object valueObject;
696
697 // Null value
698 if (value == null)
699 valueObject = null;
700
701 // String value
702 else if (value instanceof String) {
703 valueObject = convertString((String)value, type);
704 }
705
706 // Element value
707 else if (value instanceof Element) {
708 Element element = (Element)value;
709
710 // if the setter actually takes a JDOM element, pass it
711 if (type == Element.class)
712 valueObject = value;
713
714 // no children, must be a text node
715 else if (element.getChildren().isEmpty())
716 {
717 valueObject = convertString(element.getText(), type);
718 }
719
720 // we have to convert it into a bean
721 else if (element.getChildren().size() == 1) {
722
723 // Make a recursive call to this BeanMapper to map
724 // the child element
725
726 // Note that toBean could return a subclass of the
727 // property type, so just let it figure out the
728 // right type
729
730 valueObject = toBean(element.getChildren().get(0));
731 }
732 else {
733 // element with multiple children -- must be an
734 // array property
735 throw new BeanMapperException(
736 "Mapping of multiple child elements not implemented for " +
737 element.getName());
738 }
739 }
740 else {
741 throw new BeanMapperException("Can't map unknown type: " +
742 value.getClass() + "=" + value);
743 }
744 return valueObject;
745 } // convert JDOMValue
746
747 /**
748 * @return an array of the appropriate type
749 **/
750 protected Object buildArray(PropertyDescriptor property, List<Element> children)
751 throws BeanMapperException {
752 Class<?> arrayClass = property.getPropertyType();
753
754 Class<?> itemClass = arrayClass.getComponentType();
755
756 if (itemClass == null) {
757 throw new BeanMapperException("Can't instantiate array of type " +
758 arrayClass);
759 }
760
761 // use java.lang.reflect.Array
762 Object array = Array.newInstance(itemClass, children.size());
763
764 // fill it
765 for (int i = 0; i<children.size(); ++i) {
766 Element child = children.get(i);
767 Object value = convertJDOMValue(child, itemClass);
768 debug( itemClass + "[" + i + "]=" + value );
769 Array.set(array, i, value);
770 }
771
772 return array;
773 }
774
775
776 public static Class<?> getArrayItemClass(Class<?> arrayClass)
777 throws ClassNotFoundException {
778 Class<?> itemClass;
779
780 // there seems to be no way to get the item class from an
781 // array class object, so parse the name
782 String arrayClassName = arrayClass.getName();
783 debug("Parsing array classname: " + arrayClassName);
784 if (arrayClassName.equals("[B")) {
785 itemClass = byte.class;
786 }
787 else if (arrayClassName.equals("[C")) {
788 itemClass = char.class;
789 }
790 else if (arrayClassName.equals("[D")) {
791 itemClass = double.class;
792 }
793 else if (arrayClassName.equals("[F")) {
794 itemClass = float.class;
795 }
796 else if (arrayClassName.equals("[I")) {
797 itemClass = int.class;
798 }
799 else if (arrayClassName.equals("[J")) {
800 itemClass = long.class;
801 }
802 else if (arrayClassName.equals("[S")) {
803 itemClass = short.class;
804 }
805 else if (arrayClassName.equals("[Z")) {
806 itemClass = boolean.class;
807 }
808 else if (arrayClassName.startsWith("[L")) {
809 itemClass = Class.forName(
810 arrayClassName.substring(2, arrayClassName.length()-1));
811 }
812 else
813 itemClass = null;
814 return itemClass;
815 }
816
817 // Mappings
818
819 /**
820 * Map a property name to an XML element
821 * @param property the name of the property
822 * @param element the name of the element
823 **/
824 public void addMapping(String property, String element) {
825 addMapping(new Mapping(property, null, element, null));
826 }
827
828 /**
829 * Map a property name to an attribute in an XML element. If
830 * element is null, it's an attribute on the parent element
831 * (e.g. &lt;myBean id="123"&gt;); otherwise, it's an
832 * attribute on a child element (e.g. &lt;myBean&gt;&lt;thing
833 * id="123"&gt;).
834 * @param property the name of the property
835 * @param element the name of the element containing the attribute.
836 * null => parent element
837 * @param attribute the name of the attribute. null => set as element
838 **/
839 public void addMapping(String property, String element, String attribute) {
840 addMapping(new Mapping(property, null, element, attribute));
841 }
842
843 /**
844 * Map a property name to an element or an attribute. Can also
845 * specify which bean class to instantiate (applies to JDOM->Bean
846 * mapping).
847 *
848 * @param property the name of the property. null => look for property
849 * with same name as the element
850 * @param type Always convert this element name to this class.
851 * null => look for a bean with the same name as the element
852 * @param element the name of the element containing the attribute.
853 * null => parent element
854 * @param attribute the name of the attribute. null => set as element
855 **/
856 public void addMapping(String property, Class<?> type,
857 String element, String attribute) {
858 addMapping(new Mapping(property, type, element, attribute));
859 }
860
861 public void addMapping(Mapping mapping) {
862 mappings.add(mapping);
863 }
864
865 public Mapping getMappingForProperty(String property) {
866 for (Mapping m : mappings) {
867 if (m.property != null && m.property.equals(property)) {
868 return m;
869 }
870 }
871 return null;
872 }
873
874 public Mapping getMappingForElement(String element) {
875 for (Mapping m : mappings) {
876 if (m.element.equals(element)) {
877 return m;
878 }
879 }
880 return null;
881 }
882
883 public Mapping getMappingForAttribute(String element, String attribute) {
884 for (Mapping m : mappings) {
885 if (m.element != null &&
886 m.attribute != null &&
887 m.element.equals(element) &&
888 m.attribute.equals(attribute))
889 {
890 return m;
891 }
892 }
893 return null;
894 }
895
896 public class Mapping {
897 public String property;
898 public Class<?> type;
899 public String element;
900 public String attribute;
901
902 /**
903 * @param property the name of the property. null => look for
904 * property with same name as the element
905 * @param type Always convert this element name to this class.
906 * null => look for a bean with the same name as the element
907 * @param element the name of the element containing the attribute.
908 * null => parent element
909 * @param attribute the name of the attribute. null => set as element
910 **/
911 public Mapping(String property, Class<?> type,
912 String element, String attribute) {
913 this.property = property;
914 this.type = type;
915 this.element = element;
916 this.attribute = attribute;
917 }
918
919
920 }
921
922 // Hiding
923
924 protected Set<String> ignoredProperties = new HashSet<String>();
925 protected Set<String> ignoredElements = new HashSet<String>();
926 protected Set<String> ignoredAttributes = new HashSet<String>();
927
928 public void ignoreProperty(String property) {
929 ignoredProperties.add(property);
930 }
931
932 public boolean isIgnoredProperty(String property) {
933 return ignoredProperties.contains(property);
934 }
935
936 public void ignoreElement(String element) {
937 ignoredElements.add(element);
938 }
939
940 public boolean isIgnoredElement(String element) {
941 return ignoredElements.contains(element);
942 }
943
944 static protected String toAttributeString(String element,
945 String attribute) {
946 return (element == null ? "." : element) +
947 "/@" + attribute;
948 }
949
950 public void ignoreAttribute(String element, String attribute) {
951 ignoredAttributes.add(toAttributeString(element, attribute));
952 }
953
954 public boolean isIgnoredAttribute(String element, String attribute) {
955 return ignoredAttributes.contains(
956 toAttributeString(element, attribute));
957 }
958
959 // Utilities
960
961 protected Element createElement(String elementName) {
962 return namespace == null ? new Element(elementName) :
963 new Element(elementName, namespace);
964 }
965
966 protected static String unpackage(String classname) {
967 int dot = Math.max(classname.lastIndexOf("."),
968 classname.lastIndexOf("$"));
969 if (dot > -1) {
970 classname = classname.substring(dot+1);
971 }
972 classname = Introspector.decapitalize(classname);
973 return classname;
974 }
975
976 public static int debug = 0;
977 protected static void debug(String msg) {
978 if (debug > 0)
979 System.err.println("BeanMapper: " + msg);
980 }
981 }
982
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.beans;
55
56
57 /**
58 *
59 * @author Alex Chaffee (alex@jguru.com)
60 **/
61
62 @SuppressWarnings("javadoc")
63 public class BeanMapperException extends Exception {
64
65 /**
66 * Default.
67 */
68 private static final long serialVersionUID = 1L;
69
70 public BeanMapperException(Exception rootCause) {
71 super(rootCause);
72 }
73
74 public BeanMapperException(String message, Exception rootCause) {
75 super(message, rootCause);
76 }
77
78 public BeanMapperException(String message) {
79 super(message);
80 }
81
82 }
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 // Based on code Copyright (c) 1998-2000 Alex Chaffee and Purple Technology.
55
56 package org.jdom.contrib.beans;
57
58 import java.util.*;
59 import java.util.regex.Matcher;
60 import java.util.regex.Pattern;
61 import java.util.regex.PatternSyntaxException;
62 import java.text.*;
63
64 /**
65 * @author Alex Chaffee (alex@jguru.com)
66 **/
67 @SuppressWarnings("javadoc")
68 public class DateUtils {
69
70 public static boolean debug;
71
72 /**
73 * Tries to parse the date according to several different formats.
74 * <p>
75 * BUG in TimeZone processing -- Calendar class always screws up the time when a TZ is set -- so ignored for now.
76 *
77 * @return null if not parseable
78 **/
79 @SuppressWarnings("deprecation")
80 public static Date parseDate(String s) {
81
82 // some standard date format
83 try {
84 // this is deprecated, but it still parses more
85 // formats than DateFormat.parse(String)
86 return new Date(s);
87 }
88 catch (IllegalArgumentException dfe) {
89 // do nothing... we try to recover.
90 }
91
92 // some other (?) standard date format
93 try {
94 return DateFormat.getDateInstance().parse(s);
95 }
96 catch (ParseException pe) {
97 // OK, this is challenging, but we try the next option.
98 }
99
100 // a single int = msec since 1970
101 try {
102 return new Date(Long.parseLong(s));
103 }
104 catch (NumberFormatException nfe) {
105 // Getting rediculous now...
106 }
107
108 ISO8601 iso = parseISO8601(s);
109 if (iso != null) {
110 Calendar cal = Calendar.getInstance();
111
112 cal.set(Calendar.YEAR, iso.year);
113 cal.set(Calendar.MONTH, iso.month - 1);
114 cal.set(Calendar.DAY_OF_MONTH, iso.day);
115 cal.set(Calendar.HOUR, iso.hour + 12); // ??? TZ bug again?
116 cal.set(Calendar.MINUTE, iso.min);
117 cal.set(Calendar.SECOND, iso.sec);
118
119 return cal.getTime(); // why the hell does getTime() return a Date?
120
121
122 } // if iso
123
124 return null;
125 } // parseDate
126
127 public static class ISO8601 {
128 public int year;
129 public int month;
130 public int day;
131 public int hour;
132 public int min;
133 public int sec;
134 public int frac;
135 public String tz;
136 }
137
138 protected static String reISO8601 =
139 "(\\d\\d\\d\\d)(-(\\d\\d)(-(\\d\\d))?)?" +
140 "([T| ]?" +
141 "(\\d\\d):(\\d\\d)(:((\\d\\d)(\\.(\\d+))?)?)?" +
142 "(Z|([+-]\\d\\d:\\d\\d)|([A-Z]{3}))?)?";
143
144 public static ISO8601 parseISO8601(String s) {
145 // ISO 8601 datetime: http://www.w3.org/TR/NOTE-datetime
146 // e.g. 1997-07-16T19:20:30.45+01:00
147 // additions: "T" can be a space, TZ can be a three-char code, TZ can be missing
148 try {
149 Pattern pat = Pattern.compile(reISO8601);
150 Matcher re = pat.matcher(s);
151 if (re.matches()) {
152 if (debug)
153 showParens(re);
154
155 ISO8601 iso = new ISO8601();
156 iso.year = toInt(re.group(1));
157 iso.month = toInt(re.group(3));
158 iso.day = toInt(re.group(5));
159 iso.hour = toInt(re.group(7));
160 iso.min = toInt(re.group(8));
161 iso.sec = toInt(re.group(11));
162 iso.frac = toInt(re.group(13));
163 iso.tz = re.group(14);
164
165 if (debug) {
166 System.out.println("year='" + iso.year + "'");
167 System.out.println("month='" + iso.month + "'");
168 System.out.println("day='" + iso.day + "'");
169 System.out.println("hour='" + iso.hour + "'");
170 System.out.println("min='" + iso.min + "'");
171 System.out.println("sec='" + iso.sec + "'");
172 System.out.println("frac='" + iso.frac + "'");
173 System.out.println("tz='" + iso.tz + "'");
174 }
175
176 return iso;
177 }
178 } // try
179 catch (PatternSyntaxException ree) {
180 ree.printStackTrace();
181 }
182 return null;
183 }
184
185 public static int toInt(String x) {
186 if (x == null) return 0;
187 try {
188 return Integer.parseInt(x);
189 }
190 catch (NumberFormatException e) {
191 return 0;
192 }
193 }
194
195 /**
196 * Dump parenthesized subexpressions found by a regular expression matcher object
197 * @param r Matcher object with results to show
198 */
199 static void showParens(Matcher r)
200 {
201 // Loop through each paren
202 for (int i = 0; i < r.groupCount(); i++)
203 {
204 // Show paren register
205 System.out.println("$" + i + " = " + r.group(i));
206 }
207 }
208
209 public static void main(String[] args) {
210 debug = true;
211 for (int i=0; i<args.length; ++i) {
212 System.out.println( parseDate(args[i]) );
213 }
214 }
215 }
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.beans;
55
56 import java.io.File;
57 import java.io.IOException;
58 import java.util.*;
59
60 import org.jdom.Document;
61 import org.jdom.Element;
62 import org.jdom.JDOMException;
63 import org.jdom.input.SAXBuilder;
64 import org.jdom.input.sax.XMLReaderJDOMFactory;
65 import org.jdom.input.sax.XMLReaderSAX2Factory;
66 import org.jdom.output.XMLOutputter2;
67
68 // todo:
69 // weak references and/or timeout cache
70 // load from URL (instead of just from file)
71 // pathname normalization (remove ./ and foo/../ and so forth)
72 // allow DOM builder or arbitrary builder
73
74 /**
75 * A light wrapper on the JDOM library that you use to load in a file
76 * and turn it into a JDOM Document. It also keeps a cache of
77 * already-parsed files, and checks to see if they've changed on disk,
78 * and reloads if they have. (I know there's some sort of swap-out or
79 * weak-reference stuff either in JDOM or coming soon, so this may be
80 * a redundant feature.)
81 * <p>
82 *
83 * <h3>Usage from Java:</h3>
84 *
85 * <pre>
86 * JDOMBean jdom = new JDOMBean(); // or new JDOMBean("com.foo.saxparser")
87 * jdom.setFileRoot("/path/to/my/xml/documents/");
88 * Document doc = jdom.getDocument("foo.xml");
89 * Element root = jdom.getRootElement("foo.xml");
90 * </pre>
91 *
92 * <h3>Usage from JSP:</h3>
93 *
94 * <pre>
95 *
96 * &lt;jsp:useBean id="jdom" class="JDOMBean" scope="application"&gt;
97 * &lt;% jdom.setFileRoot(application.getRealPath("")); %&gt;
98 * &lt;/jsp:useBean&gt;
99 *
100 * or
101 *
102 * &lt;jsp:useBean id="jdom" class="JDOMBean" scope="application"&gt;
103 * &lt;jsp:setProperty name="jdom" property="fileRoot"
104 * +value='&lt;%=application.getRealPath("")%&gt;' /&gt;
105 * &lt;/jsp:useBean&gt;
106 *
107 * then
108 *
109 * &lt;%
110 * Element root = jdom.getRootElement("foo.xml");
111 * %&gt;
112 * Bar: &lt;%=root.getChild("bar").getContent()%&gt;
113 * </pre>
114 *
115 * @author Alex Chaffee [alex@jguru.com]
116 **/
117 @SuppressWarnings("javadoc")
118 public class JDOMBean {
119
120 /** Default SAX parser class to use */
121 private static final String DEFAULT_PARSER =
122 "org.apache.xerces.parsers.SAXParser";
123
124 /** SAX parser class to use */
125 private String parser;
126
127 /** <code>{@link SAXBuilder}</code> instance to use */
128 private SAXBuilder builder;
129
130 /** file cache **/
131 private Map<String, FileInfo> files = new HashMap<String, FileInfo>();
132
133 // /** where to locate files **/
134 // private File fileRoot;
135
136 /**
137 * default constructor, uses "org.apache.xerces.parsers.SAXParser"
138 **/
139 public JDOMBean() {
140 setParser(DEFAULT_PARSER);
141 }
142
143 /**
144 * @param parser <code>String</code> name of driver class to use.
145 **/
146 public JDOMBean(String parser) {
147 setParser(parser);
148 }
149
150 /**
151 * <p>
152 * This will create an instance of <code>{@link SAXBuilder}</code>
153 * for use in the rest of this program.
154 * </p>
155 *
156 * @param parser <code>String</code> name of SAX parser class to use.
157 */
158 public void setParser(String parser) {
159 this.parser = parser;
160 XMLReaderJDOMFactory fac = new XMLReaderSAX2Factory(false, parser);
161 builder = new SAXBuilder(fac);
162 }
163
164 /**
165 * @return name of SAX parser class being used
166 **/
167 public String getParser() {
168 return parser;
169 }
170
171 /**
172 * All files are fetched relative to this path
173 * @param root the path (absolute or relative) to the document root
174 **/
175 public void setFileRoot(String root) {
176 // if (!root.endsWith("/")) {
177 // root = root + "/";
178 // }
179 // this.fileRoot = new File(root);
180 // System.out.println("fileroot=" + fileRoot);
181 }
182
183 /**
184 * @return the path (absolute or relative) to the document root
185 **/
186 public String getFileRoot() {
187 // if (fileRoot == null) {
188 return null;
189 // }
190 // return fileRoot.getAbsolutePath();
191 }
192
193 /**
194 * Load a file, parse it with JDOM, return a org.jdom.Document.
195 * If the file has already been parsed, return the previously
196 * cached object. If the file has changed, ignore the previously
197 * parsed version and reload. <p>
198 *
199 * Note that this never unloads a document, so is unsuitable for
200 * long-term server-side use for a constantly changing set of
201 * files. Todo: use weak references or cache timeouts. <p>
202 *
203 * Also does not do secure checking on file requested, so if
204 * there's no root, and the parameter starts with a "/", this
205 * could conceivably access files you don't want accessed. So be
206 * careful out there.
207 *
208 * @param filename the file to load, relative to file root
209 * @return a JDOM Document corresponding to the given filename
210 **/
211 public Document getDocument(String filename) throws JDOMException, IOException {
212 FileInfo info = files.get(filename);
213 File file = getFile(filename);
214 if (info == null ||
215 info.modified < file.lastModified())
216 {
217 Document doc = builder.build(file);
218 info = new FileInfo(filename, file.lastModified(), doc);
219 files.put(filename, info);
220 }
221 return info.document;
222 }
223
224 /**
225 * Convenience method, calls getDocument(filename).getRootElement()
226 **/
227 public Element getRootElement(String file) throws JDOMException, IOException {
228 Document doc = getDocument(file);
229 if (doc != null) return doc.getRootElement();
230 return null;
231 }
232
233 private File getFile(String filename) {
234 // if (fileRoot == null) {
235 return new File(filename);
236 // }
237 // return new File(fileRoot, filename);
238 }
239
240 /**
241 * Information stored in the cache
242 **/
243 class FileInfo {
244 String name;
245 long modified;
246 Document document;
247 public FileInfo(String name, long modified, Document document) {
248 this.name = name;
249 this.modified = modified;
250 this.document = document;
251 }
252 }
253
254 // Usage: java JDOMBean [-parser com.foo.parser] file1.xml file2.xml
255 // Fetches and prints files
256 public static void main(String[] args) throws IOException, JDOMException {
257 int i=0;
258 JDOMBean bean;
259 if (args[i].equals("-parser")) {
260 ++i;
261 bean = new JDOMBean(args[i]);
262 i++;
263 }
264 else {
265 bean = new JDOMBean();
266 }
267
268 XMLOutputter2 out = new XMLOutputter2();
269
270 for (; i<args.length; ++i) {
271 Document doc = bean.getDocument(args[i]);
272 out.output(doc, System.out);
273 System.out.println();
274 }
275 }
276
277 }
278
0 Location for development of JDOM beans, esp ones for supporting JSP.
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.beans;
55
56 import java.lang.reflect.*;
57 import java.util.*;
58
59 /**
60 * Converts a String into a given object type.
61 *
62 * @author Alex Chaffee (alex@jguru.com)
63 **/
64
65 @SuppressWarnings("javadoc")
66 public class StringConverter {
67
68 public static interface Factory {
69 public Object instantiate(String string);
70 }
71
72 public static class DateFactory implements Factory
73 {
74 @Override
75 public Object instantiate(String string) {
76 return DateUtils.parseDate(string);
77 }
78 }
79
80 protected Map<Class<?>, Factory> factories = new HashMap<Class<?>, Factory>();
81
82 public StringConverter() {
83 try {
84 factories.put( Class.forName("java.util.Date"),
85 new DateFactory() );
86 }
87 catch (ClassNotFoundException e) {
88 // do nothing
89 }
90 }
91
92 public void setFactory(Class<?> type, Factory factory) {
93 factories.put(type, factory);
94 }
95
96 protected static Class<?>[] argString = new Class[] { String.class };
97
98 public Object parse(String string, Class<?> type)
99 {
100 // if it's a string, return it
101 if (type == String.class) {
102 return string;
103 }
104
105 // if we have a Factory for it
106 Factory factory = factories.get(type);
107 if (factory != null) {
108 return factory.instantiate(string);
109 }
110
111 // if it's a primitive, convert to wrapper (???)
112 if (type == short.class) type = Short.class;
113 if (type == int.class) type = Integer.class;
114 if (type == long.class) type = Long.class;
115 if (type == boolean.class) type = Boolean.class;
116 if (type == char.class) type = Character.class;
117 if (type == byte.class) type = Byte.class;
118
119 // last ditch: see if the class has a String Factory
120 try {
121 Constructor<?> c = type.getConstructor(argString);
122 if (c != null) {
123 return c.newInstance( new Object[] { string } );
124 }
125 }
126 catch (NoSuchMethodException e) {
127 // ignore & fall through
128 }
129 catch (Exception e) {
130 System.err.println("Couldn't instantiate " + type + "(" + string + ")");
131 e.printStackTrace();
132 }
133
134 return null;
135 }
136 }
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.beans;
55
56 import org.jdom.*;
57 import org.jdom.output.*;
58 import java.util.*;
59
60 @SuppressWarnings("javadoc")
61 public class TestBean implements java.io.Serializable {
62 /**
63 * Default.
64 */
65 private static final long serialVersionUID = 1L;
66
67 private String name;
68 private int age;
69 private Date birthdate;
70 private TestBean friend;
71
72 public String getName() {
73 return name;
74 }
75 public int getAge() {
76 return age;
77 }
78 public Date getBirthdate() {
79 return birthdate;
80 }
81 public TestBean getFriend() {
82 return friend;
83 }
84
85 public void setName(String name) {
86 this.name = name;
87 }
88 public void setAge(int age) {
89 this.age = age;
90 }
91 public void setBirthdate(Date birthdate) {
92 this.birthdate = birthdate;
93 }
94 public void setFriend(TestBean friend) {
95 this.friend = friend;
96 }
97
98 @Override
99 public String toString() {
100 return "TestBean[name='" + name + "', age=" + age + ", birthdate=" + birthdate + ", friend=" + friend + "]";
101 }
102
103
104 // Test
105
106 @SuppressWarnings("deprecation")
107 public static void main(String[] args) throws java.io.IOException {
108
109 try {
110 BeanMapper mapper = new BeanMapper();
111 mapper.addMapping("birthdate", "dob"); // element mapping
112 mapper.addMapping("age", "dob", "age"); // attribute mapping
113
114 mapper.setBeanPackage("org.jdom.contrib.beans");
115
116 // test bean->jdom
117
118 TestBean alex = new TestBean();
119 alex.setName("Alex");
120 alex.setAge(31);
121 alex.setBirthdate(new Date(69, 7, 8));
122
123 TestBean amy = new TestBean();
124 amy.setName("Amy");
125 amy.setAge(25);
126 amy.setBirthdate(new Date(75, 4, 1));
127
128 alex.setFriend(amy);
129
130 Document doc = mapper.toDocument(alex);
131 XMLOutputter2 o = new XMLOutputter2(Format.getPrettyFormat());
132 o.output(doc, System.out);
133 System.out.println();
134
135 // test jdom->bean
136 TestBean test2 = (TestBean)mapper.toBean(doc);
137 System.out.println(test2);
138 }
139 catch (BeanMapperException e) {
140 e.printStackTrace();
141 }
142 }
143
144 }
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.beans;
55
56 import org.jdom.*;
57 import org.jdom.output.*;
58 import java.util.*;
59 import java.beans.*;
60
61 @SuppressWarnings("javadoc")
62 public class TestIndexed implements java.io.Serializable {
63 /**
64 * Default.
65 */
66 private static final long serialVersionUID = 1L;
67
68 private String name;
69 private List<String> toppings = new ArrayList<String>();
70 private int[] measurements = new int[]{36, 24, 38};
71
72 public String getName() {
73 return name;
74 }
75
76 public void setName(String name) {
77 this.name = name;
78 }
79
80 public String getTopping(int i) {
81 return toppings.get(i);
82 }
83
84 public void setTopping(int i, String topping) {
85 while (i >= toppings.size()) {
86 toppings.add(null);
87 }
88 toppings.set(i, topping);
89 }
90
91 public String[] getTopping() {
92 String[] a = new String[toppings.size()];
93 for (int i = 0; i < toppings.size(); ++i) {
94 a[i] = toppings.get(i);
95 }
96 return a;
97 }
98
99 public void setTopping(String[] x) {
100 if (x != null)
101 toppings = Arrays.asList(x);
102 }
103
104 public int[] getMeasurements() {
105 return measurements;
106 }
107
108 public void setMeasurements(int[] measurements) {
109 this.measurements = measurements;
110 }
111
112 @Override
113 public String toString() {
114 StringBuilder buf = new StringBuilder();
115 buf.append("TestIndexed[name='" + name + "'");
116 for (int i = 0; i < toppings.size(); ++i) {
117 buf.append(", topping=" + toppings.get(i));
118 }
119 buf.append(", measurements=");
120 for (int i = 0; i < toppings.size(); ++i) {
121 buf.append(" " + measurements[i]);
122 }
123 buf.append("]");
124 return buf.toString();
125 }
126
127 public static void main(String[] args) throws java.beans.IntrospectionException, java.io.IOException, BeanMapperException {
128 BeanMapper mapper = new BeanMapper();
129 mapper.setBeanPackage("org.jdom.contrib.beans");
130
131 TestIndexed pizza = new TestIndexed();
132 pizza.setName("Abominable");
133 pizza.setTopping(0, "Anchovies");
134 pizza.setTopping(1, "Steak Tartare");
135 pizza.setTopping(2, "Raw Eggs");
136
137 BeanInfo info = Introspector.getBeanInfo(pizza.getClass());
138 PropertyDescriptor[] ps = info.getPropertyDescriptors();
139 for (int i = 0; i < ps.length; ++i) {
140 if (ps[i] instanceof IndexedPropertyDescriptor) {
141 IndexedPropertyDescriptor p = (IndexedPropertyDescriptor) ps[i];
142 System.out.println("Indexed property " + p.getName() + " " + p.getShortDescription());
143 System.out.println("Type = " + p.getPropertyType());
144 System.out.println("Getter = " + p.getReadMethod());
145 System.out.println("Indexed Getter = " + p.getIndexedReadMethod());
146 }
147 }
148
149 System.out.println("===== Testing toDocument()");
150 Document doc = mapper.toDocument(pizza);
151 XMLOutputter2 o = new XMLOutputter2(Format.getPrettyFormat());
152 o.output(doc, System.out);
153 System.out.println();
154
155 // test jdom->bean
156 System.out.println("===== Testing toBean()");
157 TestIndexed test2 = (TestIndexed) mapper.toBean(doc);
158 System.out.println(test2);
159
160 int[] test = new int[10];
161 Class<?> a1 = test.getClass();
162 Class<?> a2 = a1.getSuperclass();
163 System.out.println("classes: " + a1 + " " + a2);
164 }
165 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.Attr;
57 import org.w3c.dom.CDATASection;
58 import org.w3c.dom.Comment;
59 import org.w3c.dom.Document;
60 import org.w3c.dom.DocumentType;
61 import org.w3c.dom.Element;
62 import org.w3c.dom.EntityReference;
63 import org.w3c.dom.ProcessingInstruction;
64 import org.w3c.dom.Text;
65
66 import org.jdom.Content;
67
68 /**
69 * Access JDOM Content using a (Read-Only) DOM model
70 *
71 * @author Rolf Lear
72 *
73 */
74 public final class DOM {
75 /**
76 * Wrap a JDOM Document in a org.w3c.dom.Document instance.
77 * @param doc The JDOM Document to wrap.
78 * @return the wrapped Document
79 */
80 public static final Document wrap(final org.jdom.Document doc) {
81 return wrap(doc, false);
82 }
83
84 /**
85 * Wrap a JDOM Document in a org.w3c.dom.Document instance.
86 * @param doc The JDOM Document to wrap.
87 * @param scan Whether the entire document should be pre-processed
88 * @return the wrapped Document
89 */
90 public static final Document wrap(
91 final org.jdom.Document doc, final boolean scan) {
92 final JDocument ret = new JDocument(doc);
93 if (scan) {
94 ret.scanAll();
95 }
96 return ret;
97 }
98
99 private static final JDocument makeDoc(final Content c) {
100 final org.jdom.Document doc = c.getDocument();
101 return new JDocument(doc);
102 }
103
104 /**
105 * Wrap a JDOM Element in a org.w3c.dom.Element instance.
106 * @param emt The JDOM Element to wrap.
107 * @return the wrapped Element
108 */
109 public static final Element wrap(final org.jdom.Element emt) {
110 return makeDoc(emt).find(emt);
111 }
112
113
114 /**
115 * Wrap a JDOM Attribute in a org.w3c.dom.Attr instance.
116 * @param att The JDOM Attribute to wrap.
117 * @return the wrapped Attribute
118 */
119 public static final Attr wrap(final org.jdom.Attribute att) {
120 final org.jdom.Document doc = att.getDocument();
121 final JDocument jd = new JDocument(doc);
122 return jd.find(att);
123 }
124
125
126
127 /**
128 * Wrap a JDOM Text in a org.w3c.dom.Text instance.
129 * @param text The JDOM Text to wrap.
130 * @return the wrapped Text
131 */
132 public static final Text wrap(final org.jdom.Text text) {
133 return makeDoc(text).find(text);
134 }
135
136 /**
137 * Wrap a JDOM CDATA in a org.w3c.dom.CDATASection instance.
138 * @param cdata The JDOM CDATA to wrap.
139 * @return the wrapped CDATA
140 */
141 public static final CDATASection wrap(final org.jdom.CDATA cdata) {
142 return makeDoc(cdata).find(cdata);
143 }
144
145 /**
146 * Wrap a JDOM EntityRef in a org.w3c.dom.EntityReference instance.
147 * @param eref The JDOM EntityRef to wrap.
148 * @return the wrapped EtityRef
149 */
150 public static final EntityReference wrap(final org.jdom.EntityRef eref) {
151 return makeDoc(eref).find(eref);
152 }
153
154 /**
155 * Wrap a JDOM ProcessingInstruction in a org.w3c.dom.ProcessingInstruction
156 * instance.
157 * @param pi The JDOM ProcessingInstruction to wrap.
158 * @return the wrapped ProcessingInstrction
159 */
160 public static final ProcessingInstruction wrap(
161 final org.jdom.ProcessingInstruction pi) {
162 return makeDoc(pi).find(pi);
163 }
164
165 /**
166 * Wrap a JDOM Comment in a org.w3c.dom.Comment instance.
167 * @param comment The JDOM Comment to wrap.
168 * @return the wrapped Comment
169 */
170 public static final Comment wrap(final org.jdom.Comment comment) {
171 return makeDoc(comment).find(comment);
172 }
173
174 /**
175 * Wrap a JDOM DocType in a org.w3c.dom.DocumentType instance.
176 * @param dt The JDOM DocType to wrap.
177 * @return the wrapped DocType
178 */
179 public static final DocumentType wrap(final org.jdom.DocType dt) {
180 return makeDoc(dt).find(dt);
181 }
182
183 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import java.net.URISyntaxException;
57
58 import org.w3c.dom.Attr;
59 import org.w3c.dom.DOMException;
60 import org.w3c.dom.Element;
61 import org.w3c.dom.NamedNodeMap;
62 import org.w3c.dom.Node;
63 import org.w3c.dom.NodeList;
64 import org.w3c.dom.TypeInfo;
65
66 import org.jdom.Attribute;
67 import org.jdom.AttributeType;
68 import org.jdom.Namespace;
69
70 final class JAttribute extends JNamespaceAware implements Attr {
71
72 final Attribute attribute;
73 public JAttribute(final JDocument topdoc, final JParent parent, final Attribute attribute,
74 final Namespace[] nstack) {
75 super(topdoc, parent, Node.ATTRIBUTE_NODE, nstack);
76 this.attribute = attribute;
77 }
78
79 @Override
80 public final Object getWrapped() {
81 return attribute;
82 }
83
84 @Override
85 public String getNodeName() {
86 return getName();
87 }
88 @Override
89 public String getNodeValue() throws DOMException {
90 return getValue();
91 }
92 @Override
93 public NodeList getChildNodes() {
94 return EMPTYLIST;
95 }
96 @Override
97 public Node getFirstChild() {
98 return null;
99 }
100 @Override
101 public Node getLastChild() {
102 return null;
103 }
104 @Override
105 public NamedNodeMap getAttributes() {
106 return null;
107 }
108 @Override
109 public boolean hasChildNodes() {
110 return false;
111 }
112 @Override
113 public String getNamespaceURI() {
114 return attribute.getNamespaceURI();
115 }
116 @Override
117 public String getPrefix() {
118 return attribute.getNamespacePrefix();
119 }
120 @Override
121 public String getLocalName() {
122 return attribute.getName();
123 }
124 @Override
125 public boolean hasAttributes() {
126 return false;
127 }
128 @Override
129 public String getBaseURI() {
130 try {
131 return attribute.getParent().getXMLBaseURI().toASCIIString();
132 } catch (final URISyntaxException e) {
133 throw new IllegalStateException("Unable to process URI", e);
134 }
135 }
136 @Override
137 public String getTextContent() throws DOMException {
138 return "";
139 }
140 @Override
141 public String getName() {
142 return attribute.getQualifiedName();
143 }
144 @Override
145 public boolean getSpecified() {
146 return true;
147 }
148 @Override
149 public String getValue() {
150 return attribute.getValue();
151 }
152
153 @Override
154 public Element getOwnerElement() {
155 return (Element)getParentNode();
156 }
157
158 @Override
159 public TypeInfo getSchemaTypeInfo() {
160 return TYPEINFO;
161 }
162
163 @Override
164 public boolean isId() {
165 return attribute.getAttributeType() == AttributeType.ID;
166 }
167
168 @Override
169 public void setValue(final String value) throws DOMException {
170 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
171 "Cannot modify JDOM Wrapper DOM objects.");
172 }
173
174
175 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.CDATASection;
57
58 import org.jdom.Content;
59 import org.jdom.Namespace;
60
61 final class JCDATA extends JText implements CDATASection {
62 public JCDATA(final JDocument topdoc, final JParent parent,
63 final Content content, final Namespace[] nstack) {
64 super(topdoc, parent, content, nstack);
65 }
66
67 @Override
68 public String getNodeName() {
69 return "#cdata-section";
70 }
71
72 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.Comment;
57
58 import org.jdom.Content;
59 import org.jdom.Namespace;
60
61 final class JComment extends JSimpleCharacterContent implements Comment {
62
63 public JComment(final JDocument topdoc, final JParent parent, final Content content,
64 final Namespace[] nstack) {
65 super(topdoc, parent, content, nstack);
66 }
67
68 @Override
69 public String getNodeName() {
70 return "#comment";
71 }
72
73 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.NamedNodeMap;
57 import org.w3c.dom.Node;
58 import org.w3c.dom.NodeList;
59
60 import org.jdom.Content;
61 import org.jdom.Namespace;
62
63 abstract class JContent extends JNamespaceAware {
64
65 private static final short getNodeType(final Content content) {
66 switch (content.getCType()) {
67 case CDATA:
68 return Node.CDATA_SECTION_NODE;
69 case Comment:
70 return Node.COMMENT_NODE;
71 case DocType:
72 return Node.DOCUMENT_TYPE_NODE;
73 case Element:
74 throw new IllegalStateException("JElement does not extend JContent");
75 case EntityRef:
76 return Node.ENTITY_REFERENCE_NODE;
77 case ProcessingInstruction:
78 return Node.PROCESSING_INSTRUCTION_NODE;
79 case Text:
80 return Node.TEXT_NODE;
81 }
82 // this will never be run....
83 return -1;
84 }
85
86 protected final Content shadow;
87
88 public JContent(final JDocument topdoc, final JParent parent,
89 final Content content, final Namespace[] nstack) {
90 super(topdoc, parent, getNodeType(content), nstack);
91 this.shadow = content;
92 }
93
94 @Override
95 public final Object getWrapped() {
96 return shadow;
97 }
98
99 @Override
100 public final NodeList getChildNodes() {
101 return EMPTYLIST;
102 }
103
104 @Override
105 public final Node getFirstChild() {
106 return null;
107 }
108
109 @Override
110 public final Node getLastChild() {
111 return null;
112 }
113
114 @Override
115 public final boolean hasChildNodes() {
116 return false;
117 }
118
119 @Override
120 public final boolean hasAttributes() {
121 return false;
122 }
123
124 @Override
125 public final String getBaseURI() {
126 return parent.getBaseURI();
127 }
128
129 @Override
130 public final NamedNodeMap getAttributes() {
131 return null;
132 }
133
134 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.DOMConfiguration;
57 import org.w3c.dom.DOMException;
58 import org.w3c.dom.DOMStringList;
59
60 class JDOMConfiguration implements DOMConfiguration {
61
62 private static final DOMStringList EMPTYSTRINGS = new DOMStringList() {
63
64 @Override
65 public String item(final int index) {
66 return null;
67 }
68
69 @Override
70 public int getLength() {
71 return 0;
72 }
73
74 @Override
75 public boolean contains(final String str) {
76 return false;
77 }
78 };
79
80 @Override
81 public void setParameter(final String name, final Object value) throws DOMException {
82 throw new DOMException(DOMException.NOT_FOUND_ERR, "No configuration!");
83 }
84
85 @Override
86 public Object getParameter(final String name) throws DOMException {
87 return null;
88 }
89
90 @Override
91 public boolean canSetParameter(final String name, final Object value) {
92 return false;
93 }
94
95 @Override
96 public DOMStringList getParameterNames() {
97 return EMPTYSTRINGS;
98 }
99
100 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.DOMException;
57 import org.w3c.dom.DOMImplementation;
58 import org.w3c.dom.Document;
59 import org.w3c.dom.DocumentType;
60
61 class JDOMImplementation implements DOMImplementation {
62
63 @Override
64 public boolean hasFeature(final String feature, final String version) {
65 return false;
66 }
67
68 @Override
69 public DocumentType createDocumentType(final String qualifiedName,
70 final String publicId, final String systemId) throws DOMException {
71 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "JDOM Wrapper");
72 }
73
74 @Override
75 public Document createDocument(final String namespaceURI, final String qualifiedName,
76 final DocumentType doctype) throws DOMException {
77 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "JDOM Wrapper");
78 }
79
80 @Override
81 public Object getFeature(final String feature, final String version) {
82 return null;
83 }
84
85 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.DOMException;
57 import org.w3c.dom.DocumentType;
58 import org.w3c.dom.NamedNodeMap;
59
60 import org.jdom.Content;
61 import org.jdom.DocType;
62 import org.jdom.Namespace;
63
64 class JDocType extends JSimpleContent implements DocumentType {
65
66 public JDocType(final JDocument topdoc, final JParent parent, final Content content,
67 final Namespace[] nstack) {
68 super(topdoc, parent, content, nstack);
69 }
70
71 @Override
72 public String getNodeName() {
73 return getName();
74 }
75
76 @Override
77 public String getNodeValue() throws DOMException {
78 return null;
79 }
80
81 @Override
82 public String getTextContent() throws DOMException {
83 return null;
84 }
85
86 @Override
87 public String getName() {
88 return ((DocType)shadow).getElementName();
89 }
90
91 @Override
92 public NamedNodeMap getEntities() {
93 return EMPTYMAP;
94 }
95
96 @Override
97 public NamedNodeMap getNotations() {
98 return EMPTYMAP;
99 }
100
101 @Override
102 public String getPublicId() {
103 return ((DocType)shadow).getPublicID();
104 }
105
106 @Override
107 public String getSystemId() {
108 return ((DocType)shadow).getSystemID();
109 }
110
111 @Override
112 public String getInternalSubset() {
113 return ((DocType)shadow).getInternalSubset();
114 }
115
116 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import java.util.ArrayList;
57 import java.util.HashMap;
58 import java.util.IdentityHashMap;
59 import java.util.Iterator;
60
61 import org.w3c.dom.Attr;
62 import org.w3c.dom.CDATASection;
63 import org.w3c.dom.Comment;
64 import org.w3c.dom.DOMConfiguration;
65 import org.w3c.dom.DOMException;
66 import org.w3c.dom.DOMImplementation;
67 import org.w3c.dom.Document;
68 import org.w3c.dom.DocumentFragment;
69 import org.w3c.dom.DocumentType;
70 import org.w3c.dom.Element;
71 import org.w3c.dom.EntityReference;
72 import org.w3c.dom.NamedNodeMap;
73 import org.w3c.dom.Node;
74 import org.w3c.dom.NodeList;
75 import org.w3c.dom.ProcessingInstruction;
76 import org.w3c.dom.Text;
77
78 import org.jdom.Attribute;
79 import org.jdom.AttributeType;
80 import org.jdom.CDATA;
81 import org.jdom.DocType;
82 import org.jdom.EntityRef;
83 import org.jdom.Namespace;
84 import org.jdom.Parent;
85 import org.jdom.filter.Filters;
86 import org.jdom.util.NamespaceStack;
87
88 class JDocument extends JParent implements Document {
89
90 private static final JDOMImplementation implementation =
91 new JDOMImplementation();
92
93 private static final JDOMConfiguration configuration =
94 new JDOMConfiguration();
95
96 private boolean allscanned = false;
97 private final JElement root;
98 private final JDocType doctype;
99 private final IdentityHashMap<Object, JNamespaceAware> mapped =
100 new IdentityHashMap<Object, JNamespaceAware>();
101 private final HashMap<String, JElement> idmap = new HashMap<String, JElement>();
102
103 public JDocument(final org.jdom.Document shadow) {
104 super(null, null, shadow, Node.DOCUMENT_NODE, new Namespace[]{
105 Namespace.NO_NAMESPACE,
106 Namespace.XML_NAMESPACE
107 });
108 if (shadow == null) {
109 root = null;
110 doctype = null;
111 } else {
112 final JNamespaceAware[] kids = checkKids();
113 JDocType dt = null;
114 JElement je = null;
115 for (final JNamespaceAware n : kids) {
116 if (n.getNodeType() == Node.DOCUMENT_TYPE_NODE) {
117 dt = (JDocType)n;
118 }
119 if (n.getNodeType() == Node.ELEMENT_NODE) {
120 je = (JElement)n;
121 }
122 }
123 root = je;
124 doctype = dt;
125 }
126 }
127
128 public void scanAll() {
129 if (allscanned) {
130 return;
131 }
132 if (shadow == null) {
133 allscanned = true;
134 return;
135 }
136 allscanned = true;
137 final Iterator<org.jdom.Element> it = shadow.getDescendants(Filters.element());
138 while (it.hasNext()) {
139 find(it.next());
140 }
141 }
142
143 public JElement find(final org.jdom.Element emt) {
144 final JNamespaceAware me = mapped.get(emt);
145 if (me != null) {
146 return (JElement)me;
147 }
148 final org.jdom.Element jp = emt.getParentElement();
149 if (jp == null) {
150 // root level element (or detached).
151 final org.jdom.Document jd = emt.getDocument();
152 // both may be null....
153 if (jd != shadow) {
154 // we are from different documents...
155 throw new DOMException(DOMException.WRONG_DOCUMENT_ERR,
156 "Element is not part of our document");
157 }
158 // OK, we are a root level Element... let's map ourselves.
159 final NamespaceStack ns = new NamespaceStack(scope);
160 ns.push(emt);
161 final ArrayList<Namespace> added = new ArrayList<Namespace>();
162 for (final Namespace ans : ns.addedForward()) {
163 added.add(ans);
164 }
165 final JElement je = new JElement(this, this, emt, ns.getScope(),
166 added.toArray(new Namespace[added.size()]));
167 mapped.put(emt, je);
168 checkID(je);
169 return je;
170 }
171 final JElement pnt = find(jp);
172 final NamespaceStack ns = new NamespaceStack(pnt.scope);
173 ns.push(emt);
174 final ArrayList<Namespace> added = new ArrayList<Namespace>();
175 for (final Namespace ans : ns.addedForward()) {
176 added.add(ans);
177 }
178 final JElement ret = new JElement(this, pnt, emt, ns.getScope(),
179 added.toArray(new Namespace[added.size()]));
180 mapped.put(emt, ret);
181 checkID(ret);
182 return ret;
183 }
184
185 public JAttribute find(final org.jdom.Attribute att) {
186 final JNamespaceAware me = mapped.get(att);
187 if (me != null) {
188 return (JAttribute)me;
189 }
190 final org.jdom.Element jp = att.getParent();
191 final JParent pnt = jp == null ? this : find(jp);
192 final NamespaceStack ns = jp == null ?
193 new NamespaceStack() : new NamespaceStack(find(jp).scope);
194 ns.push(att);
195 final JAttribute ret = new JAttribute(this, pnt, att, ns.getScope());
196 mapped.put(att, ret);
197 return ret;
198 }
199
200 private JContent findContent(final org.jdom.Content content) {
201 final JNamespaceAware me = mapped.get(content);
202 if (me != null) {
203 return (JContent)me;
204 }
205 final org.jdom.Element jp = content.getParentElement();
206 final JParent pnt = jp == null ? this : find(jp);
207 JContent ret = null;
208 switch (content.getCType()) {
209 case CDATA:
210 ret = new JCDATA(this, pnt, content, pnt.scope);
211 break;
212 case Comment:
213 ret = new JComment(this, pnt, content, pnt.scope);
214 break;
215 case DocType:
216 ret = new JDocType(this, pnt, content, pnt.scope);
217 break;
218 case EntityRef:
219 ret = new JEntityRef(this, pnt, content, pnt.scope);
220 break;
221 case ProcessingInstruction:
222 ret = new JProcessingInstruction(this, pnt, content, pnt.scope);
223 break;
224 case Text:
225 ret = new JText(this, pnt, content, pnt.scope);
226 break;
227 default:
228 throw new IllegalStateException(
229 "Other types should have their own methods.");
230 }
231 mapped.put(content, ret);
232 return ret;
233 }
234
235 public JCDATA find(final CDATA content) {
236 return (JCDATA)findContent(content);
237 }
238
239 public JDocType find(final DocType content) {
240 return (JDocType)findContent(content);
241 }
242
243 public JProcessingInstruction find(
244 final org.jdom.ProcessingInstruction content) {
245 return (JProcessingInstruction)findContent(content);
246 }
247
248 public JEntityRef find(final EntityRef content) {
249 return (JEntityRef)findContent(content);
250 }
251
252 public JComment find(final org.jdom.Comment content) {
253 return (JComment)findContent(content);
254 }
255
256 public JText find(final org.jdom.Text content) {
257 return (JText)findContent(content);
258 }
259
260 private void checkID(final JElement je) {
261 final org.jdom.Element emt = (org.jdom.Element)(je.shadow);
262 if (emt.hasAttributes()) {
263 for (final Attribute a : emt.getAttributes()) {
264 if (a.getAttributeType() == AttributeType.ID) {
265 if (idmap.put(a.getValue(), je) != null) {
266 throw new DOMException(DOMException.INVALID_STATE_ERR,
267 "Multiple elements with id " + a.getValue());
268 }
269 }
270 }
271 }
272 }
273
274 @Override
275 public DocumentType getDoctype() {
276 return doctype;
277 }
278
279 @Override
280 public Element getDocumentElement() {
281 return root;
282 }
283
284
285
286 @Override
287 public NodeList getElementsByTagName(final String tagname) {
288 return getElementsByTagName(shadow, tagname);
289 }
290
291 @Override
292 public NodeList getElementsByTagNameNS(final String namespaceURI, final String localName) {
293 return getElementsByTagNameNS(shadow, namespaceURI, localName);
294 }
295
296 NodeList getElementsByTagName(final Parent xshadow, final String tagname) {
297 if (tagname == null) {
298 return EMPTYLIST;
299 }
300 final ArrayList<JElement> enodes = new ArrayList<JElement>();
301 final boolean alltags = "*".equals(tagname);
302
303 final Iterator<org.jdom.Element> it =
304 xshadow.getDescendants(Filters.element());
305
306 while (it.hasNext()) {
307 final org.jdom.Element e = it.next();
308 if (alltags || tagname.equals(e.getQualifiedName())) {
309 enodes.add(find(e));
310 }
311 }
312
313 return new JNodeList(enodes);
314 }
315
316 NodeList getElementsByTagNameNS(final Parent xshadow, final String namespaceURI, final String localName) {
317 if (localName == null) {
318 return EMPTYLIST;
319 }
320 if (namespaceURI == null) {
321 return EMPTYLIST;
322 }
323
324 final boolean alluri = "*".equals(namespaceURI);
325 final boolean allname = "*".equals(localName);
326
327 final ArrayList<JElement> enodes = new ArrayList<JElement>();
328
329 final Iterator<org.jdom.Element> it =
330 xshadow.getDescendants(Filters.element());
331
332 while (it.hasNext()) {
333 final org.jdom.Element e = it.next();
334 if ((allname || localName.equals(e.getName())) &&
335 (alluri || namespaceURI.equals(e.getNamespaceURI()))) {
336 enodes.add(find(e));
337 }
338 }
339
340 return new JNodeList(enodes);
341 }
342
343 @Override
344 public Element getElementById(final String elementId) {
345 scanAll();
346 return idmap.get(elementId);
347 }
348
349 @Override
350 public String getDocumentURI() {
351 return shadow == null ? null : ((org.jdom.Document)shadow).getBaseURI();
352 }
353
354 @Override
355 public String getNodeName() {
356 return "#document";
357 }
358
359 @Override
360 public String getBaseURI() {
361 return shadow == null ? null : ((org.jdom.Document)shadow).getBaseURI();
362 }
363
364 /* *********************************************************
365 * Everything after this point is 'dumb' code... (or error code)
366 * ********************************************************* */
367
368 @Override
369 public String getNodeValue() throws DOMException {
370 return null;
371 }
372
373 @Override
374 public NamedNodeMap getAttributes() {
375 return null;
376 }
377
378 @Override
379 public String getNamespaceURI() {
380 return null;
381 }
382
383 @Override
384 public String getPrefix() {
385 return null;
386 }
387
388 @Override
389 public String getLocalName() {
390 return null;
391 }
392
393 @Override
394 public boolean hasAttributes() {
395 return false;
396 }
397
398 @Override
399 public String getTextContent() throws DOMException {
400 return null;
401 }
402
403 @Override
404 public String getXmlVersion() {
405 return "1.0";
406 }
407
408 @Override
409 public String getInputEncoding() {
410 return null;
411 }
412
413 @Override
414 public String getXmlEncoding() {
415 return null;
416 }
417
418 @Override
419 public boolean getXmlStandalone() {
420 return false;
421 }
422
423 @Override
424 public final DOMImplementation getImplementation() {
425 return implementation;
426 }
427
428 @Override
429 public final DOMConfiguration getDomConfig() {
430 return configuration;
431 }
432
433 @Override
434 public final boolean getStrictErrorChecking() {
435 return false;
436 }
437
438 @Override
439 public final void setStrictErrorChecking(final boolean strictErrorChecking) {
440 // nothing
441 }
442
443 @Override
444 public final void setDocumentURI(final String documentURI) {
445 // Do nothing
446 }
447
448 @Override
449 public final void normalizeDocument() {
450 // do nothing
451 }
452
453 @Override
454 public final Node renameNode(final Node n, final String namespaceURI, final String qualifiedName)
455 throws DOMException {
456 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
457 "Cannot modify JDOM Wrapper DOM objects.");
458 }
459
460 @Override
461 public final void setXmlStandalone(final boolean xmlStandalone) throws DOMException {
462 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
463 "Cannot modify JDOM Wrapper DOM objects.");
464 }
465
466 @Override
467 public final void setXmlVersion(final String xmlVersion) throws DOMException {
468 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
469 "Cannot modify JDOM Wrapper DOM objects.");
470 }
471
472 @Override
473 public final Node adoptNode(final Node source) throws DOMException {
474 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
475 "Cannot modify JDOM Wrapper DOM objects.");
476 }
477
478 @Override
479 public final Element createElement(final String tagName) throws DOMException {
480 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
481 "Cannot modify JDOM Wrapper DOM objects.");
482 }
483
484 @Override
485 public final DocumentFragment createDocumentFragment() {
486 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
487 "Cannot modify JDOM Wrapper DOM objects.");
488 }
489
490 @Override
491 public final Text createTextNode(final String data) {
492 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
493 "Cannot modify JDOM Wrapper DOM objects.");
494 }
495
496 @Override
497 public final Comment createComment(final String data) {
498 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
499 "Cannot modify JDOM Wrapper DOM objects.");
500 }
501
502 @Override
503 public final CDATASection createCDATASection(final String data) throws DOMException {
504 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
505 "Cannot modify JDOM Wrapper DOM objects.");
506 }
507
508 @Override
509 public final ProcessingInstruction createProcessingInstruction(final String target,
510 final String data) throws DOMException {
511 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
512 "Cannot modify JDOM Wrapper DOM objects.");
513 }
514
515 @Override
516 public final Attr createAttribute(final String name) throws DOMException {
517 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
518 "Cannot modify JDOM Wrapper DOM objects.");
519 }
520
521 @Override
522 public final EntityReference createEntityReference(final String name)
523 throws DOMException {
524 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
525 "Cannot modify JDOM Wrapper DOM objects.");
526 }
527
528 @Override
529 public final Node importNode(final Node importedNode, final boolean deep) throws DOMException {
530 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
531 "Cannot modify JDOM Wrapper DOM objects.");
532 }
533
534 @Override
535 public final Element createElementNS(final String namespaceURI, final String qualifiedName)
536 throws DOMException {
537 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
538 "Cannot modify JDOM Wrapper DOM objects.");
539 }
540
541 @Override
542 public final Attr createAttributeNS(final String namespaceURI, final String qualifiedName)
543 throws DOMException {
544 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
545 "Cannot modify JDOM Wrapper DOM objects.");
546 }
547
548 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import java.net.URISyntaxException;
57 import java.util.Iterator;
58 import java.util.List;
59
60 import org.jdom.filter2.AbstractFilter;
61 import org.w3c.dom.Attr;
62 import org.w3c.dom.DOMException;
63 import org.w3c.dom.Element;
64 import org.w3c.dom.NamedNodeMap;
65 import org.w3c.dom.Node;
66 import org.w3c.dom.NodeList;
67 import org.w3c.dom.TypeInfo;
68
69 import org.jdom.Attribute;
70 import org.jdom.Namespace;
71 import org.jdom.Parent;
72 import org.jdom.filter2.Filters;
73
74 class JElement extends JParent implements Element {
75
76 private final class AttMap implements NamedNodeMap {
77
78 private final Attr[] atts;
79
80 public AttMap(final Attr[] atts) {
81 super();
82 this.atts = atts;
83 }
84
85 @Override
86 public Node item(final int index) {
87 if (index < 0 || index >= atts.length) {
88 return null;
89 }
90 return atts[index];
91 }
92
93 @Override
94 public Node getNamedItemNS(final String namespaceURI, final String localName)
95 throws DOMException {
96 if (namespaceURI == null || localName == null) {
97 return null;
98 }
99 for (int i = 0; i < atts.length; i++) {
100 if (namespaceURI.equals(atts[i].getNamespaceURI()) &&
101 localName.equals(atts[i].getLocalName())) {
102 return atts[i];
103 }
104 }
105 return null;
106 }
107
108 @Override
109 public Node getNamedItem(final String name) {
110 if (name == null) {
111 return null;
112 }
113 for (int i = 0; i < atts.length; i++) {
114 if (name.equals(atts[i].getName())) {
115 return atts[i];
116 }
117 }
118 return null;
119 }
120
121 @Override
122 public int getLength() {
123 return atts.length;
124 }
125
126 @Override
127 public Node setNamedItemNS(final Node arg) throws DOMException {
128 throw new DOMException(
129 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
130 }
131
132 @Override
133 public Node setNamedItem(final Node arg) throws DOMException {
134 throw new DOMException(
135 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
136 }
137
138 @Override
139 public Node removeNamedItemNS(final String namespaceURI, final String localName)
140 throws DOMException {
141 throw new DOMException(
142 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
143 }
144
145 @Override
146 public Node removeNamedItem(final String name) throws DOMException {
147 throw new DOMException(
148 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
149 }
150
151 }
152
153 private NamedNodeMap attmap = null;
154 private final Namespace[] nsdec;
155
156 public JElement(final JDocument topdoc, final JParent parent,
157 final Parent shadow, final Namespace[] nstack,
158 final Namespace[] ndec) {
159 super(topdoc, parent, shadow, Node.ELEMENT_NODE, nstack);
160 this. nsdec = ndec;
161 }
162
163 @Override
164 public final String getNodeName() {
165 return getTagName();
166 }
167
168 @Override
169 public final String getNodeValue() throws DOMException {
170 return null;
171 }
172
173 @Override
174 public final NamedNodeMap getAttributes() {
175 if (attmap == null) {
176 final org.jdom.Element emt = (org.jdom.Element)shadow;
177 if (emt.hasAttributes() || nsdec.length > 0) {
178 final List<Attribute> list = emt.getAttributes();
179 final int sz = list.size();
180 final Attr[] ja = new Attr[sz + nsdec.length];
181 for (int i = 0; i < nsdec.length; i++) {
182 ja[i] = new JNamespace(topdoc, this, nsdec[i], scope);
183 }
184 for (int i = 0; i < sz; i++) {
185 ja[nsdec.length + i] = topdoc.find(list.get(i));
186 }
187 attmap = new AttMap(ja);
188 } else {
189 attmap = EMPTYMAP;
190 }
191 }
192 return attmap;
193 }
194
195 @Override
196 public final String getNamespaceURI() {
197 return ((org.jdom.Element)shadow).getNamespaceURI();
198 }
199
200 @Override
201 public final String getPrefix() {
202 return ((org.jdom.Element)shadow).getNamespacePrefix();
203 }
204
205 @Override
206 public final String getLocalName() {
207 return ((org.jdom.Element)shadow).getName();
208 }
209
210 @Override
211 public final String getBaseURI() {
212 try {
213 return ((org.jdom.Element)shadow).getXMLBaseURI().toASCIIString();
214 } catch (final URISyntaxException e) {
215 throw new IllegalStateException("Broken base URI references.", e);
216 }
217 }
218
219 @Override
220 public String getTextContent() throws DOMException {
221 final Iterator<org.jdom.Text> it = ((org.jdom.Element)shadow).
222 getDescendants(AbstractFilter.toFilter(Filters.fclass(org.jdom.Text.class)));
223 final StringBuilder sb = new StringBuilder();
224 while (it.hasNext()) {
225 sb.append(it.next().getText());
226 }
227 return sb.toString();
228 }
229
230 @Override
231 public String getTagName() {
232 return ((org.jdom.Element)shadow).getQualifiedName();
233 }
234
235 @Override
236 public TypeInfo getSchemaTypeInfo() {
237 // TODO Auto-generated method stub
238 return null;
239 }
240
241 @Override
242 public NodeList getElementsByTagName(final String tagname) {
243 return topdoc.getElementsByTagName(shadow, tagname);
244 }
245
246 @Override
247 public NodeList getElementsByTagNameNS(final String namespaceURI, final String localName) {
248 return topdoc.getElementsByTagNameNS(shadow, namespaceURI, localName);
249 }
250
251
252 /* ********************************************************
253 * Attribute Access methods below
254 * ******************************************************** */
255
256 @Override
257 public final boolean hasAttributes() {
258 return ((org.jdom.Element)shadow).hasAttributes();
259 }
260
261 @Override
262 public boolean hasAttribute(final String name) {
263 final Attribute att = ((org.jdom.Element)shadow).getAttribute(name);
264 return att != null;
265 }
266
267 @Override
268 public boolean hasAttributeNS(final String namespaceURI, final String localName)
269 throws DOMException {
270 final Attribute att =
271 ((org.jdom.Element)shadow).getAttribute(
272 localName, Namespace.getNamespace(namespaceURI));
273 return att != null;
274 }
275
276 @Override
277 public String getAttribute(final String name) {
278 final Attribute att = ((org.jdom.Element)shadow).getAttribute(name);
279 return att == null ? "" : att.getValue();
280 }
281
282 @Override
283 public String getAttributeNS(final String namespaceURI, final String localName)
284 throws DOMException {
285 final Attribute att =
286 ((org.jdom.Element)shadow).getAttribute(
287 localName, Namespace.getNamespace(namespaceURI));
288 return att == null ? "" : att.getValue();
289 }
290
291 @Override
292 public Attr getAttributeNode(final String name) {
293 return (Attr)getAttributes().getNamedItem(name);
294 }
295
296 @Override
297 public Attr getAttributeNodeNS(final String namespaceURI, final String localName)
298 throws DOMException {
299 return (Attr)getAttributes().getNamedItemNS(namespaceURI, localName);
300 }
301
302 /* ********************************************************
303 * Illegal modification methods below.
304 * ******************************************************** */
305
306 @Override
307 public Attr setAttributeNodeNS(final Attr newAttr) throws DOMException {
308 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
309 "Cannot modify JDOM Wrapper DOM objects.");
310 }
311
312 @Override
313 public void setIdAttribute(final String name, final boolean isId) throws DOMException {
314 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
315 "Cannot modify JDOM Wrapper DOM objects.");
316 }
317
318 @Override
319 public void setIdAttributeNS(final String namespaceURI, final String localName,
320 final boolean isId) throws DOMException {
321 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
322 "Cannot modify JDOM Wrapper DOM objects.");
323 }
324
325 @Override
326 public void setIdAttributeNode(final Attr idAttr, final boolean isId)
327 throws DOMException {
328 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
329 "Cannot modify JDOM Wrapper DOM objects.");
330 }
331
332 @Override
333 public void setAttributeNS(final String namespaceURI, final String qualifiedName,
334 final String value) throws DOMException {
335 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
336 "Cannot modify JDOM Wrapper DOM objects.");
337 }
338
339 @Override
340 public void removeAttributeNS(final String namespaceURI, final String localName)
341 throws DOMException {
342 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
343 "Cannot modify JDOM Wrapper DOM objects.");
344 }
345
346 @Override
347 public Attr setAttributeNode(final Attr newAttr) throws DOMException {
348 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
349 "Cannot modify JDOM Wrapper DOM objects.");
350 }
351
352 @Override
353 public void setAttribute(final String name, final String value) throws DOMException {
354 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
355 "Cannot modify JDOM Wrapper DOM objects.");
356 }
357
358 @Override
359 public void removeAttribute(final String name) throws DOMException {
360 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
361 "Cannot modify JDOM Wrapper DOM objects.");
362 }
363
364 @Override
365 public Attr removeAttributeNode(final Attr oldAttr) throws DOMException {
366 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
367 "Cannot modify JDOM Wrapper DOM objects.");
368 }
369
370 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.DOMException;
57 import org.w3c.dom.EntityReference;
58
59 import org.jdom.Content;
60 import org.jdom.EntityRef;
61 import org.jdom.Namespace;
62
63 class JEntityRef extends JSimpleContent implements EntityReference {
64
65 public JEntityRef(final JDocument topdoc, final JParent parent, final Content content,
66 final Namespace[] nstack) {
67 super(topdoc, parent, content, nstack);
68 }
69
70 @Override
71 public String getNodeName() {
72 return ((EntityRef)shadow).getName();
73 }
74
75 @Override
76 public String getNodeValue() throws DOMException {
77 return null;
78 }
79
80 @Override
81 public String getTextContent() throws DOMException {
82 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
83 "Cannot modify JDOM Wrapper DOM objects.");
84 }
85
86 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.Attr;
57 import org.w3c.dom.DOMException;
58 import org.w3c.dom.Element;
59 import org.w3c.dom.NamedNodeMap;
60 import org.w3c.dom.Node;
61 import org.w3c.dom.NodeList;
62 import org.w3c.dom.TypeInfo;
63
64 import org.jdom.JDOMConstants;
65 import org.jdom.Namespace;
66
67 final class JNamespace extends JNamespaceAware implements Attr {
68
69 final Namespace ns;
70 public JNamespace(final JDocument topdoc, final JElement parent, final Namespace namespace,
71 final Namespace[] nstack) {
72 super(topdoc, parent, Node.ATTRIBUTE_NODE, nstack);
73 this.ns = namespace;
74 }
75
76 @Override
77 public final Object getWrapped() {
78 return ns;
79 }
80
81 @Override
82 public String getNodeName() {
83 return getName();
84 }
85 @Override
86 public String getNodeValue() throws DOMException {
87 return getValue();
88 }
89 @Override
90 public NodeList getChildNodes() {
91 return EMPTYLIST;
92 }
93 @Override
94 public Node getFirstChild() {
95 return null;
96 }
97 @Override
98 public Node getLastChild() {
99 return null;
100 }
101 @Override
102 public NamedNodeMap getAttributes() {
103 return null;
104 }
105 @Override
106 public boolean hasChildNodes() {
107 return false;
108 }
109 @Override
110 public String getNamespaceURI() {
111 return "".equals(ns.getPrefix()) ? "" : JDOMConstants.NS_URI_XMLNS;
112 }
113 @Override
114 public String getPrefix() {
115 return "".equals(ns.getPrefix()) ? "" : JDOMConstants.NS_PREFIX_XMLNS;
116 }
117 @Override
118 public String getLocalName() {
119 return "".equals(ns.getPrefix()) ? JDOMConstants.NS_PREFIX_XMLNS : ns.getPrefix();
120 }
121 @Override
122 public boolean hasAttributes() {
123 return false;
124 }
125 @Override
126 public String getBaseURI() {
127 return parent.getBaseURI();
128 }
129 @Override
130 public String getTextContent() throws DOMException {
131 return "";
132 }
133 @Override
134 public String getName() {
135 return "".equals(ns.getPrefix()) ? ns.getPrefix() : (JDOMConstants.NS_PREFIX_XMLNS + ":" + ns.getPrefix());
136 }
137 @Override
138 public boolean getSpecified() {
139 return true;
140 }
141 @Override
142 public String getValue() {
143 return ns.getURI();
144 }
145
146 @Override
147 public Element getOwnerElement() {
148 return (Element)getParentNode();
149 }
150
151 @Override
152 public TypeInfo getSchemaTypeInfo() {
153 return TYPEINFO;
154 }
155
156 @Override
157 public boolean isId() {
158 return false;
159 }
160
161 @Override
162 public void setValue(final String value) throws DOMException {
163 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
164 "Cannot modify JDOM Wrapper DOM objects.");
165 }
166
167
168 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.jdom.Namespace;
57
58 abstract class JNamespaceAware extends JNode {
59
60 protected final Namespace[] scope;
61
62 public JNamespaceAware(final JDocument topdoc, final JParent parent,
63 final short nodetype, final Namespace[] nstack) {
64 super(topdoc, parent, nodetype);
65 scope = nstack;
66 }
67
68 @Override
69 public final String lookupPrefix(final String namespaceURI) {
70 for (int i = 0; i < scope.length; i++) {
71 if (scope[i].getURI().equals(namespaceURI)) {
72 return scope[i].getPrefix();
73 }
74 }
75 return null;
76 }
77
78 @Override
79 public final boolean isDefaultNamespace(final String namespaceURI) {
80 for (int i = 0; i < scope.length; i++) {
81 if (scope[i].getURI().equals(namespaceURI) && "".equals(scope[i].getPrefix())) {
82 return true;
83 }
84 }
85 return false;
86 }
87
88 @Override
89 public final String lookupNamespaceURI(final String prefix) {
90 for (int i = 0; i < scope.length; i++) {
91 if (scope[i].getPrefix().equals(prefix)) {
92 return scope[i].getURI();
93 }
94 }
95 return null;
96 }
97
98
99 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import java.util.ArrayList;
57 import java.util.HashMap;
58
59 import org.w3c.dom.DOMException;
60 import org.w3c.dom.Document;
61 import org.w3c.dom.NamedNodeMap;
62 import org.w3c.dom.Node;
63 import org.w3c.dom.NodeList;
64 import org.w3c.dom.TypeInfo;
65 import org.w3c.dom.UserDataHandler;
66
67 abstract class JNode implements Node, Wrapper {
68
69 protected static final TypeInfo TYPEINFO = new TypeInfo() {
70 @Override
71 public boolean isDerivedFrom(final String typeNamespaceArg, final String typeNameArg,
72 final int derivationMethod) {
73 return false;
74 }
75
76 @Override
77 public String getTypeNamespace() {
78 return "http://www.w3.org/TR/REC-xml";
79 }
80
81 @Override
82 public String getTypeName() {
83 return null;
84 }
85 };
86
87
88
89 protected static final NodeList EMPTYLIST = new NodeList() {
90 @Override
91 public Node item(final int index) {
92 return null;
93 }
94 @Override
95 public int getLength() {
96 return 0;
97 }
98 };
99
100 protected static final NamedNodeMap EMPTYMAP = new NamedNodeMap() {
101
102 @Override
103 public Node setNamedItemNS(final Node arg) throws DOMException {
104 throw new DOMException(
105 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
106 }
107
108 @Override
109 public Node setNamedItem(final Node arg) throws DOMException {
110 throw new DOMException(
111 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
112 }
113
114 @Override
115 public Node removeNamedItemNS(final String namespaceURI, final String localName)
116 throws DOMException {
117 throw new DOMException(
118 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
119 }
120
121 @Override
122 public Node removeNamedItem(final String name) throws DOMException {
123 throw new DOMException(
124 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
125 }
126
127 @Override
128 public Node item(final int index) {
129 return null;
130 }
131
132 @Override
133 public Node getNamedItemNS(final String namespaceURI, final String localName)
134 throws DOMException {
135 return null;
136 }
137
138 @Override
139 public Node getNamedItem(final String name) {
140 return null;
141 }
142
143 @Override
144 public int getLength() {
145 return 0;
146 }
147 };
148
149 private final short nodetype;
150 protected final JDocument topdoc;
151 protected final JParent parent;
152
153 private HashMap<String, Object> userdata;
154
155 JNode(final JDocument topdoc, final JParent parent, final short nodetype) {
156 // the rule is that only JDocument constructor can pass a null topdoc.
157 this.topdoc = topdoc == null ? (JDocument)this : topdoc;
158 this.nodetype = nodetype;
159 this.parent = parent;
160 }
161
162 /**
163 * Attribute, Document, and Element need to override this.
164 * @param other will be another node of the same type that needs to be
165 * compared.
166 * @return true if the rules match the Node.isEqualsNode() method.
167 */
168 protected boolean detailEquals(final JNode other) {
169 return true;
170 }
171
172 /* ****************************************************
173 * Below this all methods are final...
174 * **************************************************** */
175
176 @Override
177 public final Node getPreviousSibling() {
178 if (parent == null) {
179 return null;
180 }
181 return parent.getPreviousSibling(this);
182 }
183
184 @Override
185 public final Node getNextSibling() {
186 if (parent == null) {
187 return null;
188 }
189 return parent.getNextSibling(this);
190 }
191
192
193
194
195 @Override
196 public final Object setUserData(final String key, final Object data, final UserDataHandler handler) {
197 // since the node can never be adopted or cloned, the handler
198 // events can never be called, thus we do not need to track the handler.
199 if (userdata == null) {
200 userdata = new HashMap<String, Object>();
201 }
202 return userdata.put(key, data);
203 }
204
205 @Override
206 public final Object getUserData(final String key) {
207 if (userdata == null) {
208 return null;
209 }
210 return userdata.get(key);
211 }
212
213 @Override
214 public final Object getFeature(final String feature, final String version) {
215 return null;
216 }
217
218 @Override
219 public final Node getParentNode() {
220 return parent;
221 }
222
223 @Override
224 public final short getNodeType() {
225 return nodetype;
226 }
227
228 @Override
229 public final Document getOwnerDocument() {
230 return topdoc;
231 }
232
233 @Override
234 public final short compareDocumentPosition(final Node other) throws DOMException {
235 if ((other instanceof JNode)) {
236 JNode their = (JNode)other;
237 if (their == this) {
238 return 0;
239 }
240 if (their.topdoc == topdoc) {
241 // same document....
242 final ArrayList<JNode> ancestry = new ArrayList<JNode>();
243 ancestry.add(their);
244 JNode p = their.parent;
245 while (p != null) {
246 if (p == this) {
247 // we contain the other node.
248 return DOCUMENT_POSITION_CONTAINED_BY | DOCUMENT_POSITION_FOLLOWING;
249 }
250 ancestry.add(p);
251 p = p.parent;
252 }
253 // OK, we have the ancestry.... but, we are not on the direct ancestry of that node.
254 // let's find an intersection of our ancestry...
255 p = this.parent;
256 JNode k = this;
257 final int alen = ancestry.size();
258 while (p != null) {
259 for (int apos = 0; apos < alen; apos++) {
260 if (p == ancestry.get(apos)) {
261 // we have intersected...
262 final int sibpos = apos - 1;
263 if (sibpos < 0) {
264 return DOCUMENT_POSITION_CONTAINS | DOCUMENT_POSITION_PRECEDING;
265 }
266 final JNode sibling = ancestry.get(sibpos);
267 // need to get relative order of 'k' and sibling within 'p'.
268 final JParent prnt = (JParent)p;
269 if (sibling instanceof JAttribute) {
270 final NamedNodeMap nnm = prnt.getAttributes();
271 for (int i = nnm.getLength() - 1; i >= 0; i--) {
272 final Node n = nnm.item(i);
273 if (n == sibling) {
274 return DOCUMENT_POSITION_FOLLOWING;
275 } else if (n == k) {
276 return DOCUMENT_POSITION_PRECEDING;
277 }
278 }
279 } else {
280 for (int i = prnt.getLength() - 1; i >= 0; i--) {
281 final Node n = prnt.item(i);
282 if (n == sibling) {
283 return DOCUMENT_POSITION_FOLLOWING;
284 } else if (n == k) {
285 return DOCUMENT_POSITION_PRECEDING;
286 }
287 }
288 }
289 throw new IllegalStateException("Sibling nodes appear not to be siblings?");
290 }
291 }
292 k = p;
293 p = p.parent;
294 }
295 }
296 return Node.DOCUMENT_POSITION_DISCONNECTED;
297 }
298 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Not same Document Model");
299 }
300
301 @Override
302 public final boolean isEqualNode(final Node other) {
303 // definition of DOM isEquals:
304 // Two nodes are equal if and only if the following conditions are satisfied:
305 //
306 // The two nodes are of the same type.
307 // The following string attributes are equal: nodeName, localName, namespaceURI, prefix, nodeValue . This is: they are both null, or they have the same length and are character for character identical.
308 // The attributes NamedNodeMaps are equal. This is: they are both null, or they have the same length and for each node that exists in one map there is a node that exists in the other map and is equal, although not necessarily at the same index.
309 // The childNodes NodeLists are equal. This is: they are both null, or they have the same length and contain equal nodes at the same index. Note that normalization can affect equality; to avoid this, nodes should be normalized before being compared.
310 //
311 if (other == null) {
312 return false;
313 }
314 if (!getClass().isInstance(other)) {
315 return false;
316 }
317 if (isSameNode(other)) {
318 return true;
319 }
320 if (areSame(getNodeName(), other.getNodeName()) &&
321 areSame(getLocalName(), other.getLocalName()) &&
322 areSame(getNamespaceURI(), other.getNamespaceURI()) &&
323 areSame(getPrefix(), other.getPrefix()) &&
324 areSame(getNodeValue(), other.getNodeValue())) {
325 return detailEquals((JNode)other);
326 }
327
328 return false;
329 }
330
331 @Override
332 public final boolean isSameNode(final Node other) {
333 return this == other;
334 }
335
336 @Override
337 public final Node cloneNode(final boolean deep) {
338 // this would modify things.... we skip it.
339 // as a convenience we just return ourselves ... readonly.
340 // this breaks the DOM specification, but there is so much
341 // that is broken by this thin wrapper.....
342 return this;
343 }
344
345 @Override
346 public final void normalize() {
347 // this would modify things.... we skip it.
348 }
349
350 @Override
351 public final boolean isSupported(final String feature, final String version) {
352 // anything that requires feature support is not supported... ;-)
353 return false;
354 }
355
356 @Override
357 public final void setPrefix(final String prefix) throws DOMException {
358 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
359 "Cannot modify JDOM Wrapper DOM objects.");
360 }
361
362 @Override
363 public final Node insertBefore(final Node newChild, final Node refChild) throws DOMException {
364 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
365 "Cannot modify JDOM Wrapper DOM objects.");
366 }
367
368 @Override
369 public final Node replaceChild(final Node newChild, final Node oldChild) throws DOMException {
370 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
371 "Cannot modify JDOM Wrapper DOM objects.");
372 }
373
374 @Override
375 public final Node removeChild(final Node oldChild) throws DOMException {
376 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
377 "Cannot modify JDOM Wrapper DOM objects.");
378 }
379
380 @Override
381 public final Node appendChild(final Node newChild) throws DOMException {
382 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
383 "Cannot modify JDOM Wrapper DOM objects.");
384 }
385
386 @Override
387 public final void setTextContent(final String textContent) throws DOMException {
388 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
389 "Cannot modify JDOM Wrapper DOM objects.");
390 }
391
392 @Override
393 public final void setNodeValue(final String nodeValue) throws DOMException {
394 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
395 "Cannot modify JDOM Wrapper DOM objects.");
396 }
397
398 protected static final boolean areSame(final String a, final String b) {
399 if (b == null) {
400 return a == null;
401 }
402 if (a == null) {
403 return false;
404 }
405 return a.equals(b);
406 }
407
408 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import java.util.List;
57
58 import org.w3c.dom.Node;
59 import org.w3c.dom.NodeList;
60
61 final class JNodeList implements NodeList {
62
63 private final List<? extends JNode> list;
64
65 public JNodeList(final List<? extends JNode> list) {
66 this.list = list;
67 }
68
69 @Override
70 public Node item(final int index) {
71 if (index < 0 || index >= list.size()) {
72 return null;
73 }
74 return list.get(index);
75 }
76
77 @Override
78 public int getLength() {
79 return list.size();
80 }
81
82 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import java.util.List;
57
58 import org.w3c.dom.Node;
59 import org.w3c.dom.NodeList;
60
61 import org.jdom.CDATA;
62 import org.jdom.Comment;
63 import org.jdom.Content;
64 import org.jdom.DocType;
65 import org.jdom.Element;
66 import org.jdom.EntityRef;
67 import org.jdom.Namespace;
68 import org.jdom.Parent;
69 import org.jdom.ProcessingInstruction;
70 import org.jdom.Text;
71
72 abstract class JParent extends JNamespaceAware implements NodeList {
73
74 private JNamespaceAware[] kids = null;
75 protected final Parent shadow;
76
77 public JParent(final JDocument topdoc, final JParent parent,
78 final Parent shadow, final short nodetype,
79 final Namespace[] nstack) {
80 super(topdoc, parent, nodetype, nstack);
81 this.shadow = shadow;
82 }
83
84 @Override
85 public final Object getWrapped() {
86 return shadow;
87 }
88
89
90
91 private final JNamespaceAware hydrate(final Content k) {
92 switch(k.getCType()) {
93 case CDATA:
94 return topdoc.find((CDATA)k);
95 case Comment:
96 return topdoc.find((Comment)k);
97 case DocType:
98 return topdoc.find((DocType)k);
99 case Element:
100 return topdoc.find((Element)k);
101 case EntityRef:
102 return topdoc.find((EntityRef)k);
103 case ProcessingInstruction:
104 return topdoc.find((ProcessingInstruction)k);
105 case Text:
106 return topdoc.find((Text)k);
107 }
108 throw new IllegalStateException("Unexpected content " + k);
109 }
110
111 protected final JNamespaceAware[] checkKids() {
112 if (kids != null) {
113 return kids;
114 }
115
116 if (shadow == null) {
117 kids = new JNamespaceAware[0];
118 return kids;
119 }
120
121 final List<Content> content = shadow.getContent();
122 kids = new JNamespaceAware[content.size()];
123 for (int i = 0; i < kids.length; i++) {
124 kids[i] = hydrate( content.get(i) );
125 }
126
127 return kids;
128 }
129
130 protected final JNode getPreviousSibling(final JNode jNode) {
131 checkKids();
132 for (int i = 0; i < kids.length; i++) {
133 if (kids[i] == jNode) {
134 return i > 0 ? kids[i - 1] : null;
135 }
136 }
137 return null;
138 }
139
140 protected final JNode getNextSibling(final JNode jNode) {
141 checkKids();
142 for (int i = 0; i < kids.length; i++) {
143 if (kids[i] == jNode) {
144 return i < kids.length - 1 ? kids[i + 1] : null;
145 }
146 }
147 return null;
148 }
149
150 @Override
151 public final boolean hasChildNodes() {
152 checkKids();
153 return kids.length > 0;
154 }
155
156
157 @Override
158 public final NodeList getChildNodes() {
159 checkKids();
160 return this;
161 }
162
163 @Override
164 public final Node getFirstChild() {
165 checkKids();
166 return kids.length > 0 ? kids[0] : null;
167 }
168
169 @Override
170 public final Node getLastChild() {
171 checkKids();
172 return kids.length > 0 ? kids[kids.length - 1] : null;
173 }
174
175 @Override
176 public final Node item(final int index) {
177 checkKids();
178 return index >= 0 && index < kids.length ? kids[index] : null;
179 }
180
181 @Override
182 public final int getLength() {
183 checkKids();
184 return kids.length;
185 }
186
187
188 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.DOMException;
57 import org.w3c.dom.ProcessingInstruction;
58
59 import org.jdom.Content;
60 import org.jdom.Namespace;
61
62 class JProcessingInstruction extends JSimpleContent implements
63 ProcessingInstruction {
64
65 public JProcessingInstruction(final JDocument topdoc, final JParent parent,
66 final Content content, final Namespace[] nstack) {
67 super(topdoc, parent, content, nstack);
68 }
69
70 @Override
71 public String getNodeName() {
72 return getTarget();
73 }
74
75 @Override
76 public String getNodeValue() throws DOMException {
77 return getData();
78 }
79
80 @Override
81 public String getTextContent() throws DOMException {
82 return getData();
83 }
84
85 @Override
86 public String getTarget() {
87 return ((org.jdom.ProcessingInstruction)shadow).getTarget();
88 }
89
90 @Override
91 public String getData() {
92 return ((org.jdom.ProcessingInstruction)shadow).getData();
93 }
94
95 @Override
96 public void setData(final String data) throws DOMException {
97 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
98 "Cannot modify JDOM Wrapper DOM objects.");
99 }
100
101 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.CharacterData;
57 import org.w3c.dom.DOMException;
58
59 import org.jdom.Content;
60 import org.jdom.Namespace;
61
62 abstract class JSimpleCharacterContent extends JSimpleContent implements CharacterData {
63
64 public JSimpleCharacterContent(final JDocument topdoc, final JParent parent,
65 final Content content, final Namespace[] nstack) {
66 super(topdoc, parent, content, nstack);
67 }
68
69 @Override
70 public final String getNodeValue() throws DOMException {
71 return getData();
72 }
73
74 @Override
75 public final String getTextContent() throws DOMException {
76 return getData();
77 }
78
79 @Override
80 public final String getData() throws DOMException {
81 return shadow.getValue();
82 }
83
84 @Override
85 public final void setData(final String data) throws DOMException {
86 throw new DOMException(
87 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
88 }
89
90 @Override
91 public final int getLength() {
92 return getData().length();
93 }
94
95 @Override
96 public final String substringData(final int offset, final int count) throws DOMException {
97 return getData().substring(offset, offset + count);
98 }
99
100 @Override
101 public final void appendData(final String arg) throws DOMException {
102 throw new DOMException(
103 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
104 }
105
106 @Override
107 public final void insertData(final int offset, final String arg) throws DOMException {
108 throw new DOMException(
109 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
110 }
111
112 @Override
113 public final void deleteData(final int offset, final int count) throws DOMException {
114 throw new DOMException(
115 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
116 }
117
118 @Override
119 public final void replaceData(final int offset, final int count, final String arg)
120 throws DOMException {
121 throw new DOMException(
122 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
123 }
124
125 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.jdom.Content;
57 import org.jdom.Namespace;
58
59 abstract class JSimpleContent extends JContent {
60
61 public JSimpleContent(final JDocument topdoc, final JParent parent,
62 final Content content, final Namespace[] nstack) {
63 super(topdoc, parent, content, nstack);
64 }
65
66 @Override
67 public String getNamespaceURI() {
68 return null;
69 }
70
71 @Override
72 public String getPrefix() {
73 return null;
74 }
75
76 @Override
77 public String getLocalName() {
78 return null;
79 }
80
81 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 import org.w3c.dom.DOMException;
57 import org.w3c.dom.Text;
58
59 import org.jdom.Content;
60 import org.jdom.Namespace;
61 import org.jdom.Verifier;
62
63 class JText extends JSimpleCharacterContent implements Text {
64
65 public JText(final JDocument topdoc, final JParent parent,
66 final Content content, final Namespace[] nstack) {
67 super(topdoc, parent, content, nstack);
68 }
69
70 @Override
71 public String getNodeName() {
72 return "#text";
73 }
74
75 @Override
76 public final Text splitText(final int offset) throws DOMException {
77 throw new DOMException(
78 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
79 }
80
81 @Override
82 public final boolean isElementContentWhitespace() {
83 return Verifier.isAllXMLWhitespace(getData());
84 }
85
86 @Override
87 public final String getWholeText() {
88 return getData();
89 }
90
91 @Override
92 public final Text replaceWholeText(final String tcontent) throws DOMException {
93 throw new DOMException(
94 DOMException.NO_MODIFICATION_ALLOWED_ERR, "JDOM Wrapper");
95 }
96
97 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dom;
55
56 /**
57 * All DOM Node instances from this package are also instances of this.
58 * You can access the JDOM object behind this DOM node by calling the
59 * getWrapped() method.
60 *
61 * @author Rolf Lear
62 *
63 */
64 public interface Wrapper {
65 /**
66 * Get the backing JDOM object. The backing object could be:
67 * <ol>
68 * <li> null if this is a Document DOM node, and there was not an actual
69 * JDOM document instance.
70 * <li> A JDOM Document for
71 * <li> A JDOM Attribute
72 * <li> A JDOM Element
73 * <li> A JDOM Text
74 * <li> A JDOM CDATA
75 * <li> A JDOM ProcessingInstruction
76 * <li> A JDOM EntityRef
77 * <li> A JDOM Comment
78 * <li> A JDOM DocTyoe
79 * </ol>
80 * @return the JDOM object that backs this DOM Node.
81 */
82 public Object getWrapped();
83 }
0 <body>
1
2 Classes enabling the read-only view of a JDOM document as a DOM model.
3
4 </body>
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dtdaware;
55
56 import java.io.IOException;
57 import java.io.Writer;
58 import java.util.HashMap;
59 import java.util.HashSet;
60 import java.util.Map;
61 import java.util.Set;
62
63 import org.jdom.Attribute;
64 import org.jdom.Element;
65 import org.jdom.output.support.AbstractXMLOutputProcessor;
66 import org.jdom.output.support.FormatStack;
67
68 /**
69 * Implement a class that is sensitive to an input document's defaulted/implied
70 * attributes, and will not output attributes that are implied.
71 * <p>
72 * You create an instance of this Processor, then tell it what attribute values
73 * to ignore. You do that by calling the ignore() methods with the details of
74 * what attributes (and what the required value of that attribute would be) to
75 * ignore.
76 * <p>
77 * When the XML is output this processor will ignore those attributes which
78 * match the 'ignore' specs.
79 *
80 * @author Rolf Lear
81 *
82 */
83 public class AttAwareXMLOutputProcessor extends AbstractXMLOutputProcessor {
84 /**
85 * Yeah, this is complicated, but it is basically a search tree index.
86 * This is a nested index of attribute details:
87 * <p>
88 * <ol>
89 * <li> at the top is the attribute name
90 * <li> then the Attribute value.
91 * <li> next is the Element name. We only check this level if the attribute
92 * name and value matches to something that is ignored.
93 * <li> next we check to make sure that we are in the correct Attribute Namespace
94 * <li> then finally the Element namespace.
95 * </ol>
96 * <p>
97 * If we search this index tree and all the details match existing entries,
98 * then it is an ignored attribute. The order is set up in such a way that
99 * there should not need to be many checks in HashMaps for non-ignored
100 * content... essentiually we have to have the same attname and attvalue
101 * before the system even checks the Attribute's parent details.
102 */
103 // attname attval emtname attns emtns
104 private final Map<String,Map<String,Map<String,Map<String,Set<String>>>>>
105 ignores = new HashMap<String,Map<String,Map<String,Map<String,Set<String>>>>>();
106
107 /**
108 * Construct this AttAwareXMLOutputProcessor.
109 * Add attribute to exclude using the
110 * {@link #ignore(String, String, String, String, String)} method
111 */
112 public AttAwareXMLOutputProcessor() {
113 super();
114 }
115
116
117 /**
118 * Ignore an attribute (where the attribute and element are both in the
119 * no-uri namespace).
120 * @param elementname The name of the Attribute's parent element.
121 * @param attname The name of the attribute.
122 * @param attvalue The attribute value to ignore.
123 */
124 public void ignore(String elementname, String attname, String attvalue) {
125 ignore("", elementname, "", attname, attvalue);
126 }
127
128 /**
129 * Ignore an attribute.
130 * @param elementuri The NamespaceURI of the Attribute's parent Element
131 * @param elementname The name of the Attribute's parent Element.
132 * @param atturi The Attribute's namespace URI.
133 * @param attname The name of the attribute.
134 * @param attvalue The attribute value.
135 */
136 public void ignore(String elementuri, String elementname,
137 String atturi, String attname, String attvalue) {
138 Map<String, Map<String, Map<String, Set<String>>>> av =
139 ignores.get(attname);
140 if (av == null) {
141 av = new HashMap<String, Map<String,Map<String,Set<String>>>>();
142 ignores.put(attname, av);
143 }
144 Map<String, Map<String,Set<String>>> en = av.get(attvalue);
145 if (en == null) {
146 en = new HashMap<String, Map<String,Set<String>>>();
147 av.put(attvalue, en);
148 }
149 Map<String, Set<String>> ans = en.get(elementname);
150 if (ans == null) {
151 ans = new HashMap<String, Set<String>>();
152 en.put(elementname, ans);
153 }
154 Set<String> ens = ans.get(atturi);
155 if (ens == null) {
156 ens = new HashSet<String>();
157 ans.put(atturi, ens);
158 }
159 ens.add(elementuri);
160 }
161
162 /**
163 * This extends the printAttribute code to search for attributes to ignore.
164 */
165 @Override
166 protected void printAttribute(Writer out, FormatStack fstack,
167 Attribute attribute) throws IOException {
168 // do we have anything to ignore.
169 if (!ignores.isEmpty()) {
170 // yes, there are ignores.
171 final Map<String, Map<String, Map<String, Set<String>>>> av =
172 ignores.get(attribute.getName());
173 if (av != null) {
174 // we are ignoring at least one attribute with this name.
175 final Map<String, Map<String, Set<String>>> en =
176 av.get(attribute.getValue());
177 if (en != null) {
178 // we ignore something with the attribute name and value
179 final Element e = attribute.getParent();
180 final Map<String, Set<String>> ans =
181 en.get(e.getName());
182 if (ans != null) {
183 // and the same Element name
184 final Set<String> ens = ans.get(attribute.getNamespaceURI());
185 if (ens != null && ens.contains(e.getNamespaceURI())) {
186 // and the same Attribute and Element namespace....
187 // we match the ignored content...
188 // skip this attribute.
189 return;
190 }
191 }
192 }
193 }
194 }
195 // we are not ignoring this attribute.
196 super.printAttribute(out, fstack, attribute);
197 }
198 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dtdaware;
55
56 import java.util.HashMap;
57 import java.util.HashSet;
58 import java.util.Map;
59 import java.util.Set;
60
61 import org.jdom.Attribute;
62 import org.jdom.Element;
63 import org.jdom.filter2.AbstractFilter;
64
65
66 /**
67 * This AttFilter can be programmed to ignore specific attributes.
68 * The ignore criteria is based on the Attribute name, value, and the
69 * Element it is attached to.
70 *
71 * @author Rolf Lear
72 *
73 */
74 public class AttFilter extends AbstractFilter<Attribute> {
75
76 /**
77 *
78 */
79 private static final long serialVersionUID = 1L;
80 /**
81 * Yeah, this is complicated, but it is basically a search tree index.
82 * This is a nested index of attribute details:
83 * <p>
84 * <ol>
85 * <li> at the top is the attribute name
86 * <li> then the Attribute value.
87 * <li> next is the Element name. We only check this level if the attribute
88 * name and value matches to something that is ignored.
89 * <li> next we check to make sure that we are in the correct Attribute Namespace
90 * <li> then finally the Element namespace.
91 * </ol>
92 * <p>
93 * If we search this index tree and all the details match existing entries,
94 * then it is an ignored attribute. The order is set up in such a way that
95 * there should not need to be many checks in HashMaps for non-ignored
96 * content... essentiually we have to have the same attname and attvalue
97 * before the system even checks the Attribute's parent details.
98 */
99 // attname attval emtname attns emtns
100 private final Map<String,Map<String,Map<String,Map<String,Set<String>>>>>
101 ignores = new HashMap<String,Map<String,Map<String,Map<String,Set<String>>>>>();
102
103 /**
104 * Ignore an attribute (where the attribute and element are both in the
105 * no-uri namespace).
106 * @param elementname The name of the Attribute's parent element.
107 * @param attname The name of the attribute.
108 * @param attvalue The attribute value to ignore.
109 */
110 public void ignore(String elementname, String attname, String attvalue) {
111 ignore("", elementname, "", attname, attvalue);
112 }
113
114 /**
115 * Ignore an attribute.
116 * @param elementuri The NamespaceURI of the Attribute's parent Element
117 * @param elementname The name of the Attribute's parent Element.
118 * @param atturi The Attribute's namespace URI.
119 * @param attname The name of the attribute.
120 * @param attvalue The attribute value.
121 */
122 public void ignore(String elementuri, String elementname,
123 String atturi, String attname, String attvalue) {
124 Map<String, Map<String, Map<String, Set<String>>>> av =
125 ignores.get(attname);
126 if (av == null) {
127 av = new HashMap<String, Map<String,Map<String,Set<String>>>>();
128 ignores.put(attname, av);
129 }
130 Map<String, Map<String,Set<String>>> en = av.get(attvalue);
131 if (en == null) {
132 en = new HashMap<String, Map<String,Set<String>>>();
133 av.put(attvalue, en);
134 }
135 Map<String, Set<String>> ans = en.get(elementname);
136 if (ans == null) {
137 ans = new HashMap<String, Set<String>>();
138 en.put(elementname, ans);
139 }
140 Set<String> ens = ans.get(atturi);
141 if (ens == null) {
142 ens = new HashSet<String>();
143 ans.put(atturi, ens);
144 }
145 ens.add(elementuri);
146 }
147
148
149
150
151 @Override
152 public Attribute filter(Object content) {
153 if (!(content instanceof Attribute)) {
154 return null;
155 }
156 Attribute attribute = (Attribute)content;
157 if (!ignores.isEmpty()) {
158 // yes, there are ignores.
159 final Map<String, Map<String, Map<String, Set<String>>>> av =
160 ignores.get(attribute.getName());
161 if (av != null) {
162 // we are ignoring at least one attribute with this name.
163 final Map<String, Map<String, Set<String>>> en =
164 av.get(attribute.getValue());
165 if (en != null) {
166 // we ignore something with the attribute name and value
167 final Element e = attribute.getParent();
168 final Map<String, Set<String>> ans =
169 en.get(e.getName());
170 if (ans != null) {
171 // and the same Element name
172 final Set<String> ens = ans.get(attribute.getNamespaceURI());
173 if (ens != null && ens.contains(e.getNamespaceURI())) {
174 // and the same Attribute and Element namespace....
175 // we match the ignored content...
176 // skip this attribute.
177 return null;
178 }
179 }
180 }
181 }
182 }
183 return attribute;
184 }
185
186
187
188 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.dtdaware;
55
56 import java.io.IOException;
57 import java.io.Writer;
58
59 import org.jdom.Attribute;
60 import org.jdom.filter2.Filter;
61 import org.jdom.output.support.AbstractXMLOutputProcessor;
62 import org.jdom.output.support.FormatStack;
63
64 /**
65 * Implement a class that is sensitive to a document's attributes, and will not
66 * output attributes that fail to match the supplied Filter.
67 *
68 * @author Rolf Lear
69 *
70 */
71 public class AttFilteredXMLOutputProcessor extends AbstractXMLOutputProcessor {
72 /**
73 * Attributes that do not match this filter will not be printed.
74 */
75 private final Filter<? super Attribute> attfilter;
76
77 /**
78 * Construct this AttAwareXMLOutputProcessor.
79 * @param attf The filter to use which determines what Attributes are processed.
80 */
81 public AttFilteredXMLOutputProcessor(Filter<? super Attribute> attf) {
82 super();
83 this.attfilter = attf;
84 }
85
86
87 /**
88 * This extends the printAttribute code to search for attributes to ignore.
89 */
90 @Override
91 protected void printAttribute(Writer out, FormatStack fstack,
92 Attribute attribute) throws IOException {
93 // do we have anything to ignore.
94 // we are not ignoring this attribute.
95 if (!attfilter.matches(attribute)) {
96 return;
97 }
98 super.printAttribute(out, fstack, attribute);
99 }
100 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.helpers;
55
56 import org.jdom.*;
57 import java.util.*;
58
59 /** <p>
60 * This class contains static helper methods.
61 * </p>
62 * @author Alex Rosen
63 * @deprecated concept has been moved in to core:
64 * {@link Element#sortContent(Comparator)}
65 * @see Element#sortChildren(Comparator)
66 * @see Element#sortContent(Comparator)
67 * @see Element#sortContent(org.jdom.filter2.Filter, Comparator)
68 */
69 @Deprecated
70 public class JDOMHelper {
71 /**
72 * <p>
73 * Sorts the child elements, using the specified comparator.
74 * @param parent The parent Element, whose child Elements should be sorted.
75 * @param c The Comparator to use for ordering the child Elements.
76 * It will only be given Element objects to compare.
77 * </p>
78 * <p>
79 * This method overcomes two problems with the standard Collections.sort():
80 * <ul>
81 * <li>Collections.sort() doesn't bother to remove an item from its old
82 * location before placing it in its new location, which causes JDOM to
83 * complain that the item has been added twice.
84 * <li>This method will sort the child Elements without moving any other
85 * content, such as formatting text nodes (newlines, indents, etc.)
86 * Otherwise, all the formatting whitespace would move to the beginning
87 * or end of the content list.
88 * (Note that this means that the elements will now be in a different
89 * order with respect to any comments, which may cause a problem
90 * if the comments describe the elements.)
91 * </ul>
92 * </p>
93 */
94 public static void sortElements(Element parent, Comparator<Element> c) {
95 // Create a new, static list of child elements, and sort it.
96 List<Element> children = new ArrayList<Element>(parent.getChildren());
97 Collections.sort(children, c);
98 ListIterator<Element> childrenIter = children.listIterator();
99
100 // Create a new, static list of all content items.
101 List<Content> content = new ArrayList<Content>(parent.getContent());
102 ListIterator<Content> contentIter = content.listIterator();
103
104 // Loop through the content items, and whenever we find an Element,
105 // we'll insert the next ordered Element in its place. Because the
106 // content list is not live, it won't complain about an Element being
107 // added twice.
108 while(contentIter.hasNext()) {
109 Object obj = contentIter.next();
110 if (obj instanceof Element)
111 contentIter.set(childrenIter.next());
112 }
113
114 // Finally, we set the content list back into the parent Element.
115 parent.setContent((List<Content>)null);
116 parent.setContent(content);
117 }
118 }
0 This is an area for little helper classes. It's open to experimentation and
1 whimsy.
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.helpers;
55
56
57 import java.util.Iterator;
58 import java.util.List;
59
60 import org.jdom.Attribute;
61 import org.jdom.Comment;
62 import org.jdom.Document;
63 import org.jdom.Element;
64 import org.jdom.JDOMException;
65 import org.jdom.Namespace;
66 import org.jdom.ProcessingInstruction;
67 import org.jdom.Text;
68 import org.jdom.filter.Filters;
69
70
71 /**
72 * Provides a set of utility methods to generate XPath expressions
73 * to select a given node in a (subtree of a) document.
74 * <p>
75 * <strong>Note</strong>: As this class has no knowledge of the
76 * document content, the generated XPath expression rely on the
77 * document structure. Hence any modification of the structure
78 * of the document may invalidate the generated XPaths.</p>
79 *
80 * @author Laurent Bihanic
81 * @deprecated moved in to core: org.jdom.xpath.XPathHelper
82 * @see org.jdom.xpath.XPathHelper
83 */
84 @Deprecated
85 public class XPathHelper {
86
87 /**
88 * Returns the path to the specified Element from the document
89 * root as an XPath expression.
90 *
91 * @param to the Element the generated path shall select.
92 *
93 * @return an XPath expression to select the specified node.
94 *
95 * @throws JDOMException if the XPath generation failed.
96 * @throws IllegalArgumentException if <code>to</code> is
97 * <code>null</code>.
98 */
99 public static String getPathString(Element to) throws JDOMException {
100 return getPathString(null, to);
101 }
102
103 /**
104 * Returns the path from a given JDOM node to the specified
105 * Element as an XPath expression.
106 *
107 * @param from the Document or Element node at which the
108 * the generated path shall be applied. Use
109 * <code>null</code> to specify the topmost
110 * ancestor of the <code>to</code> node.
111 * @param to the Element the generated path shall select.
112 *
113 * @return an XPath expression to select the specified node.
114 *
115 * @throws JDOMException if the XPath generation failed.
116 * @throws IllegalArgumentException if <code>to</code> is
117 * <code>null</code> or <code>from</code> is not
118 * a {@link Document} or a {@link Element} node.
119 */
120 public static String getPathString(Object from, Element to)
121 throws JDOMException {
122 checkPathStringArguments(from, to);
123
124 if (to == from) {
125 return "node()";
126 }
127 return getElementPath(from, to, true).toString();
128 }
129
130 /**
131 * Returns the path to the specified Attribute from the document
132 * root as an XPath expression.
133 *
134 * @param to the Attribute the generated path shall select.
135 *
136 * @return an XPath expression to select the specified node.
137 *
138 * @throws JDOMException if the XPath generation failed.
139 * @throws IllegalArgumentException if <code>to</code> is
140 * <code>null</code>.
141 */
142 public static String getPathString(Attribute to) throws JDOMException {
143 return getPathString(null, to);
144 }
145
146 /**
147 * Returns the path from a given JDOM node to the specified
148 * Attribute as an XPath expression.
149 *
150 * @param from the Document or Element node at which the
151 * the generated path shall be applied. Use
152 * <code>null</code> to specify the topmost
153 * ancestor of the <code>to</code> node.
154 * @param to the Attribute the generated path shall select.
155 *
156 * @return an XPath expression to select the specified node.
157 *
158 * @throws JDOMException if the XPath generation failed.
159 * @throws IllegalArgumentException if <code>to</code> is
160 * <code>null</code> or <code>from</code> is not
161 * a {@link Document} or a {@link Element} node.
162 */
163 public static String getPathString(Object from, Attribute to)
164 throws JDOMException {
165 checkPathStringArguments(from, to);
166
167 if (to == from) {
168 return "node()";
169 }
170 StringBuilder path = getElementPath(from, to.getParent(), false);
171 path.append('@').append(to.getName()).toString();
172 return path.toString();
173 }
174
175 /**
176 * Returns the path to the specified Text node from the document
177 * root as an XPath expression.
178 *
179 * @param to the Text node the generated path shall select.
180 *
181 * @return an XPath expression to select the specified node.
182 *
183 * @throws JDOMException if the XPath generation failed.
184 * @throws IllegalArgumentException if <code>to</code> is
185 * <code>null</code>.
186 */
187 public static String getPathString(Text to) throws JDOMException {
188 return getPathString(null, to);
189 }
190
191 /**
192 * Returns the path from a given JDOM node to the specified
193 * Text node as an XPath expression.
194 *
195 * @param from the Document or Element node at which the
196 * the generated path shall be applied. Use
197 * <code>null</code> to specify the topmost
198 * ancestor of the <code>to</code> node.
199 * @param to the Text node the generated path shall select.
200 *
201 * @return an XPath expression to select the specified node.
202 *
203 * @throws JDOMException if the XPath generation failed.
204 * @throws IllegalArgumentException if <code>to</code> is
205 * <code>null</code> or <code>from</code> is not
206 * a {@link Document} or a {@link Element} node.
207 */
208 public static String getPathString(Object from, Text to)
209 throws JDOMException {
210 checkPathStringArguments(from, to);
211
212 if (to == from) {
213 return "node()";
214 }
215 Element parent = to.getParentElement();
216 List<Text> siblings = null;
217 StringBuilder path = getElementPath(from, parent, false);
218
219 if (parent != null) {
220 siblings = parent.getContent(Filters.text());
221 }
222 else {
223 Document doc = to.getDocument();
224 if (doc != null) {
225 siblings = doc.getContent(Filters.text());
226 }
227 }
228 return getPositionPath(to, siblings, "text()", path).toString();
229 }
230
231 /**
232 * Returns the path to the specified Comment from the document
233 * root as an XPath expression.
234 *
235 * @param to the Comment the generated path shall select.
236 *
237 * @return an XPath expression to select the specified node.
238 *
239 * @throws JDOMException if the XPath generation failed.
240 * @throws IllegalArgumentException if <code>to</code> is
241 * <code>null</code>.
242 */
243 public static String getPathString(Comment to) throws JDOMException {
244 return getPathString(null, to);
245 }
246
247 /**
248 * Returns the path from a given JDOM node to the specified
249 * Comment as an XPath expression.
250 *
251 * @param from the Document or Element node at which the
252 * the generated path shall be applied. Use
253 * <code>null</code> to specify the topmost
254 * ancestor of the <code>to</code> node.
255 * @param to the Comment the generated path shall select.
256 *
257 * @return an XPath expression to select the specified node.
258 *
259 * @throws JDOMException if the XPath generation failed.
260 * @throws IllegalArgumentException if <code>to</code> is
261 * <code>null</code> or <code>from</code> is not
262 * a {@link Document} or a {@link Element} node.
263 */
264 public static String getPathString(Object from, Comment to)
265 throws JDOMException {
266 checkPathStringArguments(from, to);
267
268 if (to == from) {
269 return "node()";
270 }
271 Element parent = to.getParentElement();
272 List<Comment> siblings = null;
273 StringBuilder path = getElementPath(from, parent, false);
274
275 if (parent != null) {
276 siblings = parent.getContent(Filters.comment());
277 }
278 else {
279 Document doc = to.getDocument();
280 if (doc != null) {
281 siblings = doc.getContent(Filters.comment());
282 }
283 }
284 return getPositionPath(to, siblings, "comment()", path).toString();
285 }
286
287 /**
288 * Returns the path to the specified ProcessingInstruction node
289 * from the document root as an XPath expression.
290 *
291 * @param to the ProcessingInstruction node the generated path
292 * shall select.
293 *
294 * @return an XPath expression to select the specified node.
295 *
296 * @throws JDOMException if the XPath generation failed.
297 * @throws IllegalArgumentException if <code>to</code> is
298 * <code>null</code>.
299 */
300 public static String getPathString(ProcessingInstruction to)
301 throws JDOMException {
302 return getPathString(null, to);
303 }
304
305 /**
306 * Returns the path from a given JDOM node to the specified
307 * ProcessingInstruction node as an XPath expression.
308 *
309 * @param from the Document or Element node at which the
310 * the generated path shall be applied. Use
311 * <code>null</code> to specify the topmost
312 * ancestor of the <code>to</code> node.
313 * @param to the ProcessingInstruction node the generated
314 * path shall select.
315 *
316 * @return an XPath expression to select the specified node.
317 *
318 * @throws JDOMException if the XPath generation failed.
319 * @throws IllegalArgumentException if <code>to</code> is
320 * <code>null</code> or <code>from</code> is not
321 * a {@link Document} or a {@link Element} node.
322 */
323 public static String getPathString(Object from, ProcessingInstruction to)
324 throws JDOMException {
325 checkPathStringArguments(from, to);
326
327 if (to == from) {
328 return "node()";
329 }
330 Element parent = to.getParentElement();
331 List<ProcessingInstruction> siblings = null;
332 StringBuilder path = getElementPath(from, parent, false);
333
334 if (parent != null) {
335 siblings = parent.getContent(Filters.processinginstruction());
336 }
337 else {
338 Document doc = to.getDocument();
339 if (doc != null) {
340 siblings = doc.getContent(Filters.processinginstruction());
341 }
342 }
343 return getPositionPath(to, siblings,
344 "processing-instruction()", path).toString();
345 }
346
347 /**
348 * Returns the path to the specified JDOM node from the document
349 * root as an XPath expression.
350 *
351 * @param to the JDOM node the generated path shall select.
352 *
353 * @return an XPath expression to select the specified node.
354 *
355 * @throws JDOMException if the XPath generation failed.
356 * @throws IllegalArgumentException if <code>to</code> is
357 * <code>null</code> or is not a JDOM node selectable
358 * by XPath expressions (Element, Attribute, Text,
359 * Comment, ProcessingInstruction).
360 */
361 public static String getPathString(Object to) throws JDOMException {
362 return getPathString(null, to);
363 }
364
365 /**
366 * Returns the path from a JDOM node to another JDOM node
367 * as an XPath expression.
368 *
369 * @param from the Document or Element node at which the
370 * the generated path shall be applied. Use
371 * <code>null</code> to specify the topmost
372 * ancestor of the <code>to</code> node.
373 * @param to the JDOM node the generated path shall select.
374 *
375 * @return an XPath expression to select the specified node.
376 *
377 * @throws JDOMException if the XPath generation failed.
378 * @throws IllegalArgumentException if <code>from</code> is not
379 * a {@link Document} or a {@link Element} node or
380 * <code>to</code> is <code>null</code> or is not a JDOM
381 * node selectable by XPath expressions (Element,
382 * Attribute, Text, Comment, ProcessingInstruction).
383 */
384 public static String getPathString(Object from, Object to)
385 throws JDOMException {
386 if (to instanceof Element) {
387 return getPathString(from, (Element) to);
388 }
389 else if (to instanceof Attribute) {
390 return getPathString(from, (Attribute) to);
391 }
392 else if (to instanceof Text) {
393 return getPathString(from, (Text) to);
394 }
395 else if (to instanceof Comment) {
396 return getPathString(from, (Comment) to);
397 }
398 else if (to instanceof ProcessingInstruction) {
399 return getPathString(from, (ProcessingInstruction) to);
400 }
401 else {
402 throw new IllegalArgumentException(
403 "\"to \" shall be an Element, Attribute," +
404 " Text, Comment or ProcessingInstruction node");
405 }
406 }
407
408
409 /**
410 * Checks that the two arguments of a <code>getPathString()</code>
411 * call are valid.
412 *
413 * @param from the <code>from</code> node.
414 * @param to the <code>to</code> node.
415 *
416 * @throws IllegalArgumentException if one of the arguments is
417 * invalid.
418 */
419 private static void checkPathStringArguments(Object from, Object to) {
420 if (!((from == null) || (from instanceof Element)
421 || (from instanceof Document))) {
422 throw new IllegalArgumentException("from");
423 }
424 if (to == null) {
425 throw new IllegalArgumentException("to");
426 }
427 }
428
429 /**
430 * Returns the XPath expression to select the <code>to</code>
431 * element relatively to the <code>from</code> element.
432 *
433 * @param from the <code>from</code> element.
434 * @param to the <code>to</code> element.
435 * @param leaf whether the <code>to</code> is the last element
436 * of the path to return.
437 *
438 * @return an XPath expression to select the <code>to</code>
439 * element.
440 *
441 * @throws JDOMException if the XPath generation failed.
442 */
443 private static StringBuilder getElementPath(Object from,
444 Element to, boolean leaf)
445 throws JDOMException {
446 if (from instanceof Document) {
447 from = null;
448 }
449 return getElementPath((Element) from, to, leaf, new StringBuilder());
450 }
451
452 /**
453 * Returns the XPath expression to select the <code>to</code>
454 * element relatively to the <code>from</code> element.
455 *
456 * @param from the <code>from</code> element.
457 * @param to the <code>to</code> element.
458 * @param leaf whether the <code>to</code> is the last element
459 * of the path to return.
460 * @param path the buffer to which append the path.
461 *
462 * @return an XPath expression to select the <code>to</code>
463 * element.
464 *
465 * @throws JDOMException if the XPath generation failed.
466 */
467 private static StringBuilder getElementPath(Element from, Element to,
468 boolean leaf, StringBuilder path)
469 throws JDOMException {
470 if (to != from) {
471 List<Element> siblings = null;
472
473 Element parent = to.getParentElement();
474 if (parent == null) {
475 // Oops! No more parent but I haven't yet reached the from node.
476 if (parent != from) {
477 // Ouch! from node is not an ancestor.
478 throw new JDOMException(
479 "The \"from\" node is not an ancestor of the \"to\" node");
480 }
481 if (to.isRootElement()) {
482 path.append('/');
483 }
484 }
485 else {
486 siblings = parent.getChildren(to.getName(), null);
487 }
488
489 if (parent != from) {
490 path = getElementPath(from, parent, false, path);
491 }
492
493 Namespace ns = to.getNamespace();
494 if (ns == Namespace.NO_NAMESPACE) {
495 // No namespace => Use local name only.
496 path = getPositionPath(to, siblings, to.getName(), path);
497 }
498 else {
499 // Elements belongs to a namespace => Check prefix.
500 String prefix = to.getNamespacePrefix();
501 if ("".equals(prefix)) {
502 // No prefix (default namespace in scope
503 // => Use wildcard & local name combination.
504 path.append("*[local-name()='").
505 append(to.getName()).append("']");
506
507 path = getPositionPath(to, siblings, null, path);
508 }
509 else {
510 // Not the default namespace => Use prefix.
511 path.append(to.getNamespacePrefix()).append(':');
512
513 path = getPositionPath(to, siblings, to.getName(), path);
514 }
515 }
516
517 if ((!leaf) && (path.length() != 0)) {
518 path.append('/');
519 }
520 }
521 return (path);
522 }
523
524 /**
525 * Appends the specified path token to the provided buffer
526 * followed by the position specification of the target node in
527 * its siblings list.
528 *
529 * @param node the target node for the XPath expression.
530 * @param siblings the siblings of the target node.
531 * @param pathToken the path token identifying the target node.
532 * @param buffer the buffer to which appending the XPath
533 * sub-expression or <code>null</code> if the
534 * method shall allocate a new buffer.
535 *
536 * @return the XPath sub-expression to select the target node
537 * among its siblings.
538 */
539 private static StringBuilder getPositionPath(Object node, List<?> siblings,
540 String pathToken,
541 StringBuilder buffer) {
542 if (buffer == null) {
543 buffer = new StringBuilder();
544 }
545 if (pathToken != null) {
546 buffer.append(pathToken);
547 }
548
549 if ((siblings != null) && (siblings.size() != 1)) {
550 int position = 0;
551 for (Iterator<?> i = siblings.iterator(); i.hasNext();) {
552 position++;
553 if (i.next() == node) break;
554 }
555 buffer.append('[').append(position).append(']');
556 }
557 return buffer;
558 }
559 }
560
0 /*--
1
2 Copyright (C) 2001-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.ids;
55
56 import org.jdom.Attribute;
57 import org.jdom.AttributeType;
58 import org.jdom.Document;
59 import org.jdom.Element;
60 import org.jdom.Namespace;
61 import org.jdom.Parent;
62
63
64 /**
65 * A sub-class of the default JDOM <code>Attribute</code> to help
66 * keeping up-to-date the element lookup table maintained by
67 * <code>IdDocument</code>.
68 *
69 * @author Laurent Bihanic
70 */
71 @SuppressWarnings("javadoc")
72 public class IdAttribute extends Attribute {
73
74 /**
75 * Default.
76 */
77 private static final long serialVersionUID = 1L;
78
79 public IdAttribute(String name, String value, Namespace namespace) {
80 super(name, value, namespace);
81 }
82
83 public IdAttribute(String name, String value,
84 AttributeType type, Namespace namespace) {
85 super(name, value, type, namespace);
86 }
87
88 public IdAttribute(String name, String value) {
89 this(name, value, UNDECLARED_TYPE, Namespace.NO_NAMESPACE);
90 }
91
92 public IdAttribute(String name, String value, AttributeType type) {
93 this(name, value, type, Namespace.NO_NAMESPACE);
94 }
95
96 @Override
97 protected Attribute setParent(Element parent) {
98 Parent oldParent = this.getParent();
99
100 super.setParent(parent);
101
102 if (this.getAttributeType() == Attribute.ID_TYPE) {
103 Document doc;
104
105 // Udpate the owning document's lookup table.
106 if (oldParent != null) {
107 doc = oldParent.getDocument();
108 if (doc instanceof IdDocument) {
109 ((IdDocument)doc).removeId(this.getValue());
110 }
111 }
112 doc = this.getDocument();
113 if (doc instanceof IdDocument) {
114 ((IdDocument)doc).addId(this.getValue(), this.getParent());
115 }
116 }
117 return this;
118 }
119
120 @Override
121 public Attribute setValue(String value) {
122 String oldValue = this.getValue();
123
124 super.setValue(value);
125
126 if (this.getAttributeType() == Attribute.ID_TYPE) {
127 // Udpate the owning document's lookup table.
128 Document doc = this.getDocument();
129 if (doc instanceof IdDocument) {
130 ((IdDocument)doc).removeId(oldValue);
131 ((IdDocument)doc).addId(this.getValue(), this.getParent());
132 }
133 }
134 return this;
135 }
136
137 @Override
138 public Attribute setAttributeType(AttributeType type) {
139 AttributeType oldType = this.getAttributeType();
140
141 if (type != oldType) {
142 super.setAttributeType(type);
143
144 // Udpate the owning document's lookup table.
145 Document doc = this.getDocument();
146 if (doc instanceof IdDocument) {
147 if (oldType == Attribute.ID_TYPE) {
148 ((IdDocument)doc).removeId(this.getValue());
149 }
150 if (type == Attribute.ID_TYPE) {
151 ((IdDocument)doc).addId(this.getValue(), this.getParent());
152 }
153 }
154 }
155 return this;
156 }
157 }
158
0 /*--
1
2 Copyright (C) 2001-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.ids;
55
56 import java.util.*;
57
58 import org.jdom.Document;
59 import org.jdom.DocType;
60 import org.jdom.Element;
61
62
63 /**
64 * IdDocument extends the default JDOM document to support looking
65 * up elements using their ID attribute.
66 * <p>
67 * Instances of this class should not be created directly but through
68 * the {@link IdFactory}. Using this factory ensures that the
69 * document is made of {@link IdElement} instances which update the
70 * look-up table when the element attribute list is updated.</p>
71 * <p>
72 * The method {@link #getElementById} allows looking up an element
73 * in the document given the value of its ID attribute. Instead of
74 * scanning the whole document when searching for an element,
75 * <code>IdDocument</code> uses a lookup table for fast direct
76 * access to the elements. Hence, applications using this method
77 * should see their performances improved compared to walking the
78 * document tree.</p>
79 *
80 * @author Laurent Bihanic
81 */
82 @SuppressWarnings("javadoc")
83 public class IdDocument extends Document {
84
85 /**
86 * Default.
87 */
88 private static final long serialVersionUID = 1L;
89
90 /**
91 * <p>The ID lookup table for the document.</p>
92 */
93 private Map<String,Element> ids = new HashMap<String, Element>();
94
95 /**
96 * <p>
97 * Creates a new <code>IdDocument</code>, with the supplied
98 * <code>{@link Element}</code> as the root element and the
99 * supplied <code>{@link DocType}</code> declaration.</p>
100 *
101 * @param rootElement <code>Element</code> for document root.
102 * @param docType <code>DocType</code> declaration.
103 */
104 public IdDocument(Element root, DocType docType) {
105 super(root, docType);
106 }
107
108 /**
109 * <p>
110 * Creates a new <code>Document</code>, with the supplied
111 * <code>{@link Element}</code> as the root element, and no
112 * <code>{@link DocType document type}</code> declaration.
113 * </p>
114 *
115 * @param rootElement <code>Element</code> for document root.
116 */
117 public IdDocument(Element root) {
118 super(root);
119 }
120
121 /**
122 * <p>
123 * Retrieves an element using the value of its ID attribute as
124 * key.</p>
125 *
126 * @param id the value of the ID attribute of the element to
127 * retrieve.
128 * @return the <code>Element</code> associated to <code>id</code>
129 * or <code>null</code> if none was found.
130 */
131 public Element getElementById(String id) {
132 return ids.get(id);
133 }
134
135 /**
136 * <p>
137 * Adds the specified ID to the ID lookup table of this document
138 * and make it point to the associated element.</p>
139 *
140 * @param id the ID to add.
141 * @param elt the <code>Element</code> associated to the ID.
142 */
143 protected void addId(String id, Element elt) {
144 ids.put(id, elt);
145 return;
146 }
147
148 /**
149 * <p>
150 * Removes the specified ID from the ID lookup table of this
151 * document.</p>
152 *
153 * @param id the ID to remove.
154 * @return <code>true</code> if the ID was found and removed;
155 * <code>false</code> otherwise.
156 */
157 protected boolean removeId(String id) {
158 return (ids.remove(id) != null);
159 }
160 }
161
0 /*--
1
2 Copyright (C) 2001-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.ids;
55
56 import java.util.*;
57
58 import org.jdom.Attribute;
59 import org.jdom.Content;
60 import org.jdom.Document;
61 import org.jdom.Element;
62 import org.jdom.Parent;
63 import org.jdom.Namespace;
64
65 /**
66 * A sub-class of the default JDOM <code>Element</code> to help
67 * keeping up-to-date the element lookup table maintained by
68 * <code>IdDocument</code>.
69 *
70 * @author Laurent Bihanic
71 */
72 @SuppressWarnings("javadoc")
73 public class IdElement extends Element {
74
75 /**
76 * Default.
77 */
78 private static final long serialVersionUID = 1L;
79
80 // Allow Javadocs to inherit from superclass
81
82 public IdElement(String name, Namespace namespace) {
83 super(name, namespace);
84 }
85
86 public IdElement(String name) {
87 this(name, (Namespace)null);
88 }
89
90 public IdElement(String name, String uri) {
91 this(name, Namespace.getNamespace("", uri));
92 }
93
94 public IdElement(String name, String prefix, String uri) {
95 this(name, Namespace.getNamespace(prefix, uri));
96 }
97
98 @Override
99 protected Content setParent(Parent parent) {
100 // Save previous owning document (if any).
101 Document prevDoc = this.getDocument();
102 Document newDoc = (parent != null)? parent.getDocument(): null;
103
104 // Attach to new parent element.
105 super.setParent(parent);
106
107 if (newDoc != prevDoc) {
108 // New and previous owning documents are different.
109 // => Remove all the IDs for the subtree this element is the root
110 // of from the previous owning document's lookup table and
111 // insert them into the new owning document's lookup table.
112 transferIds(prevDoc, newDoc);
113 }
114 return this;
115 }
116
117
118 /**
119 * <p>
120 * Transfers all the IDs for the subtree this element is the root
121 * of from the lookup table of the previous owning document to
122 * the lookup table of the new owning document.</p>
123 * <p>
124 * If either of the documents is <code>null</code> or is not an
125 * {@link IdDocument}, this method performs not action on the
126 * document. Hence, this method supports being called with both
127 * documents equal to <code>null</code>.</p>
128 *
129 * @param prevDoc the previous owning document.
130 * @param newDoc the new owning document.
131 */
132 private void transferIds(Document prevDoc, Document newDoc)
133 {
134 if ((prevDoc instanceof IdDocument) || (newDoc instanceof IdDocument)) {
135 // At least one of the documents supports lookup by ID.
136 // => Walk subtree to collect ID mappings.
137 Map<String,Element> ids = getIds(this, new HashMap<String, Element>());
138
139 // Update previous owning document.
140 if (prevDoc instanceof IdDocument) {
141 // Document supports lookup by ID.
142 // => Remove IDs from document's lookup table.
143 IdDocument idDoc = (IdDocument)prevDoc;
144
145 for (String key : ids.keySet()) {
146 idDoc.removeId(key);
147 }
148 }
149 // Else: Lookup by ID not supported. => Nothing to update!
150
151 // Update new owning document.
152 if (newDoc instanceof IdDocument) {
153 // Document supports lookup by ID.
154 // => Add IDs from document's lookup table.
155 IdDocument idDoc = (IdDocument)newDoc;
156
157 for (Map.Entry<String,Element> me : ids.entrySet()) {
158 idDoc.addId(me.getKey(), me.getValue());
159 }
160 }
161 // Else: Lookup by ID not supported. => Nothing to update!
162 }
163 // Else: None of the documents supports lookup by ID not supported.
164 // => Ignore call.
165 return;
166 }
167
168 /**
169 * <p>
170 * Retrieves the ID attributes for the subtree rooted at
171 * <code>root</code> to populate the ID mapping table
172 * <code>ids</code>. In the mapping table, ID attribute values are
173 * the keys to access the elements.</p>
174 *
175 * @param root the root element of the subtree to walk.
176 * @param ids the ID lookup table to populate.
177 *
178 * @return the updated ID lookup table.
179 */
180 private static Map<String,Element> getIds(Element root, Map<String,Element> ids) {
181 addIdAttributes(root, ids);
182
183 for (Element emt : root.getChildren()) {
184 getIds(emt, ids);
185 }
186 return ids;
187 }
188
189 /**
190 * <p>
191 * Gets the ID attribute for <code>elt</code> and adds the
192 * correpsonding entries in the ID mapping table
193 * <code>ids</code>.</p>
194 *
195 * @param elt the element to the ID attributes from.
196 * @param ids the ID lookup table to populate.
197 */
198 private static void addIdAttributes(Element elt, Map<String,Element> ids) {
199 for (Attribute attr : elt.getAttributes()) {
200 if (attr.getAttributeType() == Attribute.ID_TYPE) {
201 ids.put(attr.getValue(), elt);
202 break;
203 }
204 }
205 return;
206 }
207 }
208
0 /*--
1
2 Copyright (C) 2001-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.ids;
55
56 import org.jdom.Attribute;
57 import org.jdom.AttributeType;
58 import org.jdom.Document;
59 import org.jdom.DocType;
60 import org.jdom.Element;
61 import org.jdom.Namespace;
62 import org.jdom.DefaultJDOMFactory;
63
64 /**
65 * The <code>IdFactory</code> extends the default JDOM factory to
66 * build documents that support looking up elements using their ID
67 * attribute.
68 * <p>
69 * Looking-up elements by ID only works if a DTD is associated to
70 * the XML document as the information defining some attributes as
71 * IDs is only available from the DTD and not from the XML document
72 * itself.</p>
73 * <p>
74 * The Documents created by this factory are instances of
75 * {@link IdDocument} which provides the method
76 * {@link IdDocument#getElementById} to look up an element given the
77 * value of its ID attribute.</p>
78 * <p>
79 * The following code snippet demonstrates how to use the
80 * <code>IdFactory</code> with JDOM's SAXBuilder to create an
81 * <code>IdDocument</code>.</p>
82 * <blockquote><pre>
83 * SAXBuilder builder = new SAXBuilder();
84 * builder.setFactory(new IdFactory());
85 *
86 * IdDocument doc = (IdDocument)(builder.build(xmlDocument));
87 *
88 * Element elt = doc.getElementById(idValue);
89 * </pre></blockquote>
90 *
91 * @author Laurent Bihanic
92 */
93 public class IdFactory extends DefaultJDOMFactory {
94
95 /**
96 * Creates a new IdFactory object.
97 */
98 public IdFactory() {
99 super();
100 }
101
102 // Allow Javadocs to inherit from superclass
103
104 @Override
105 public Attribute attribute(String name, String value, Namespace namespace) {
106 return new IdAttribute(name, value, namespace);
107 }
108
109 @Override
110 public Attribute attribute(String name, String value,
111 AttributeType type, Namespace namespace) {
112 return new IdAttribute(name, value, type, namespace);
113 }
114
115 @Override
116 public Attribute attribute(String name, String value) {
117 return new IdAttribute(name, value);
118 }
119
120 @Override
121 public Attribute attribute(String name, String value, AttributeType type) {
122 return new IdAttribute(name, value, type);
123 }
124
125 @Override
126 public Document document(Element rootElement, DocType docType) {
127 return new IdDocument(rootElement, docType);
128 }
129 @Override
130 public Document document(Element rootElement) {
131 return new IdDocument(rootElement);
132 }
133
134 @Override
135 public Element element(final int line, final int col, String name, Namespace namespace) {
136 return new IdElement(name, namespace);
137 }
138 @Override
139 public Element element(final int line, final int col, String name) {
140 return new IdElement(name);
141 }
142 @Override
143 public Element element(final int line, final int col, String name, String uri) {
144 return new IdElement(name, uri);
145 }
146 @Override
147 public Element element(final int line, final int col, String name, String prefix, String uri) {
148 return new IdElement(name, prefix, uri);
149 }
150 }
151
0
1 This package demonstrates how to use the attribute type support provided
2 by JDOM to create JDOM documents that allow looking up elements using
3 the value of their ID attribute.
4 Note that for an attribute to be recognized as an ID, the XML document
5 must be associated to a DTD which defines the type of the attributes.
6
7 For detailed information, please refer to the package Javadoc documentation
8 or the file "package.html" in this directory.
9
10
11 The "doc-files" directory contains simple test cases that demonstrate how
12 to use the IdFactory to build an IdDocument and how to retrieve an element
13 by its ID from an IdDocument:
14
15 - TestIds.java is a simple program that builds an IdDocument from the
16 filename passed as first argument and looks up the element whose ID
17 value matches the second argument.
18 Usage: java TestIds <XML file> <ID>
19
20 - testIds.xml is an example of XML file that can be used with the above
21 sample. It is associated to the DTD "testIds.dtd" which defines which
22 attributes are IDs.
23
24
25 -- Laurent Bihanic
0 /*--
1
2 Copyright (C) 2002-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55 import org.jdom.*;
56 import org.jdom.input.SAXBuilder;
57 import org.jdom.output.*;
58
59 import org.jdom.contrib.ids.IdDocument;
60 import org.jdom.contrib.ids.IdFactory;
61
62
63 @SuppressWarnings("javadoc")
64 public class TestIds {
65
66 public static void main(String[] args) throws Exception {
67 if (args.length < 2) {
68 System.out.println("Usage: java TestIds <XML file> <ID>");
69 System.exit(2);
70 }
71
72 SAXBuilder builder = new SAXBuilder();
73 builder.setJDOMFactory(new IdFactory());
74
75 IdDocument doc = (IdDocument)(builder.build(args[0]));
76 Element elt = doc.getElementById(args[1]);
77
78 if (elt != null) {
79 new XMLOutputter2(Format.getPrettyFormat()).output(elt, System.out);
80 System.out.println();
81 System.exit(0);
82 }
83 else {
84 System.out.println("No element with ID \"" + args[1] + "\" found");
85 System.exit(1);
86 }
87 }
88 }
89
0 <!ELEMENT catalog (entry*)>
1 <!ATTLIST catalog
2 name CDATA #REQUIRED
3 version CDATA #REQUIRED
4 indexID IDREF #IMPLIED
5 >
6
7 <!ELEMENT entry (#PCDATA)>
8 <!ATTLIST entry
9 price CDATA #REQUIRED
10 currency (USD | EUR) #REQUIRED
11 name ID #REQUIRED
12 >
13
0 <?xml version="1.0" encoding="UTF-8"?>
1
2 <!DOCTYPE catalog SYSTEM "testIds.dtd" [
3 <!ENTITY nbsp "&#160;">
4 ]>
5
6 <catalog name="Test IdDocument" version="0.4" indexID="t">
7 <entry name="a" price="1.0" currency="EUR">entry A</entry>
8 <entry name="b" price="1.25" currency="USD">entry B</entry>
9 <entry name="c" price="3.0" currency="USD">entry C</entry>
10 <entry name="d" price="4.75" currency="USD">entry D</entry>
11 <entry name="e" price="5.0" currency="EUR">entry E</entry>
12 <entry name="f" price="5.50" currency="USD">entry F</entry>
13 <entry name="g" price="2.75" currency="USD">entry G</entry>
14 <entry name="h" price="7.0" currency="USD">entry H</entry>
15 <entry name="i" price="2.45" currency="USD">entry I</entry>
16 <entry name="j" price="10.0" currency="EUR">entry J</entry>
17 <entry name="k" price="6.05" currency="USD">entry K</entry>
18 <entry name="l" price="1.33" currency="USD">entry L</entry>
19 <entry name="m" price="4.48" currency="USD">entry M</entry>
20 <entry name="n" price="6.87" currency="USD">entry N</entry>
21 <entry name="o" price="15.0" currency="EUR">entry O</entry>
22 <entry name="p" price="18.0" currency="USD">entry P</entry>
23 <entry name="q" price="12.0" currency="USD">entry Q</entry>
24 <entry name="r" price="1.10" currency="USD">entry R</entry>
25 <entry name="s" price="2.50" currency="USD">entry S</entry>
26 <entry name="t" price="20.0" currency="EUR">entry T</entry>
27 <entry name="u" price="12.0" currency="USD">entry U</entry>
28 <entry name="v" price="1.88" currency="USD">entry V</entry>
29 <entry name="w" price="2.63" currency="USD">entry W</entry>
30 <entry name="x" price="9.0" currency="USD">entry X</entry>
31 <entry name="y" price="25.0" currency="EUR">entry Y</entry>
32 <entry name="z" price="26.0" currency="EUR">entry Z</entry>
33 </catalog>
34
0 <html>
1 <body>
2 Provides support for Documents allowing looking up elements using
3 the value of their ID attribute.
4 <p>
5 ID attributes are define in DTDs. Hence, the lookup features
6 provided by this package are available only for XML documents
7 associated to a DTD and only for the elements for which the DTD
8 defines an ID attribute.</p>
9 <p>
10 Please refer to <a href="IdFactory.html">IdFactory</a> for details
11 on how to use IdFactory within an application.</p>
12 <p>
13 A sample application is provided
14 <a href="doc-files/TestIds.java">here</a>, with an example
15 <a href="doc-files/testIds.xml">XML file</a> and its
16 <a href="doc-files/testIds.dtd">DTD</a>.</p>
17 </body>
18 </html>
19
0 /*--
1
2 Copyright (C) 2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.input;
55
56 import org.jdom.Element;
57 import org.jdom.Namespace;
58
59 /**
60 * This class extends a normal Element with a traceback to its
61 * beginning and endling line number, if available and reported.
62 * <p>
63 * Each instance is created using a factory internal to the
64 * LineNumberSAXBuilder class.
65 *
66 * @author Per Norrman
67 *
68 */
69 @SuppressWarnings("javadoc")
70 public class LineNumberElement extends Element
71 {
72 /**
73 * Default.
74 */
75 private static final long serialVersionUID = 1L;
76
77 private int _startLine;
78 private int _endLine;
79
80 public LineNumberElement(String name) {
81 super(name);
82 }
83
84 public LineNumberElement()
85 {
86 super();
87 }
88
89 public LineNumberElement(String name, String uri)
90 {
91 super(name, uri);
92 }
93
94 public LineNumberElement(String name, String prefix, String uri)
95 {
96 super(name, prefix, uri);
97 }
98
99 public LineNumberElement(String name, Namespace namespace) {
100 super(name, namespace);
101 }
102
103
104
105 public int getEndLine()
106 {
107 return _endLine;
108 }
109
110 public int getStartLine()
111 {
112 return _startLine;
113 }
114
115 public void setEndLine(int i)
116 {
117 _endLine = i;
118 }
119
120 public void setStartLine(int i)
121 {
122 _startLine = i;
123 }
124
125 }
0 /*--
1
2 Copyright (C) 2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.input;
55
56 import org.xml.sax.Attributes;
57 import org.xml.sax.Locator;
58 import org.xml.sax.SAXException;
59
60 import org.jdom.DefaultJDOMFactory;
61 import org.jdom.Element;
62 import org.jdom.JDOMFactory;
63 import org.jdom.Namespace;
64 import org.jdom.input.sax.SAXHandler;
65 import org.jdom.input.sax.SAXHandlerFactory;
66
67 /**
68 * This builder works in parallell with {@link LineNumberElement}
69 * to provide each element with information on its beginning and
70 * ending line number in the corresponding source.
71 * This only works for SAX parsers that supply that information, and
72 * since this is optional, there are no guarantees.
73 * <p>
74 * Note that this builder always creates its own for each
75 * build, thereby cancelling any previous call to setFactory.
76 * <p>
77 * All elements created are instances of {@link LineNumberElement}.
78 * No other construct currently receive line number information.
79 *
80 * @author Per Norrman
81 *
82 */
83 public class LineNumberSAXHandler extends SAXHandler {
84
85 /**
86 * A SAXHandlerFactory that can be used to supply LineNumberSAXHandler
87 * instances to SAXBuilder.
88 */
89 public static final SAXHandlerFactory SAXFACTORY = new SAXHandlerFactory() {
90 @Override
91 public SAXHandler createSAXHandler(JDOMFactory factory) {
92 // ignore input factory, we use our own.
93 return new LineNumberSAXHandler();
94 }
95 };
96
97 private static class MyJDOMFactory extends DefaultJDOMFactory {
98
99 @Override
100 public Element element(final int line, final int col, String name)
101 {
102 return new LineNumberElement(name);
103 }
104
105 @Override
106 public Element element(final int line, final int col, String name, String prefix, String uri)
107 {
108 return new LineNumberElement(name, prefix, uri);
109 }
110
111 @Override
112 public Element element(final int line, final int col, String name, Namespace namespace)
113 {
114 return new LineNumberElement(name, namespace);
115 }
116
117 @Override
118 public Element element(final int line, final int col, String name, String uri)
119 {
120 return new LineNumberElement(name, uri);
121 }
122
123 }
124
125 /**
126 * Create a new instance of the LineNumberSAXHandler.
127 */
128 public LineNumberSAXHandler()
129 {
130 super(new MyJDOMFactory());
131 }
132
133 /** override */
134 @Override
135 public void startElement(
136 String arg0,
137 String arg1,
138 String arg2,
139 Attributes arg3)
140 throws SAXException
141 {
142 super.startElement(arg0, arg1, arg2, arg3);
143 Locator l = getDocumentLocator();
144 if (l != null)
145 {
146 ((LineNumberElement) getCurrentElement()).setStartLine(
147 l.getLineNumber());
148 }
149 }
150
151 /** override */
152 @Override
153 public void endElement(String arg0, String arg1, String arg2)
154 throws SAXException
155 {
156 Locator l = getDocumentLocator();
157 if (l != null)
158 {
159 ((LineNumberElement) getCurrentElement()).setEndLine(
160 l.getLineNumber());
161 }
162
163 super.endElement(arg0, arg1, arg2);
164 }
165
166 }
0 Location for development of experimental JDOM builders.
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.input;
55
56 import java.sql.*;
57 import java.text.*;
58 import java.util.*;
59
60 import org.jdom.*;
61
62 /**
63 * <p><code>ResultSetBuilder</code> builds a JDOM tree from a
64 * <code>java.sql.ResultSet</code>. Many good ideas were leveraged from
65 * SQLBuilder written from Jon Baer.</p>
66 *
67 * Notes:
68 * Uses name returned by rsmd.getColumnName(), not getColumnLabel()
69 * because that is less likely to be a valid XML element title.
70 * Null values are given empty bodies, but you can mark them as empty with
71 * an attribute using the setNullAttribute() method. Be aware that databases
72 * may change the case of column names. setAsXXX() methods are case
73 * insensitive on input column name. Assign each one a proper output name
74 * if you're worried. Only build() throws JDOMException. Any exceptions
75 * encountered in the set methods are thrown during the build().
76 * The setAsXXX(String columnName, ...) methods do not verify that a column
77 * with the given name actually exists.
78 *
79 * Still needs method-by-method Javadocs.
80 * <p>
81 * Issues:
82 * Do attributes have to be added in a namespace?
83 *
84 * @author Jason Hunter
85 * @author Jon Baer
86 * @author David Bartle
87 * @author Robert J. Munro
88 * @version 0.5
89 */
90 @SuppressWarnings("javadoc")
91 public class ResultSetBuilder {
92
93 /** The ResultSet that becomes a <code>Document</code> */
94 private ResultSet rs;
95
96 /** The meta data from the ResultSet */
97 private ResultSetMetaData rsmd;
98
99 /** Allows for throwing an exception whenever needed if caught early on */
100 private SQLException exception;
101
102 /** Map of original column names to display names */
103 private Map<String,String> names = new HashMap<String, String>();
104
105 /**
106 * Maps column data to be located either as an <code>Attribute</code> of
107 * the row (if in the Map) or a child <code>Element</code> of the row
108 * (if not in the Map)
109 */
110 private Map<String, Boolean> attribs = new HashMap<String, Boolean>();
111
112 /** The <code>Namespace</code> to use for each <code>Element</code> */
113 private Namespace ns = Namespace.NO_NAMESPACE;
114
115 /** The maximum rows to return from the result set */
116 int maxRows = Integer.MAX_VALUE; // default to all
117
118 /** Name for the root <code>Element</code> of the <code>Document</code> */
119 private String rootName = "result";
120
121 /** Name for the each immediate child <code>Element</code> of the root */
122 private String rowName = "entry";
123
124 /** Name for attribute to mark that a field was null */
125 private String nullAttribName = null;
126
127 /** Value for attribute to mark that a field was null */
128 private String nullAttribValue = null;
129
130 /**
131 * <p>
132 * This sets up a <code>java.sql.ResultSet</code> to be built
133 * as a <code>Document</code>.
134 * </p>
135 *
136 * @param rs <code>java.sql.ResultSet</code> to build
137 */
138 public ResultSetBuilder(ResultSet rs) {
139 this.rs = rs;
140 try {
141 rsmd = rs.getMetaData();
142 }
143 catch (SQLException e) {
144 // Hold the exception until build() is called
145 exception = e;
146 }
147 }
148
149 /**
150 * <p>
151 * This sets up a <code>java.sql.ResultSet</code> to be built
152 * as a <code>Document</code>.
153 * </p>
154 *
155 * @param rs <code>java.sql.ResultSet</code> to build from
156 * @param rootName <code>String</code> name for the root
157 * <code>Element</code>
158 * of the <code>Document</code>
159 * @param rowName <code>String</code> name for the each immediate child
160 * <code>Element</code> of the root
161 */
162 public ResultSetBuilder(ResultSet rs, String rootName, String rowName) {
163 this(rs);
164 setRootName(rootName);
165 setRowName(rowName);
166 }
167
168 /**
169 * <p>
170 * This sets up a <code>java.sql.ResultSet</code> to be built
171 * as a <code>Document</code>.
172 * </p>
173 *
174 * @param rs <code>java.sql.ResultSet</code> to build from
175 * @param rootName <code>String</code> name for the root
176 * <code>Element</code>
177 * of the <code>Document</code>
178 * @param rowName <code>String</code> name for the each immediate child
179 * <code>Element</code> of the root
180 * @param ns <code>Namespace</code> to use for each <code>Element</code>
181 */
182 public ResultSetBuilder(ResultSet rs,
183 String rootName, String rowName, Namespace ns) {
184 this(rs, rootName, rowName);
185 setNamespace(ns);
186 }
187
188 /**
189 * <p>
190 * This builds a <code>Document</code> from the
191 * <code>java.sql.ResultSet</code>.
192 * </p>
193 *
194 * @return <code>Document</code> - resultant Document object.
195 * @throws <code>JDOMException</code> when there is a problem
196 * with the build.
197 *
198 */
199 public Document build() throws JDOMException {
200 if (exception != null) {
201 throw new JDOMException("Database problem", exception);
202 }
203
204 try {
205 int colCount = rsmd.getColumnCount();
206
207 Element root = new Element(rootName, ns);
208 Document doc = new Document(root);
209
210 int rowCount = 0;
211
212 // get the column labels for this record set
213 String[] columnName = new String[colCount];
214 for (int index = 0; index < colCount; index++) {
215 columnName[index] = rsmd.getColumnName(index+1);
216 }
217
218 // build the org.jdom.Document out of the result set
219 String name;
220 String value;
221 Element entry;
222 Element child;
223
224 while (rs.next() && (rowCount++ < maxRows)) {
225 entry = new Element(rowName, ns);
226 for (int col = 1; col <= colCount; col++) {
227 if (names.isEmpty()) {
228 name = columnName[col-1];
229 }
230 else {
231 name = lookupName(columnName[col-1]);
232 }
233
234 value = getString(rs, col, rsmd.getColumnType(col));
235 if (!attribs.isEmpty() && isAttribute(columnName[col-1])) {
236 if (!rs.wasNull()) {
237 entry.setAttribute(name, value);
238 }
239 }
240 else {
241 child = new Element(name, ns);
242 if (!rs.wasNull()) {
243 child.setText(value);
244 } else {
245 if (nullAttribName != null) {
246 child.setAttribute(nullAttribName, nullAttribValue);
247 }
248 }
249 entry.addContent(child);
250 }
251 }
252 root.addContent(entry);
253 }
254
255 return doc;
256 }
257 catch (SQLException e) {
258 throw new JDOMException("Database problem", e);
259 }
260 }
261
262 protected String getString(ResultSet prs, int column, int columnType)
263 throws SQLException {
264 if (columnType == Types.TIMESTAMP) {
265 Timestamp timeStamp = prs.getTimestamp(column);
266 if (timeStamp != null) {
267 return DateFormat.getDateTimeInstance(DateFormat.FULL,
268 DateFormat.FULL).format(timeStamp);
269 }
270 }
271 if (columnType == Types.DATE) {
272 java.sql.Date date = prs.getDate(column);
273 if (date != null) {
274 return DateFormat.getDateInstance(DateFormat.FULL).format(date);
275 }
276 }
277 if (columnType == Types.TIME) {
278 java.sql.Time time = prs.getTime(column);
279 if (time != null) {
280 return DateFormat.getTimeInstance(DateFormat.FULL).format(time);
281 }
282 }
283 return prs.getString(column);
284 }
285
286 private String lookupName(String origName) {
287 String name = names.get(origName.toLowerCase());
288 if (name != null) {
289 return name;
290 }
291 return origName;
292 }
293
294 private boolean isAttribute(String origName) {
295 Boolean val = attribs.get(origName.toLowerCase());
296 if (val == Boolean.TRUE) {
297 return true;
298 }
299 return false;
300 }
301
302 /**
303 * Set the name to use as the root element in
304 * the <code>Document</code>.
305 *
306 * @param rootName <code>String</code> the new name.
307 *
308 */
309 public void setRootName(String rootName) {
310 this.rootName = rootName;
311 }
312
313 /**
314 * Set the name to use as the row element in
315 * the <code>Document</code>.
316 *
317 * @param rowName <code>String</code> the new name.
318 *
319 */
320 public void setRowName(String rowName) {
321 this.rowName = rowName;
322 }
323
324 /**
325 * <p>
326 * Set the <code>Namespace</code> to use for
327 * each <code>Element</code> in the <code>Document</code>.
328 * </p>
329 *
330 * @param ns <code>String</code> the namespace to use.
331 *
332 */
333 public void setNamespace(Namespace ns) {
334 this.ns = ns;
335 }
336
337 /**
338 * <p>
339 * Set the maximum number of rows to add to your
340 * <code>Document</code>.
341 * </p>
342 *
343 * @param maxRows <code>int</code>
344 *
345 */
346 public void setMaxRows(int maxRows) {
347 this.maxRows = maxRows;
348 }
349
350 /**
351 * <p>
352 * Set a column as an <code>Attribute</code> of a row using the
353 * original column name. The attribute will appear as the original
354 * column name.
355 * </p>
356 *
357 * @param columnName <code>String</code> the original column name
358 *
359 */
360 public void setAsAttribute(String columnName) {
361 attribs.put(columnName.toLowerCase(), Boolean.TRUE);
362 }
363
364 /**
365 * <p>
366 * Set a column as an <code>Attribute</code> of a row using the
367 * column name. The attribute will appear as the new name provided.
368 * </p>
369 *
370 * @param columnName <code>String</code> original column name
371 * @param attribName <code>String</code> new name to use for the attribute
372 *
373 */
374 public void setAsAttribute(String columnName, String attribName) {
375 attribs.put(columnName.toLowerCase(), Boolean.TRUE);
376 names.put(columnName.toLowerCase(), attribName);
377 }
378
379 /**
380 * <p>
381 * Set a column as an <code>Attribute</code> of a row using the
382 * column number. The attribute will appear as the original column
383 * name.
384 * </p>
385 *
386 * @param columnNum <code>int</code>
387 *
388 */
389 public void setAsAttribute(int columnNum) {
390 try {
391 String name = rsmd.getColumnName(columnNum).toLowerCase();
392 attribs.put(name, Boolean.TRUE);
393 }
394 catch (SQLException e) {
395 exception = e;
396 }
397 }
398
399 /**
400 * <p>
401 * Set a column as an <code>Attribute</code> of a row using the
402 * column number. The attribute will appear as new name provided.
403 * </p>
404 *
405 * @param columnNum <code>int</code>
406 * @param attribName <code>String</code> new name to use for the attribute
407 *
408 */
409 public void setAsAttribute(int columnNum, String attribName) {
410 try {
411 String name = rsmd.getColumnName(columnNum).toLowerCase();
412 attribs.put(name, Boolean.TRUE);
413 names.put(name, attribName);
414 }
415 catch (SQLException e) {
416 exception = e;
417 }
418 }
419
420 /**
421 * <p>
422 * Set a column as an <code>Element</code> of a row using the
423 * column name. The element name will appear as the new name provided.
424 * </p>
425 *
426 * @param columnName <code>String</code> original column name
427 * @param elemName <code>String</code> new name to use for the element
428 *
429 */
430 public void setAsElement(String columnName, String elemName) {
431 String name = columnName.toLowerCase();
432 attribs.put(name, Boolean.FALSE);
433 names.put(name, elemName);
434 }
435
436 /**
437 * <p>
438 * Set a column as an <code>Element</code> of a row using the
439 * column number. The element name will appear as new name provided.
440 * </p>
441 *
442 * @param columnNum <code>int</code>
443 * @param elemName <code>String</code> new name to use for the element
444 *
445 */
446 public void setAsElement(int columnNum, String elemName) {
447 try {
448 String name = rsmd.getColumnName(columnNum).toLowerCase();
449 attribs.put(name, Boolean.FALSE);
450 names.put(name, elemName);
451 }
452 catch (SQLException e) {
453 exception = e;
454 }
455 }
456
457 /**
458 * <p>
459 * Set a specific attribute to use to mark that a value in the
460 * database was null, not just an empty string. This is necessary
461 * because &lt;foo/&gt; semantically represents both null and empty.
462 * This method lets you have &lt;foo null="true"&gt;.
463 * </p>
464 *
465 * @param nullAttribName <code>String</code> name of attribute to add
466 * @param nullAttribValue <code>String</code> value to set it to.
467 *
468 */
469 public void setNullAttribute(String nullAttribName,
470 String nullAttribValue) {
471 this.nullAttribName = nullAttribName;
472 this.nullAttribValue = nullAttribValue;
473 }
474
475 /*
476 public void setAsIngore(String columnName) {
477 }
478
479 public void setAsIngore(int columnNum) {
480 }
481 */
482
483 }
0 /*--
1
2 Copyright (C) 2001-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.input.scanner;
55
56 import org.jdom.Element;
57 import org.jdom.JDOMException;
58
59 /**
60 * The interface objects listening for element creation notification
61 * fired by {@link ElementScanner} shall implement.
62 *
63 * @author Laurent Bihanic
64 */
65 public interface ElementListener {
66
67 /**
68 * Notifies of the parsing of an Element.
69 * <p>
70 * <code>ElementScanner</code> invokes this method when
71 * encountering the closing tag of the element definition. Thus,
72 * element <code>e</code> and all its child nodes are fully built
73 * but the parent element is not.</p>
74 * <p>
75 * Note that the element is not attached to any
76 * {@link Element#getDocument document} and that the
77 * {@link Element#getParent() parent element} is <code>null</code>
78 * unless another listener is listening on one of the element
79 * ancestors.</p>
80 * <p>
81 * As no copy of the notified elements is performed, all changes
82 * made on element <code>e</code> will be visible of the
83 * not-yet-notified listeners listening on this same element and
84 * of the listeners listening on one of the element ancestors.</p>
85 *
86 * @param path the path to the parsed element.
87 * @param e the parsed <code>Element</code>.
88 *
89 * @throws JDOMException if the listener wishes to abort the
90 * parsing of the input XML document.
91 */
92 abstract public void elementMatched(String path, Element e)
93 throws JDOMException;
94 }
95
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.input.scanner;
55
56 import java.io.IOException;
57 import java.util.*;
58
59 import org.xml.sax.Attributes;
60 import org.xml.sax.ContentHandler;
61 import org.xml.sax.InputSource;
62 import org.xml.sax.XMLReader;
63 import org.xml.sax.SAXException;
64 import org.xml.sax.SAXNotRecognizedException;
65 import org.xml.sax.SAXNotSupportedException;
66 import org.xml.sax.helpers.XMLFilterImpl;
67
68 import org.jdom.*;
69 import org.jdom.input.SAXBuilder;
70 import org.jdom.input.sax.XMLReaders;
71 import org.jdom.input.sax.XMLReaderJDOMFactory;
72 import org.jdom.input.sax.SAXHandler;
73 import org.jdom.input.sax.SAXHandlerFactory;
74
75 /**
76 * An XML filter that uses XPath-like expressions to select the
77 * element nodes to build and notifies listeners when these
78 * elements becomes available during the parse.
79 * <p>
80 * ElementScanner does not aim at providing a faster parsing of XML
81 * documents. Its primary focus is to allow the application to
82 * control the parse and to consume the XML data while they are
83 * being parsed. ElementScanner can be viewed as a high-level SAX
84 * parser that fires events conveying JDOM {@link Element elements}
85 * rather that XML tags and character data.</p>
86 * <p>
87 * ElementScanner only notifies of the parsing of element nodes and
88 * does not support reporting the parsing of DOCTYPE data, processing
89 * instructions or comments except for those present within the
90 * selected elements. Application needing such data shall register
91 * a specific {@link ContentHandler} of this filter to receive them
92 * in the form of raw SAX events.</p>
93 * <p>
94 * To be notified of the parsing of JDOM Elements, an application
95 * shall {@link #addElementListener register} objects implementing
96 * the {@link ElementListener} interface. For each registration,
97 * an XPath-like expression defines the elements to be parsed and
98 * reported.</p>
99 * <p>
100 * Opposite to XPath, there is no concept of <i>current context</i>
101 * or <i>current node</i> in ElementScanner. And thus, the syntax
102 * of the "XPath-like expressions" is not as strict as in XPath and
103 * closer to what one uses in XSLT stylesheets in the
104 * <code>match</code> specification of the XSL templates:<br>
105 * In ElementScanner, the expression "<code>x</code>" matches any
106 * element named &quot;x&quot; at any level of the document and not
107 * only the root element (as expected in strict XPath if the
108 * document is considered the <i>current context</i>). Thus, in
109 * ElementScanner, "<code>x</code>" is equivalent to
110 * "<code>//x</code>".</p>
111 * <p>
112 * Example:
113 * <blockquote><pre>
114 * ElementScanner f = new ElementScanner();
115 *
116 * // All descendants of x named y
117 * f.addElementListener(new MyImpl(), "x//y");
118 * // All grandchilden of y named t
119 * f.addElementListener(new MyImpl(), "y/*&thinsp;/t");
120 *
121 * ElementListener l2 = new MyImpl2();
122 * f.addElementListener(l2, "/*"); // Root element
123 * f.addElementListener(l2, "z"); // Any node named z
124 *
125 * ElementListener l3 = new MyImpl3();
126 * // Any node having an attribute "name" whose value contains ".1"
127 * f.addElementListener(l3, "*[contains(@name,'.1')]");
128 * // Any node named y having at least one "y" descendant
129 * f.addElementListener(l3, "y[.//y]");
130 *
131 * f.parse(new InputSource("test.xml"));
132 * </pre></blockquote>
133 * </p>
134 * <p>
135 * The XPath interpreter can be changed (see {@link XPathMatcher}).
136 * The default implementation is a mix of the
137 * <a href="http://jakarta.apache.org/regexp/index.html">Jakarta
138 * RegExp package</a> and the
139 * <a href="http://www.jaxen.org">Jaxen XPath interpreter</a>.</p>
140 * <p>
141 * ElementScanner splits XPath expressions in 2 parts: a node
142 * selection pattern and an optional test expression (the part of
143 * the XPath between square backets that follow the node selection
144 * pattern).</p>
145 * <p>
146 * Regular expressions are used to match nodes applying the node
147 * selection pattern. This allows matching node without requiring to
148 * build them (as Jaxen does).<br>
149 * If a test expression appears in an XPath expression, Jaxen is used
150 * to match the built elements against it and filter out those not
151 * matching the test.</p>
152 * <p>
153 * As a consequence of using regular expressions, the <i>or</i>"
154 * operator ("<code>|</code>" in XPath) is not supported in node
155 * selection patterns but can be achieved by registering the same
156 * listener several times with different node patterns.</p>
157 * <p>
158 * <strong>Note</strong>: The methods marked with
159 * "<i>[ContentHandler interface support]</i>" below shall not be
160 * invoked by the application. Their usage is reserved to
161 * the XML parser.</p>
162 *
163 * @author Laurent Bihanic
164 */
165 @SuppressWarnings("javadoc")
166 public class ElementScanner extends XMLFilterImpl {
167
168 /**
169 * The registered element listeners, each wrapped in a
170 * XPathMatcher instance.
171 */
172 private final Collection<XPathMatcher> listeners = new ArrayList<XPathMatcher>();
173
174 /**
175 * The <i>SAXBuilder</i> instance to build the JDOM objects used
176 * for parsing the input XML documents. We actually do not need
177 * SAXBuilder per se, we just want to reuse the tons of Java code
178 * this class implements!
179 */
180 private SAXBuilder parserBuilder = new SAXBuilder();
181
182 /**
183 * The <i>SAXHandler</i> instance to build the JDOM Elements.
184 */
185 private SAXHandler saxHandler = null;
186
187 /**
188 * The path of the being parsed element.
189 */
190 private StringBuilder currentPath = new StringBuilder();
191
192 /**
193 * The matching rules active for the current path. It includes
194 * the matching rules active for all the ancestors of the
195 * current node.
196 */
197 private Map<String,Collection<XPathMatcher>> activeRules = new HashMap<String, Collection<XPathMatcher>>();
198
199 /**
200 * Construct an ElementScanner, with no parent.
201 * <p>
202 * If no parent has been assigned when {@link #parse} is invoked,
203 * ElementScanner will use JAXP to get an instance of the default
204 * SAX parser installed.</p>
205 */
206 public ElementScanner() {
207 super();
208 }
209
210 /**
211 * Constructs an ElementScanner with the specified parent.
212 */
213 public ElementScanner(XMLReader parent) {
214 super(parent);
215 }
216
217 //-------------------------------------------------------------------------
218 // Specific implementation
219 //-------------------------------------------------------------------------
220
221 /**
222 * Adds a new element listener to the list of listeners
223 * maintained by this filter.
224 * <p>
225 * The same listener can be registered several times using
226 * different patterns and several listeners can be registered
227 * using the same pattern.</p>
228 *
229 * @param listener the element listener to add.
230 * @param pattern the XPath expression to select the elements
231 * the listener is interested in.
232 *
233 * @throws JDOMException if <code>listener</code> is null or
234 * the expression is invalid.
235 */
236 public void addElementListener(ElementListener listener, String pattern)
237 throws JDOMException {
238 if (listener != null) {
239 this.listeners.add(XPathMatcher.newXPathMatcher(pattern, listener));
240 }
241 else {
242 throw (new JDOMException("Invalid listener object: <null>"));
243 }
244 }
245
246 /**
247 * Removes element listeners from the list of listeners maintained
248 * by this filter.
249 * <p>
250 * if <code>pattern</code> is <code>null</code>, this method
251 * removes all registrations of <code>listener</code>, regardless
252 * the pattern(s) used for creating the registrations.</p>
253 * <p>
254 * if <code>listener</code> is <code>null</code>, this method
255 * removes all listeners registered for <code>pattern</code>.</p>
256 * <p>
257 * if both <code>listener</code> and <code>pattern</code> are
258 * <code>null</code>, this method performs no action!</p>
259 *
260 * @param listener the element listener to remove.
261 */
262 public void removeElementListener(ElementListener listener, String pattern) {
263 if ((listener != null) || (pattern != null)) {
264 for (Iterator<XPathMatcher> i=this.listeners.iterator(); i.hasNext(); ) {
265 XPathMatcher m = i.next();
266
267 if (((m.getListener().equals(listener)) || (listener == null)) &&
268 ((m.getExpression().equals(pattern)) || (pattern == null))) {
269 i.remove();
270 }
271 }
272 }
273 // Else: Both null => Just ignore that dummy call!
274 }
275
276 /**
277 * Returns the list of rules that match the element path and
278 * attributes.
279 *
280 * @param path the current element path.
281 * @param attrs the attributes of the element.
282 *
283 * @return the list of matching rules or <code>null</code> if
284 * no match was found.
285 */
286 private Collection<XPathMatcher> getMatchingRules(String path, Attributes attrs) {
287 Collection<XPathMatcher> matchingRules = null;
288
289 for (XPathMatcher rule : this.listeners) {
290 if (rule.match(path, attrs)) {
291 if (matchingRules == null) {
292 matchingRules = new ArrayList<XPathMatcher>();
293 }
294 matchingRules.add(rule);
295 }
296 }
297 return (matchingRules);
298 }
299
300 //-------------------------------------------------------------------------
301 // SAXBuilder / SAXHandler configuration helper methods
302 //-------------------------------------------------------------------------
303
304 /**
305 * Sets a custom JDOMFactory for the builder. Use this to build
306 * the tree with your own subclasses of the JDOM classes.
307 *
308 * @param factory <code>JDOMFactory</code> to use.
309 */
310 public void setFactory(JDOMFactory factory) {
311 this.parserBuilder.setJDOMFactory(factory);
312 }
313
314 /**
315 * Activates or deactivates validation for the builder.
316 *
317 * @param validate whether XML validation should occur.
318 */
319 public void setValidation(boolean validate) {
320 if (validate)
321 this.parserBuilder.setXMLReaderFactory(XMLReaders.DTDVALIDATING);
322 else
323 this.parserBuilder.setXMLReaderFactory(XMLReaders.NONVALIDATING);
324 }
325
326 /**
327 * Specifies whether or not the parser should elminate whitespace
328 * in element content (sometimes known as "ignorable whitespace")
329 * when building the document. Only whitespace which is contained
330 * within element content that has an element only content model
331 * will be eliminated (see XML Rec 3.2.1). For this setting to
332 * take effect requires that validation be turned on.
333 * <p>
334 * The default value is <code>false</code>.</p>
335 *
336 * @param ignoringWhite whether to ignore ignorable whitespace.
337 */
338 public void setIgnoringElementContentWhitespace(boolean ignoringWhite) {
339 this.parserBuilder.setIgnoringElementContentWhitespace(ignoringWhite);
340 }
341
342 /**
343 * Sets whether or not to expand entities for the builder.
344 * <p>
345 * A value <code>true</code> means to expand entities as normal
346 * content; <code>false</code> means to leave entities unexpanded
347 * as <code>EntityRef</code> objects.</p>
348 * <p>
349 * The default value is <code>true</code>.</p>
350 *
351 * @param expand whether entity expansion should occur.
352 */
353 public void setExpandEntities(boolean expand) {
354 this.parserBuilder.setExpandEntities(expand);
355 }
356
357 //-------------------------------------------------------------------------
358 // XMLFilterImpl overwritten methods
359 //-------------------------------------------------------------------------
360
361 //-------------------------------------------------------------------------
362 // XMLReader interface support
363 //-------------------------------------------------------------------------
364
365 /**
366 * Sets the state of a feature.
367 *
368 * @param name the feature name, which is a fully-qualified
369 * URI.
370 * @param state the requested state of the feature.
371 *
372 * @throws SAXNotRecognizedException when the XMLReader does not
373 * recognize the feature name.
374 * @throws SAXNotSupportedException when the XMLReader
375 * recognizes the feature name but cannot set the
376 * requested value.
377 */
378 @Override
379 public void setFeature(String name, boolean state)
380 throws SAXNotRecognizedException, SAXNotSupportedException {
381 if (this.getParent() != null) {
382 this.getParent().setFeature(name, state);
383 }
384 this.parserBuilder.setFeature(name, state);
385 }
386
387 /**
388 * Set the value of a property.
389 *
390 * @param name the property name, which is a fully-qualified
391 * URI.
392 * @param value the requested value for the property.
393 *
394 * @throws SAXNotRecognizedException when the XMLReader does not
395 * recognize the property name.
396 * @throws SAXNotSupportedException when the XMLReader
397 * recognizes the property name but cannot set the
398 * requested value.
399 */
400 @Override
401 public void setProperty(String name, Object value)
402 throws SAXNotRecognizedException, SAXNotSupportedException {
403 if (this.getParent() != null) {
404 this.getParent().setProperty(name, value);
405 }
406 this.parserBuilder.setProperty(name, value);
407 }
408
409 /**
410 * Parses an XML document.
411 * <p>
412 * The application can use this method to instruct ElementScanner
413 * to begin parsing an XML document from any valid input source
414 * (a character stream, a byte stream, or a URI).</p>
415 * <p>
416 * Applications may not invoke this method while a parse is in
417 * progress. Once a parse is complete, an application may reuse
418 * the same ElementScanner object, possibly with a different input
419 * source.</p>
420 * <p>
421 * This method is synchronous: it will not return until parsing
422 * has ended. If a client application wants to terminate parsing
423 * early, it should throw an exception.</p>
424 *
425 * @param source the input source for the XML document.
426 *
427 * @throws SAXException any SAX exception, possibly wrapping
428 * another exception.
429 * @throws IOException an IO exception from the parser,
430 * possibly from a byte stream or character
431 * stream supplied by the application.
432 */
433 @Override
434 public void parse(InputSource source) throws IOException, SAXException {
435 final SAXHandler shandler = new FragmentHandler(parserBuilder.getJDOMFactory());
436 SAXHandlerFactory shfactory = new SAXHandlerFactory() {
437 @Override
438 public SAXHandler createSAXHandler(JDOMFactory fac) {
439 // ignore the fac.
440 return shandler;
441 }
442 };
443 final XMLReaderJDOMFactory currentfac = parserBuilder.getXMLReaderFactory();
444 final SAXHandlerFactory currentshfac = parserBuilder.getSAXHandlerFactory();
445 try {
446 final XMLReader xreader = getParent() != null
447 ? getParent()
448 : parserBuilder.getXMLReaderFactory().createXMLReader();
449 final boolean validating = currentfac.isValidating();
450 parserBuilder.setSAXHandlerFactory(shfactory);
451 parserBuilder.setXMLReaderFactory(new XMLReaderJDOMFactory() {
452 @Override
453 public boolean isValidating() {
454 return validating;
455 }
456
457 @Override
458 public XMLReader createXMLReader() throws JDOMException {
459 return xreader;
460 }
461 });
462 // configures the sax handler and parser to mate.
463 parserBuilder.buildEngine();
464 // Allocate the element builder (SAXHandler subclass).
465 this.saxHandler = shandler;
466
467 // Allocate (if not provided) and configure the parent parser.
468 if (this.getParent() != null) {
469 setParent(xreader);
470 }
471
472 } catch (JDOMException e) {
473 throw new SAXException("Problem in JDOM.", e);
474 } finally {
475 parserBuilder.setXMLReaderFactory(currentfac);
476 parserBuilder.setSAXHandlerFactory(currentshfac);
477 }
478 // And delegate to superclass now that everything has been set-up.
479 // Note: super.parse() forces the registration of this filter as
480 // ContentHandler, ErrorHandler, DTDHandler and EntityResolver.
481 super.parse(source);
482 }
483
484 //-------------------------------------------------------------------------
485 // ContentHandler interface support
486 //-------------------------------------------------------------------------
487
488 /**
489 * <i>[ContentHandler interface support]</i> Receives notification
490 * of the beginning of a document.
491 *
492 * @throws SAXException any SAX exception, possibly wrapping
493 * another exception.
494 */
495 @Override
496 public void startDocument() throws SAXException {
497 // Reset state.
498 this.currentPath.setLength(0);
499 this.activeRules.clear();
500
501 // Propagate event.
502 this.saxHandler.startDocument();
503 super.startDocument();
504 }
505
506 /**
507 * <i>[ContentHandler interface support]</i> Receives notification
508 * of the end of a document.
509 *
510 * @throws SAXException any SAX exception, possibly wrapping
511 * another exception.
512 */
513 @Override
514 public void endDocument() throws SAXException {
515 // Propagate event.
516 this.saxHandler.endDocument();
517 super.endDocument();
518 }
519
520 /**
521 * <i>[ContentHandler interface support]</i> Begins the scope of
522 * a prefix-URI Namespace mapping.
523 *
524 * @param prefix the Namespace prefix being declared.
525 * @param uri the Namespace URI the prefix is mapped to.
526 *
527 * @throws SAXException any SAX exception, possibly wrapping
528 * another exception.
529 */
530 @Override
531 public void startPrefixMapping(String prefix, String uri)
532 throws SAXException {
533 // Propagate event.
534 this.saxHandler.startPrefixMapping(prefix, uri);
535 super.startPrefixMapping(prefix, uri);
536 }
537
538 /**
539 * <i>[ContentHandler interface support]</i> Ends the scope of a
540 * prefix-URI Namespace mapping.
541 *
542 * @param prefix the prefix that was being mapped.
543 *
544 * @throws SAXException any SAX exception, possibly wrapping
545 * another exception.
546 */
547 @Override
548 public void endPrefixMapping(String prefix) throws SAXException {
549 // Propagate event.
550 this.saxHandler.endPrefixMapping(prefix);
551 super.endPrefixMapping(prefix);
552 }
553
554 /**
555 * <i>[ContentHandler interface support]</i> Receives notification
556 * of the beginning of an element.
557 *
558 * @param nsUri the Namespace URI, or the empty string if
559 * the element has no Namespace URI or if
560 * Namespace processing is not being performed.
561 * @param localName the local name (without prefix), or the
562 * empty string if Namespace processing is
563 * not being performed.
564 * @param qName the qualified name (with prefix), or the
565 * empty string if qualified names are not
566 * available.
567 * @param attrs the attributes attached to the element. If
568 * there are no attributes, it shall be an
569 * empty Attributes object.
570 *
571 * @throws SAXException any SAX exception, possibly wrapping
572 * another exception.
573 */
574 @Override
575 public void startElement(String nsUri, String localName,
576 String qName, Attributes attrs)
577 throws SAXException {
578 // Append new element to the current path.
579 this.currentPath.append('/').append(localName);
580
581 // Retrieve the matching rules for this element.
582 String eltPath = this.currentPath.substring(0);
583 Collection<XPathMatcher> matchingRules = this.getMatchingRules(eltPath, attrs);
584 if (matchingRules != null) {
585 // Matching rules found.
586 // => Make them active to trigger element building.
587 this.activeRules.put(eltPath, matchingRules);
588 }
589
590 // Propagate event.
591 if (this.activeRules.size() != 0) {
592 this.saxHandler.startElement(nsUri, localName, qName, attrs);
593 }
594 super.startElement(nsUri, localName, qName, attrs);
595 }
596
597 /**
598 * <i>[ContentHandler interface support]</i> Receives notification
599 * of the end of an element.
600 *
601 * @param nsUri the Namespace URI, or the empty string if
602 * the element has no Namespace URI or if
603 * Namespace processing is not being performed.
604 * @param localName the local name (without prefix), or the
605 * empty string if Namespace processing is
606 * not being performed.
607 * @param qName the qualified name (with prefix), or the
608 * empty string if qualified names are not
609 * available.
610 *
611 * @throws SAXException any SAX exception, possibly wrapping
612 * another exception.
613 */
614 @Override
615 public void endElement(String nsUri, String localName, String qName)
616 throws SAXException {
617 // Grab the being-built element.
618 Element elt = this.saxHandler.getCurrentElement();
619
620 // Complete element building before making use of it.
621 // (This sets the current element to the parent of elt.)
622 if (this.activeRules.size() != 0) {
623 this.saxHandler.endElement(nsUri, localName, qName);
624 }
625
626 // Get the matching rules for this element (if any).
627 String eltPath = this.currentPath.substring(0);
628 Collection<XPathMatcher> matchingRules = this.activeRules.remove(eltPath);
629 if (matchingRules != null) {
630 // Matching rules found.
631 // => Detach the current element if no rules remain active.
632 if (this.activeRules.size() == 0) {
633 elt.detach();
634 }
635
636 // And notify all matching listeners.
637 try {
638 for (XPathMatcher matcher : matchingRules) {
639 if (matcher.match(eltPath, elt)) {
640 matcher.getListener().elementMatched(eltPath, elt);
641 }
642 }
643 }
644 catch (JDOMException ex1) {
645 // Oops! Listener-originated exception.
646 // => Fire a SAXException to abort parsing.
647 throw (new SAXException(ex1.getMessage(), ex1));
648 }
649 }
650 // Remove notified element from the current path.
651 this.currentPath.setLength(
652 this.currentPath.length() - (localName.length() + 1));
653 // Propagate event.
654 super.endElement(nsUri, localName, qName);
655 }
656
657 /**
658 * <i>[ContentHandler interface support]</i> Receives notification
659 * of character data.
660 *
661 * @param ch the characters from the XML document.
662 * @param start the start position in the array.
663 * @param length the number of characters to read from the array.
664 *
665 * @throws SAXException any SAX exception, possibly wrapping
666 * another exception.
667 */
668 @Override
669 public void characters(char[] ch, int start, int length)
670 throws SAXException {
671 // Propagate event.
672 if (this.activeRules.size() != 0) {
673 this.saxHandler.characters(ch, start, length);
674 }
675 super.characters(ch, start, length);
676 }
677
678 /**
679 * <i>[ContentHandler interface support]</i> Receives notification
680 * of ignorable whitespace in element content.
681 *
682 * @param ch the characters from the XML document.
683 * @param start the start position in the array.
684 * @param length the number of characters to read from the array.
685 *
686 * @throws SAXException any SAX exception, possibly wrapping
687 * another exception.
688 */
689 @Override
690 public void ignorableWhitespace(char[] ch, int start, int length)
691 throws SAXException {
692 // Propagate event.
693 if (this.activeRules.size() != 0) {
694 this.saxHandler.ignorableWhitespace(ch, start, length);
695 }
696 super.ignorableWhitespace(ch, start, length);
697 }
698
699 /**
700 * <i>[ContentHandler interface support]</i> Receives notification
701 * of processing instruction.
702 *
703 * @param target the processing instruction target.
704 * @param data the processing instruction data, or
705 * <code>null</code> if none was supplied.
706 *
707 * @throws SAXException any SAX exception, possibly wrapping
708 * another exception.
709 */
710 @Override
711 public void processingInstruction(String target, String data)
712 throws SAXException {
713 // Propagate event.
714 if (this.activeRules.size() != 0) {
715 this.saxHandler.processingInstruction(target, data);
716 }
717 super.processingInstruction(target, data);
718 }
719
720 /**
721 * <i>[ContentHandler interface support]</i> Receives notification
722 * of a skipped entity.
723 *
724 * @param name the name of the skipped entity.
725 *
726 * @throws SAXException any SAX exception, possibly wrapping
727 * another exception.
728 */
729 @Override
730 public void skippedEntity(String name) throws SAXException {
731 // Propagate event.
732 if (this.activeRules.size() != 0) {
733 this.saxHandler.skippedEntity(name);
734 }
735 super.skippedEntity(name);
736 }
737
738
739 //=========================================================================
740 // Deviant implementations of JDOM builder objects
741 //=========================================================================
742
743 //-------------------------------------------------------------------------
744 // ParserBuilder nested class
745 //-------------------------------------------------------------------------
746
747 //-------------------------------------------------------------------------
748 // FragmentHandler nested class
749 //-------------------------------------------------------------------------
750
751 /**
752 * FragmentHandler extends SAXHandler to support matching nodes
753 * without a common ancestor. This class inserts a dummy root
754 * element in the being-built document. This prevents the document
755 * to have, from SAXHandler's point of view, multiple root
756 * elements (which would cause the parse to fail).
757 */
758 private static class FragmentHandler extends SAXHandler {
759 /**
760 * Public constructor.
761 */
762 public FragmentHandler(JDOMFactory factory) {
763 super(factory);
764
765 // Add a dummy root element to the being-built document.
766 this.pushElement(new Element("root", null, null));
767 }
768 }
769
770 }
771
0 /*--
1
2 Copyright (C) 2001-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.input.scanner;
55
56
57 import java.util.regex.Pattern;
58 import java.util.regex.PatternSyntaxException;
59
60 import org.jdom.Element;
61 import org.jdom.JDOMException;
62 import org.jdom.xpath.XPathExpression;
63 import org.jdom.xpath.XPathFactory;
64
65 import org.xml.sax.Attributes;
66
67
68 /* package */ class JakartaRegExpXPathMatcher extends XPathMatcher {
69
70 /**
71 * The compiled regular expression this matcher matches.
72 */
73 private final Pattern re;
74
75 private final XPathExpression<Object> test;
76
77 /**
78 * Creates a new XPath matcher using Jakarta RegExp regular
79 * expression matcher implementation.
80 *
81 * @param expression the XPath-like expression to match.
82 * @param listener the element listener to notify when an
83 * element matches the expression.
84 *
85 * @throws JDOMException if one of the arguments is invalid.
86 */
87 public JakartaRegExpXPathMatcher(
88 String expression, ElementListener listener)
89 throws JDOMException {
90 super(expression, listener);
91
92 try {
93 String pathPattern = getPathPatternAsRE(expression);
94
95 this.re = Pattern.compile(pathPattern);
96
97 String testPattern = getTestPattern(expression);
98 if (testPattern != null) {
99 testPattern = "." + testPattern;
100
101 this.test = XPathFactory.instance().compile(testPattern);
102 }
103 else {
104 this.test = null;
105 }
106
107 if (isDebug()) {
108 System.out.println("Listener " + listener + ":");
109 System.out.println(" " + expression +
110 " -> RE = " + pathPattern);
111 System.out.println(" " + expression +
112 " -> XPath = " + testPattern);
113 }
114 }
115 catch (PatternSyntaxException ex1) {
116 throw (new JDOMException(
117 "Illegal XPath expression: " + expression, ex1));
118 }
119 }
120
121 /**
122 * Tries to match an element path and attributes with the XPath
123 * expression this matcher matches.
124 * <p>
125 * This method is invoked when processing the
126 * <code>startElement</code> SAX event.</p>
127 * <p>
128 * This implementation only matches the element path, ignoring
129 * the attributes.</p>
130 *
131 * @param path the path to the element.
132 * @param attrs the SAX attributes of the element.
133 *
134 * @return <code>true</code> is the element matches the XPath
135 * expression, <code>false</code> otherwise.
136 */
137 @Override
138 public boolean match(String path, Attributes attrs) {
139 return (this.re.matcher(path).matches());
140 }
141
142 /**
143 * Tries to match an element with the XPath expression this
144 * matcher matches.
145 * <p>
146 * This method is invoked when processing the
147 * <code>endElement</code> SAX event. It allows matching on
148 * data not part of the <code>startElement</code> event such
149 * as the presence of child elements.</p>
150 * <p>
151 * This implementation always return <code>true</code> as it
152 * does not support matching on anything but the path.</p>
153 *
154 * @param path the path to the element.
155 * @param elt the JDOM element.
156 *
157 * @return <code>true</code> is the element matches the XPath
158 * expression, <code>false</code> otherwise.
159 */
160 @Override
161 public boolean match(String path, Element elt) {
162 if (this.test != null) {
163 return !this.test.evaluate(elt).isEmpty();
164 }
165 return (true);
166 }
167 }
168
0
1 ElementScanner is a SAX filter that uses XPath-like expressions to select
2 element nodes to build and notifies listeners when these elements becomes
3 available during the SAX parse.
4
5 ElementScanner does not aim at providing a faster parsing of XML documents.
6 Its primary focus is to allow the application to control the parse and to
7 consume the XML data while they are being parsed. ElementScanner can be
8 viewed as a high-level SAX parser that fires events conveying JDOM elements
9 rather that XML tags and character data.
10 ElementScanner only notifies of the parsing of element nodes and does not
11 support reporting the parsing of DOCTYPE data, processing instructions or
12 comments except for those present within the selected elements.
13 Applications needing such data shall register a specific SAX ContentHandler
14 on ElementScanner to receive them in the form of raw SAX events.
15
16 To use this package, in addition to JDOM, the following products must be
17 present in the application class path:
18 - Jakarta Regexp 1.1 or higher
19 (see "http://jakarta.apache.org/regexp/index.html")
20 - Jaxen 1.0 beta7 or higher
21 (see "http://www.jaxen.org/")
22
23 For detailed information, please refer to the package Javadoc documentation
24 or the file "package.html" in this directory.
25
26
27 The "doc-files directory contains simple test cases that demonstrate how to
28 use ElementScanner within an application:
29
30 - ElementScannerTest.java is a simple program that uses ElementScanner
31 to parse the XML file passed as argument and registers a set of
32 ElementListeners that display the parsed elements.
33 Usage: java ElementScannerTest [XML file]
34
35 - test.xml is an example of XML file that can be used with the above
36 sample.
37
38
39 -- Laurent Bihanic
0 /*--
1
2 Copyright (C) 2001-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.input.scanner;
55
56
57 import java.lang.reflect.InvocationTargetException;
58 import java.lang.reflect.Constructor;
59 import java.lang.reflect.Modifier;
60
61 import org.jdom.Element;
62 import org.jdom.JDOMException;
63 import org.jdom.internal.SystemProperty;
64
65 import org.xml.sax.Attributes;
66
67
68 /**
69 * The base class for all XPath matchers used by
70 * {@link ElementScanner}.
71 * <p>
72 * This class also plays the role of factory for concrete
73 * implementations: The system property
74 * "<code>org.jdom.XPathMatcher.class</code>" shall contain the
75 * fully-qualified name of a concrete subclass of XPatchMatcher with
76 * a public {@link #XPathMatcher two argument constructor}. If this
77 * property is not defined, the default concrete implementation
78 * (supporting only node matching patterns) will be used.</p>
79 * <p>
80 * As the default implementation relies on Perl5-like regular
81 * expression to match nodes, any regular expression can be used as
82 * "<i>XPath expression</i>" with the restriction that any '*'
83 * character be escaped (i&#46;e&#46; preceded with a '\' character).</p>
84 *
85 * @author Laurent Bihanic
86 */
87 public abstract class XPathMatcher {
88
89 /**
90 * The name of the system property from which to retrieve the
91 * name of the implementation class to use.
92 * <p>
93 * The property name is:
94 * "<code>org.jdom.XPathMatcher.class</code>".</p>
95 */
96 private final static String IMPLEMENTATION_CLASS_PROPERTY =
97 "org.jdom.XPathMatcher.class";
98
99 /**
100 * The default implementation class to use if none was configured.
101 */
102 private final static String DEFAULT_IMPLEMENTATION_CLASS =
103 "org.jdom.contrib.input.scanner.JakartaRegExpXPathMatcher";
104
105 /**
106 * The constructor to instanciate a new XPathMatcher concrete
107 * implementation.
108 *
109 * @see #newXPathMatcher
110 */
111 private static Constructor<?> constructor = null;
112
113 /**
114 * Whether debug traces are active.
115 */
116 private static boolean debug = false;
117
118 /**
119 * The XPath expression this matcher matches!
120 */
121 private final String expression;
122
123 /**
124 * The element listener.
125 */
126 private final ElementListener listener;
127
128 /**
129 * Default constructor, protected on purpose.
130 *
131 * @param expression the XPath-like expression to match.
132 * @param listener the element listener to notify when an
133 * element matches the expression.
134 *
135 * @throws JDOMException if one of the arguments is invalid.
136 */
137 protected XPathMatcher(String expression, ElementListener listener)
138 throws JDOMException {
139 if ((expression == null) || (expression.length() == 0)) {
140 throw (new JDOMException(
141 "Invalid XPath expression: \"" + expression + "\""));
142 }
143 if (listener == null) {
144 throw (new JDOMException("Invalid ElementListener: <null>"));
145 }
146 this.expression = expression;
147 this.listener = listener;
148 }
149
150 /**
151 * Returns the XPath expression this matcher matches.
152 *
153 * @return the XPath expression this matcher matches.
154 */
155 public String getExpression() {
156 return (this.expression);
157 }
158
159 /**
160 * Returns the element listener associated to this matcher object.
161 *
162 * @return the element listener.
163 */
164 public ElementListener getListener() {
165 return (this.listener);
166 }
167
168 /**
169 * Tries to match an element path and attributes with the XPath
170 * expression this matcher matches.
171 * <p>
172 * This method is invoked when processing the
173 * <code>startElement</code> SAX event.</p>
174 * <p>
175 * <strong>Note</strong>: The default implementation ignores the
176 * attributes.</p>
177 *
178 * @param path the path to the element.
179 * @param attrs the SAX attributes of the element.
180 *
181 * @return <code>true</code> is the element matches the XPath
182 * expression, <code>false</code> otherwise.
183 */
184 abstract public boolean match(String path, Attributes attrs);
185
186 /**
187 * Tries to match an element with the XPath expression this
188 * matcher matches.
189 * <p>
190 * This method is invoked when processing the
191 * <code>endElement</code> SAX event. It allows matching on
192 * data not part of the <code>startElement</code> event such
193 * as the presence of child elements.</p>
194 * <p>
195 * <strong>Note</strong>: The default implementation always
196 * returns <code>true</code> as it only supports filtering on
197 * the node path.</p>
198 *
199 * @param path the path to the element.
200 * @param elt the JDOM element.
201 *
202 * @return <code>true</code> is the element matches the XPath
203 * expression, <code>false</code> otherwise.
204 */
205 abstract public boolean match(String path, Element elt);
206
207 /**
208 * Extracts the node matching pattern part from an XPath
209 * expression and converts it into a Perl5-like regular
210 * expression.
211 *
212 * @param expr an XPath expression.
213 *
214 * @return the RE to match the element path.
215 *
216 * @throws JDOMException if <code>expression</code> is invalid.
217 */
218 protected static String getPathPatternAsRE(String expr)
219 throws JDOMException {
220 if ((expr == null) || (expr.length() == 0)) {
221 expr = "/*";
222 }
223
224 // It the expression ends with a square backet, a test part is
225 // present. => Strip it!
226 // Note: Any other sub-expression between square backet is view as
227 // a RE alphabet definition and proccessed. OK, that's not
228 // XPath compliant but that's very convenient!
229 String path = (expr.endsWith("]"))?
230 expr.substring(0, expr.lastIndexOf('[')): expr;
231
232 int length = path.length();
233 StringBuilder re = new StringBuilder(2 * length);
234
235 char previous = (char)0;
236 for (int i=0; i<length; i++) {
237 char current = path.charAt(i);
238
239 if (i == 0) {
240 re.append((current == '/')? '^': '/');
241 }
242 if (current == '*') {
243 if (previous == '\\') {
244 // Escaped wildcard. => Remove previous '\' and insert '*'.
245 re.setLength(re.length() - 1);
246 }
247 else {
248 // Regular XPath wildcard.
249 // => "*" -> ".[^/]*", i.e. all chars but the separator '/'
250 re.append(".[^/]");
251 }
252 re.append('*');
253 }
254 else {
255 if ((current == '/') && (previous == '/')) {
256 // "//" -> "/.*/" or "/" !!!
257 // => Remove previous '/'
258 re.setLength(re.length() - 1);
259
260 // And insert RE.
261 re.append("(/.*/|/)");
262 }
263 else {
264 re.append(current);
265 }
266 }
267 previous = current;
268 }
269 re.append('$');
270
271 return (re.toString());
272 }
273
274 /**
275 * Extracts the test part from an XPath expression. The test
276 * part if the part of the XPath expression between square
277 * backets.
278 *
279 * @param expr an XPath expression.
280 *
281 * @return the test part of the expression of <code>null</code>
282 * if no test was specified.
283 *
284 * @throws JDOMException if <code>expression</code> is invalid.
285 */
286 protected static String getTestPattern(String expr) throws JDOMException {
287 if (expr.endsWith("]")) {
288 return (expr.substring(expr.lastIndexOf('[')));
289 }
290 return (null);
291 }
292
293
294 //-------------------------------------------------------------------------
295 // XPathMatcher Factory methods
296 //-------------------------------------------------------------------------
297
298 /**
299 * Activates or deactivates debug traces on the process standard
300 * output. Debug traces allow to trace the mapping between the
301 * XPath-like expressions provided when registering a listener
302 * and the regular expressions and/or XPath expressions actually
303 * used to filter elements.
304 *
305 * @param value whether to activate debug traces.
306 */
307 public static void setDebug(boolean value) {
308 debug = value;
309 }
310
311 /**
312 * Returns whether debug traces are active.
313 *
314 * @return <code>true</code> if debug traces are active;
315 * <code>false</code> otherwise.
316 */
317 public static boolean isDebug() {
318 return (debug);
319 }
320
321 /**
322 * Sets the concrete XPathMatcher subclass to be used when
323 * allocating XPathMatcher instances.
324 *
325 * @param aClass the concrete subclass of XPathMatcher.
326 *
327 * @throws IllegalArgumentException if <code>aClass</code> is
328 * <code>null</code>.
329 * @throws JDOMException if <code>aClass</code> is
330 * not a concrete subclass
331 * of XPathMatcher.
332 */
333 public static void setXPathMatcherClass(Class<?> aClass)
334 throws IllegalArgumentException, JDOMException {
335 if (aClass != null) {
336 try {
337 if ((XPathMatcher.class.isAssignableFrom(aClass)) &&
338 (Modifier.isAbstract(aClass.getModifiers()) == false)) {
339 // Concrete subclass pf XPathMatcher.
340 // => Get the constructor to use.
341 constructor = aClass.getConstructor(String.class, ElementListener.class);
342 }
343 else {
344 throw (new JDOMException(
345 aClass.getName() + " is not a concrete XPathMatcher"));
346 }
347 }
348 catch (Exception ex1) {
349 // Any reflection error (probably due to a configuration mistake).
350 throw (new JDOMException(ex1.toString(), ex1));
351 }
352 }
353 else {
354 throw (new IllegalArgumentException("aClass"));
355 }
356 }
357
358 /**
359 * Creates a new XPath matcher matching the specified XPath
360 * expression.
361 *
362 * @param expression the XPath-like expression to match.
363 * @param listener the element listener to notify when an
364 * element matches the expression.
365 * @return a matcher.
366 *
367 * @throws JDOMException if <code>expression</code> is invalid.
368 */
369 public static final XPathMatcher newXPathMatcher(
370 String expression, ElementListener listener)
371 throws JDOMException {
372 try {
373 if (constructor == null) {
374 // First call.
375 // => Load configuration to determine implementation.
376 String className = SystemProperty.get(
377 IMPLEMENTATION_CLASS_PROPERTY,
378 DEFAULT_IMPLEMENTATION_CLASS);
379
380 setXPathMatcherClass(Class.forName(className));
381 }
382 return (XPathMatcher)constructor.newInstance(expression, listener);
383 }
384 catch (InvocationTargetException ex1) {
385 // Constructor threw an error on invocation.
386 Throwable te = ex1.getTargetException();
387
388 throw ((te instanceof JDOMException)? (JDOMException)te:
389 new JDOMException(te.toString(), te));
390 }
391 catch (Exception ex3) {
392 // Any reflection error (probably due to a configuration mistake).
393 throw (new JDOMException(ex3.toString(), ex3));
394 }
395 }
396 }
397
0 import java.io.IOException;
1
2 import org.xml.sax.InputSource;
3
4 import org.jdom.Element;
5 import org.jdom.output.XMLOutputter2;
6
7 import org.jdom.contrib.input.scanner.ElementScanner;
8 import org.jdom.contrib.input.scanner.ElementListener;
9
10
11 @SuppressWarnings("javadoc")
12 public class ElementScannerTest
13 {
14 public static XMLOutputter2 out = new XMLOutputter2();
15
16 public static void main(String[] args) throws Exception
17 {
18 org.jdom.contrib.input.scanner.XPathMatcher.setDebug(true);
19
20 ElementScanner scanner = new ElementScanner();
21
22 scanner.addElementListener(new Spy("Listener #1 - \"x//y\""), "x//y");
23 scanner.addElementListener(new Spy("Listener #2 - \"y/*/y\""), "y/*/y");
24 scanner.addElementListener(new Spy("Listener #3 - \"/*\""), "/*");
25 scanner.addElementListener(new Spy("Listener #4 - \"z\""), "z");
26
27 scanner.addElementListener(new Spy("Listener #5 - \"*[contains(@name,'.1')]\""),
28 "*[contains(@name,'.1')]");
29 scanner.addElementListener(new Spy("Listener #6 - \"y[.//y]\""),
30 "y[.//y]");
31
32 String input = "test.xml";
33 if (args.length > 0)
34 {
35 input = args[0];
36 }
37
38 scanner.parse(new InputSource(input));
39 }
40
41 private static class Spy implements ElementListener
42 {
43 private String name;
44
45 public Spy(String name)
46 {
47 this.name = name;
48 }
49
50 @Override
51 public void elementMatched(String path, Element e)
52 {
53 try
54 {
55 System.out.print(this.name + "\n>>> " + path + "\n");
56 out.output(e, System.out);
57 System.out.println("\n<<<\n");
58 }
59 catch (IOException ex1) { ex1.printStackTrace(); }
60 }
61 }
62 }
63
0 <?xml version="1.0" ?>
1
2 <a>
3 <x name="element1">
4 <y name="child-1">
5 <z name="child-1.1">
6 <y name="child-1.1.1"/>
7 </z>
8 <z name="child-1.2">
9 <y name="child-1.2.1"/>
10 </z>
11 </y>
12 <y name="child-2"/>
13 <y name="child-3">
14 <z name="child-3.1"/>
15 <z name="child-3.2">
16 <y name="child-3.2.1"/>
17 <y name="child-3.2.2"/>
18 <y name="child-3.2.3"/>
19 <y name="child-3.2.4"/>
20 <y name="child-3.2.5"/>
21 </z>
22 </y>
23 </x>
24 </a>
25
0 <html>
1 <body>
2 ElementScanner is a SAX filter that uses XPath-like expressions to
3 select element nodes to build and notifies listeners when these
4 elements becomes available during the SAX parse.
5 <p>
6 ElementScanner does not aim at providing a faster parsing of XML
7 documents. Its primary focus is to allow the application to
8 control the parse and to consume the XML data while they are
9 being parsed. ElementScanner can be viewed as a high-level SAX
10 parser that fires events conveying JDOM
11 {@link org.jdom.Element elements} rather that XML tags and
12 character data.</p>
13 <p>
14 ElementScanner only notifies of the parsing of element nodes and
15 does not support reporting the parsing of DOCTYPE data, processing
16 instructions or comments except for those present within the
17 selected elements. Application needing such data shall register
18 a specific {@link org.xml.sax.ContentHandler} of this filter to
19 receive them in the form of raw SAX events.</p>
20 <p>
21 Please refer to <a href="ElementScanner.html">ElementScanner</a>
22 for details on how to use ElementScanner within an application.</p>
23 <p>
24 A sample application is also provided
25 <a href="doc-files/ElementScannerTest.java">here</a>, with an example
26 <a href="doc-files/test.xml">XML file</a>.<p>
27 </body>
28 </html>
29
0 /*--
1
2 Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.output;
55
56 /**
57 * A JTree outputter.
58 * <p>
59 * This outputter builds a JTree representation of the JDOM document for
60 * easy visual navigation. This is a full rewrite of the JTreeOutputter
61 * originally written by James Davies.
62 * </p>
63 *
64 * @author Matthew MacKenzie [matt@xmlglobal.com]
65 */
66 import java.util.Iterator;
67 import javax.swing.tree.DefaultMutableTreeNode;
68 import org.jdom.Document;
69 import org.jdom.Attribute;
70 import org.jdom.Element;
71
72 @SuppressWarnings("javadoc")
73 public class JTreeOutputter {
74
75 public JTreeOutputter() {
76 }
77
78 /**
79 * @param toBeCompatible unused.
80 */
81 public JTreeOutputter(boolean toBeCompatible) {
82 // just here to mimic the legacy JTreeOutputter
83 }
84
85 /**
86 * Output a Document.
87 * @param doc The document to transform to TreeNode.
88 * @param root The root tree node.
89 */
90 public void output(Document doc, DefaultMutableTreeNode root) {
91 processElement(doc.getRootElement(),root);
92 }
93
94 /**
95 * Output an Element.
96 * @param el The element to transform to TreeNode.
97 * @param root The root tree node.
98 */
99 public void output(Element el, DefaultMutableTreeNode root) {
100 processElement(el, root);
101 }
102
103 protected void processElement(Element el, DefaultMutableTreeNode dmtn) {
104 DefaultMutableTreeNode dmtnLocal =
105 new DefaultMutableTreeNode(el.getName());
106 String elText = el.getTextNormalize();
107 if (elText != null && !elText.equals("")) {
108 dmtnLocal.add(new DefaultMutableTreeNode(elText));
109 }
110 processAttributes(el, dmtnLocal);
111
112 Iterator<Element> iter = el.getChildren().iterator();
113
114 while (iter.hasNext()) {
115 Element nextEl = iter.next();
116 processElement(nextEl, dmtnLocal);
117 }
118 dmtn.add(dmtnLocal);
119 }
120
121 protected void processAttributes(Element el, DefaultMutableTreeNode dmtn) {
122 if (!el.hasAttributes()) {
123 return;
124 }
125 Iterator<Attribute> atts = el.getAttributes().iterator();
126 while (atts.hasNext()) {
127 Attribute att = atts.next();
128 DefaultMutableTreeNode node =
129 new DefaultMutableTreeNode("@" + att.getName());
130 node.add(new DefaultMutableTreeNode(att.getValue()));
131 dmtn.add(node);
132 }
133 }
134 }
135
0 Location for development of experimental JDOM outputters.
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55 package org.jdom.contrib.perf;
56
57 import java.io.IOException;
58 import java.io.Writer;
59
60 final class DevNull extends Writer {
61
62 int counter = 0;
63
64 public void reset() {
65 counter = 0;
66 }
67
68 public int getCounter() {
69 return counter;
70 }
71
72 @Override
73 public void write(final char[] cbuf, final int off, final int len) throws IOException {
74 // do nothing
75 counter++;
76 }
77
78 @Override
79 public void flush() throws IOException {
80 // do nothing
81 counter++;
82 }
83
84 @Override
85 public void close() throws IOException {
86 // do nothing
87 counter++;
88 }
89
90 @Override
91 public void write(final int c) throws IOException {
92 // do nothing
93 counter++;
94 }
95
96 @Override
97 public void write(final char[] cbuf) throws IOException {
98 // do nothing
99 counter++;
100 }
101
102 @Override
103 public void write(final String str) throws IOException {
104 // do nothing
105 counter++;
106 }
107
108 @Override
109 public void write(final String str, final int off, final int len) throws IOException {
110 // do nothing
111 counter++;
112 }
113
114 @Override
115 public Writer append(final CharSequence csq) throws IOException {
116 counter++;
117 return this;
118 }
119
120 @Override
121 public Writer append(final CharSequence csq, final int start, final int end) throws IOException {
122 counter++;
123 return this;
124 }
125
126 @Override
127 public Writer append(final char c) throws IOException {
128 counter++;
129 return this;
130 }
131
132 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55 package org.jdom.contrib.perf;
56
57 import java.io.CharArrayReader;
58 import java.io.File;
59 import java.io.FileReader;
60 import java.io.IOException;
61 import java.util.ArrayList;
62 import java.util.Collection;
63 import java.util.Iterator;
64 import java.util.List;
65
66 import javax.xml.parsers.DocumentBuilder;
67 import javax.xml.parsers.DocumentBuilderFactory;
68 import javax.xml.parsers.ParserConfigurationException;
69 import javax.xml.stream.XMLEventReader;
70 import javax.xml.stream.XMLInputFactory;
71 import javax.xml.stream.XMLStreamReader;
72
73 import org.jdom.filter.ElementFilter;
74 import org.xml.sax.InputSource;
75 import org.xml.sax.SAXException;
76 import org.xml.sax.XMLReader;
77 import org.xml.sax.ext.DefaultHandler2;
78
79 import org.jdom.Attribute;
80 import org.jdom.CDATA;
81 import org.jdom.Comment;
82 import org.jdom.Content;
83 import org.jdom.DefaultJDOMFactory;
84 import org.jdom.DocType;
85 import org.jdom.Document;
86 import org.jdom.Element;
87 import org.jdom.EntityRef;
88 import org.jdom.Namespace;
89 import org.jdom.ProcessingInstruction;
90 import org.jdom.Text;
91 import org.jdom.UncheckedJDOMFactory;
92 import org.jdom.input.DOMBuilder;
93 import org.jdom.input.SAXBuilder;
94 import org.jdom.input.StAXEventBuilder;
95 import org.jdom.input.StAXStreamBuilder;
96 import org.jdom.input.sax.SAXHandler;
97 import org.jdom.internal.ArrayCopy;
98 import org.jdom.output.Format;
99 import org.jdom.output.SAXOutputter;
100 import org.jdom.output.XMLOutputter2;
101 import org.jdom.xpath.XPathExpression;
102 import org.jdom.xpath.XPathFactory;
103
104 @SuppressWarnings("javadoc")
105 public class PerfDoc {
106
107 private class SAXLoadRunnable implements TimeRunnable {
108 private final int type;
109
110 SAXLoadRunnable(int type) {
111 this.type = type;
112 }
113
114 @Override
115 public void run() throws Exception {
116 Document doc = subload(type);
117 if (document == null) {
118 document = doc;
119 }
120 }
121 }
122
123 private static final DevNull devnull = new DevNull();
124
125 private final File infile;
126
127 private long saxTime = -1L;
128 private long domTime = -1L;
129 private long staxTime = -1L;
130 private long staxETime = -1L;
131 private long saxDTime = -1L;
132 private long domDTime = -1L;
133 private long staxDTime = -1L;
134 private long staxDETime = -1L;
135 private long loadMem = -1L;
136
137 private long dumpTime = -1L;
138 private long xpathTime = -1L;
139 private long dupeTime = -1L;
140 private long scanTime = -1L;
141 private long checkedTime = -1L;
142 private long uncheckedTime = -1L;
143
144
145 private Document document = null;
146 private final char[] chars;
147
148 public PerfDoc(File file) throws IOException {
149 infile = file;
150 char[] fchars = new char[(int)infile.length()];
151 int len = 0;
152 int cnt = 0;
153 FileReader fr = null;
154 try {
155 fr = new FileReader(infile);
156 while ((cnt = fr.read(fchars, len, fchars.length - len)) >= 0) {
157 if (cnt == 0 && len == fchars.length) {
158 fchars = ArrayCopy.copyOf(fchars, fchars.length + 10240);
159 }
160 len += cnt;
161 }
162 fchars = ArrayCopy.copyOf(fchars, len);
163 } finally {
164 if (fr != null) {
165 fr.close();
166 }
167 fr = null;
168 }
169 this.chars = fchars;
170 }
171
172 public File getFile() {
173 return infile;
174 }
175
176 public long saxLoad() throws Exception {
177 final long startmem = PerfTest.usedMem();
178 saxTime = PerfTest.timeRun(new SAXLoadRunnable(0) );
179 loadMem = PerfTest.usedMem() - startmem;
180 saxDTime = PerfTest.timeRun(new SAXLoadRunnable(8) );
181 return saxTime;
182 }
183
184 public long domLoad() throws Exception {
185 domTime = PerfTest.timeRun( new SAXLoadRunnable(1) );
186 domDTime = PerfTest.timeRun( new SAXLoadRunnable(9) );
187 return domTime;
188 }
189
190 public long staxLoad() throws Exception {
191 staxTime = PerfTest.timeRun( new SAXLoadRunnable(2) );
192 staxDTime = PerfTest.timeRun( new SAXLoadRunnable(10) );
193 return staxTime;
194 }
195
196 public long staxELoad() throws Exception {
197 staxETime = PerfTest.timeRun( new SAXLoadRunnable(3) );
198 staxDETime = PerfTest.timeRun( new SAXLoadRunnable(11) );
199 return staxETime;
200 }
201
202 public Document subload(int type) throws Exception {
203
204 CharArrayReader car = new CharArrayReader(chars);
205 switch (type) {
206 case 0:
207 SAXBuilder sax = new SAXBuilder();
208 sax.setJDOMFactory(new UncheckedJDOMFactory());
209 return sax.build(car);
210 case 1:
211 DOMBuilder dom = new DOMBuilder();
212 dom.setFactory(new UncheckedJDOMFactory());
213 InputSource source = new InputSource(car);
214 return dom.build(getDocument(source, false));
215 case 2:
216 StAXStreamBuilder stax = new StAXStreamBuilder();
217 stax.setFactory(new UncheckedJDOMFactory());
218 XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(car);
219 return stax.build(reader);
220 case 3:
221 StAXEventBuilder staxe = new StAXEventBuilder();
222 staxe.setFactory(new UncheckedJDOMFactory());
223 XMLEventReader events = XMLInputFactory.newInstance().createXMLEventReader(car);
224 return staxe.build(events);
225 case 8:
226 SAXBuilder dsax = new SAXBuilder();
227 DefaultHandler2 def = new DefaultHandler2();
228 XMLReader sread = dsax.getXMLReaderFactory().createXMLReader();
229 sread.setContentHandler(def);
230 sread.setDTDHandler(def);
231 sread.setEntityResolver(def);
232 sread.setErrorHandler(def);
233 sread.setProperty("http://xml.org/sax/properties/lexical-handler",
234 def);
235 sread.parse(new InputSource(car));
236 return null;
237 case 9:
238 InputSource dsource = new InputSource(car);
239 getDocument(dsource, false);
240 return null;
241 case 10:
242 XMLStreamReader dreader = XMLInputFactory.newInstance().createXMLStreamReader(car);
243 int sum = 0;
244 while (dreader.hasNext()) {
245 sum += dreader.next();
246 }
247 System.out.println("Sum " + sum);
248 return null;
249 case 11:
250 XMLEventReader dereader = XMLInputFactory.newInstance().createXMLEventReader(car);
251 int esum = 0;
252 while (dereader.hasNext()) {
253 esum += dereader.nextEvent().getEventType();
254 }
255 System.out.println("Sum " + esum);
256 return null;
257 case 12:
258 SAXBuilder slimsax = new SAXBuilder();
259 //slimsax.setJDOMFactory(new SlimJDOMFactory());
260 //slimsax.setFeature("http://xml.org/sax/features/string-interning", true);
261 return slimsax.build(car);
262 }
263 return null;
264 }
265
266 public int recurse(Element emt) {
267 int cnt = 1;
268 for (Object kid : emt.getChildren()) {
269 cnt += recurse((Element)kid);
270 }
271 return cnt;
272 }
273
274 public long scan() throws Exception {
275 scanTime = PerfTest.timeRun(new TimeRunnable() {
276 @Override
277 public void run() {
278 int elements = 0;
279 Iterator<Content> it = document.getDescendants();
280 while (it.hasNext()) {
281 if (it.next() instanceof Element) {
282 elements++;
283 }
284 }
285
286 int felements = 0;
287 Iterator<?> et = document.getDescendants(new ElementFilter());
288 while (et.hasNext()) {
289 et.next();
290 felements++;
291 }
292 if (felements != elements) {
293 System.out.printf("Different counts Descendants=%d Elements=%d\n", elements, felements);
294 }
295
296 int rcnt = recurse(document.getRootElement());
297 if (rcnt != elements) {
298 System.out.printf("Different counts Descendants=%d Recurse=%d\n", elements, rcnt);
299 }
300 }
301 });
302 return scanTime;
303 }
304
305 public long dump () throws Exception {
306 dumpTime = PerfTest.timeRun(new TimeRunnable() {
307
308 @Override
309 public void run() throws Exception {
310 long start = System.nanoTime();
311 dump(Format.getCompactFormat());
312 long comp = System.nanoTime();
313 dump(Format.getPrettyFormat());
314 long pretty = System.nanoTime();
315 dump(Format.getRawFormat());
316 long raw = System.nanoTime();
317 raw -= pretty;
318 pretty -= comp;
319 comp -= start;
320 System.out.printf("Raw=%d Pretty=%8d Compact=%8d\n", raw, pretty, comp);
321 }
322 });
323 return dumpTime;
324 }
325
326 private void dump(Format format) throws IOException {
327 XMLOutputter2 xout = new XMLOutputter2(format);
328 devnull.reset();
329 System.setProperty("NamespaceStack", "");
330 xout.output(document, devnull);
331 System.clearProperty("NamespaceStack");
332 if (devnull.getCounter() <= 0) {
333 throw new IllegalStateException("Needed a counter");
334 }
335 }
336
337 public long xpath() throws Exception {
338
339 final XPathFactory fac = XPathFactory.instance();
340
341 xpathTime = PerfTest.timeRun(new TimeRunnable() {
342 @Override
343 public void run() throws Exception {
344 XPathExpression<Object> patha = fac.compile("//@null");
345 patha.evaluate(document);
346 // select everything
347 XPathExpression<?> pathb = fac.compile("//node()");
348 pathb.evaluate(document);
349 }
350 });
351 return xpathTime;
352 }
353
354 private Collection<Content>duplicateContent(List<? extends Content> content) {
355 ArrayList<Content>ret = new ArrayList<Content>(content.size());
356 for (Content c : content) {
357 if (c instanceof Element) {
358 Element emt = (Element)c;
359 Element ne = new Element(emt.getName(), emt.getNamespacePrefix(), emt.getNamespaceURI());
360 if (emt.hasAttributes()) {
361 for (Object oatt : emt.getAttributes()) {
362 Attribute att = (Attribute)oatt;
363 Attribute a = new Attribute(att.getName(), att.getValue(),
364 att.getAttributeType(),
365 Namespace.getNamespace(att.getNamespacePrefix(), att.getNamespaceURI()));
366 emt.setAttribute(a);
367 }
368 }
369 if (emt.hasAdditionalNamespaces()) {
370 for (Object ns : emt.getAdditionalNamespaces()) {
371 ne.addNamespaceDeclaration((Namespace)ns);
372 }
373 }
374 ne.addContent(duplicateContent(emt.getContent()));
375 ret.add(ne);
376 } else if (c instanceof CDATA) {
377 ret.add(new CDATA(((CDATA)c).getText()));
378 } else if (c instanceof Comment) {
379 ret.add(new Comment(((Comment)c).getText()));
380 } else if (c instanceof EntityRef) {
381 EntityRef er = (EntityRef)c;
382 ret.add(new EntityRef(er.getName(), er.getPublicID(), er.getSystemID()));
383 } else if (c instanceof Text) {
384 ret.add(new Text(((Text)c).getText()));
385 } else if (c instanceof ProcessingInstruction) {
386 ProcessingInstruction pi = (ProcessingInstruction)c;
387 ret.add(new ProcessingInstruction(pi.getTarget(), pi.getData()));
388 } else if (c instanceof DocType) {
389 DocType dt = (DocType)c;
390 DocType ndt = new DocType(dt.getElementName(), dt.getPublicID(), dt.getSystemID());
391 if (dt.getInternalSubset() != null) {
392 ndt.setInternalSubset(dt.getInternalSubset());
393 }
394 ret.add(ndt);
395 } else {
396 throw new IllegalStateException("Unknown content " + c);
397 }
398 }
399 return ret;
400 }
401
402 public long duplicate() throws Exception {
403 final XMLOutputter2 xout = new XMLOutputter2(Format.getRawFormat());
404 final String orig = xout.outputString(document);
405 dupeTime = PerfTest.timeRun(new TimeRunnable() {
406 @Override
407 public void run() throws Exception {
408 // select nothing.
409 Document doc = new Document();
410 doc.addContent(duplicateContent(document.getContent()));
411 String dupe = xout.outputString(doc);
412 if (!orig.equals(dupe)) {
413 throw new IllegalStateException("Bad clone!");
414 }
415 }
416 });
417 return dupeTime;
418 }
419
420 public long checkedParse() throws Exception {
421 final XMLOutputter2 xout = new XMLOutputter2(Format.getRawFormat());
422 final String orig = xout.outputString(document);
423 checkedTime = PerfTest.timeRun(new TimeRunnable() {
424 @Override
425 public void run() throws Exception {
426 // select nothing.
427 SAXHandler handler = new SAXHandler(new DefaultJDOMFactory());
428 SAXOutputter saxout = new SAXOutputter(handler, handler, handler, handler, handler);
429 saxout.output(document);
430 Document doc = handler.getDocument();
431 String dupe = xout.outputString(doc);
432 if (!orig.equals(dupe)) {
433 throw new IllegalStateException("Bad clone!");
434 }
435 }
436 });
437 return checkedTime;
438 }
439
440 public long unCheckedParse() throws Exception {
441 final XMLOutputter2 xout = new XMLOutputter2(Format.getRawFormat());
442 final String orig = xout.outputString(document);
443 uncheckedTime = PerfTest.timeRun(new TimeRunnable() {
444 @Override
445 public void run() throws Exception {
446 // select nothing.
447 SAXHandler handler = new SAXHandler(new UncheckedJDOMFactory());
448 SAXOutputter saxout = new SAXOutputter(handler, handler, handler, handler, handler);
449 saxout.output(document);
450 Document doc = handler.getDocument();
451 String dupe = xout.outputString(doc);
452 if (!orig.equals(dupe)) {
453 throw new IllegalStateException("Bad clone!");
454 }
455 }
456 });
457 return uncheckedTime;
458 }
459
460 public long getSAXLoadTime() {
461 return saxTime;
462 }
463
464
465 public long getLoadMem() {
466 return loadMem;
467 }
468
469
470 public long getDumpTime() {
471 return dumpTime;
472 }
473
474 public long getDupeTime() {
475 return dupeTime;
476 }
477
478 public long getXpathTime() {
479 return xpathTime;
480 }
481
482 public long getCheckedTime() {
483 return checkedTime;
484 }
485
486 public long getUncheckedTime() {
487 return uncheckedTime;
488 }
489
490
491 public long getScanTime() {
492 return scanTime;
493 }
494
495
496
497 public long getSaxDTime() {
498 return saxDTime;
499 }
500
501 public long getDomDTime() {
502 return domDTime;
503 }
504
505 public long getStaxDTime() {
506 return staxDTime;
507 }
508
509
510 public long getStaxETime() {
511 return staxETime;
512 }
513
514 public long getStaxDETime() {
515 return staxDETime;
516 }
517
518 public Document getDocument() {
519 return document;
520 }
521
522 @Override
523 public String toString() {
524 return String.format("PerfDoc %s mem=%d sax=%d dom=%d stax=%d scan=%d xpath=%d dump=%d",
525 infile.getPath(), loadMem, saxTime, domTime, staxTime, scanTime, xpathTime, dumpTime);
526 }
527
528 private static final org.w3c.dom.Document getDocument(InputSource data, boolean xsdvalidate) throws ParserConfigurationException, SAXException, IOException {
529 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
530 dbf.setNamespaceAware(true);
531 dbf.setValidating(xsdvalidate);
532 dbf.setExpandEntityReferences(false);
533
534 if (xsdvalidate) {
535 dbf.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
536 }
537 DocumentBuilder db = dbf.newDocumentBuilder();
538 return db.parse(data);
539 }
540 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55 package org.jdom.contrib.perf;
56
57 import java.io.File;
58 import java.io.FileFilter;
59 import java.io.IOException;
60 import java.util.ArrayList;
61 import java.util.List;
62
63
64 @SuppressWarnings("javadoc")
65 public class PerfTest {
66
67 public static final long timeRun(TimeRunnable torun) throws Exception {
68 long min = Long.MAX_VALUE;
69 long max = Long.MIN_VALUE;
70 long sum = 0L;
71 final int cnt = 12;
72 for (int i = 0 ; i < cnt; i++) {
73 System.gc();
74 long time = System.nanoTime();
75 torun.run();
76 time = System.nanoTime() - time;
77 if (time > max) {
78 max = time;
79 }
80 if (time < min) {
81 min = time;
82 }
83 sum += time;
84 }
85 return (sum - (min + max)) / (cnt - 2);
86 }
87
88
89 public static final long usedMem() {
90 long mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
91 boolean stable = false;
92 Thread gct = new Thread("GCPrompt") {
93 @Override
94 public void run() {
95 System.gc();
96 }
97 };
98 gct.setDaemon(true);
99 try {
100 gct.start();
101 Thread.sleep(100);
102 gct.join();
103 } catch (Exception e) {
104 // ignore;
105 }
106 do {
107 int cnt = 3;
108 while (--cnt >= 0) {
109 System.gc();
110 }
111 long tmpmem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
112 long diff = mem - tmpmem;
113 mem = tmpmem;
114 if (diff >= 0 && diff < 128) {
115 stable = true;
116 }
117 } while (!stable);
118 return mem;
119 }
120
121 private static final String[] suffix = new String[]{"Bytes", "KiB", "MiB", "GiB", "TiB" };
122
123 private static final String formatMem(long mem) {
124 double frac = mem;
125 int cnt = 0;
126 while (frac > 1024.0) {
127 frac /= 1024.0;
128 cnt++;
129 }
130 return String.format("%.2f%s", frac, suffix[cnt]);
131 }
132
133 /**
134 * @param args
135 */
136 public static void main(String[] args) {
137 ArrayList<File> infiles = new ArrayList<File>();
138
139 final FileFilter filefilter = new FileFilter() {
140 @Override
141 public boolean accept(File path) {
142 return path.isFile() && path.getName().toLowerCase().endsWith(".xml");
143 }
144 };
145
146 for (String arg : args) {
147 File f = new File(arg);
148 if (f.exists()) {
149 if (f.isFile() && f.getName().toLowerCase().endsWith(".xml")) {
150 infiles.add(f);
151 } else if (f.isDirectory()) {
152 File[] files = f.listFiles(filefilter);
153 if (files.length > 0) {
154 for (File sf : files) {
155 infiles.add(sf);
156 }
157 } else {
158 System.err.println("Ignoring File " + f + ": Directory has no XML files.");
159 }
160 } else {
161 System.err.println("Ignoring File " + f + ": not .xml and not Directory.");
162 }
163 } else {
164 System.err.println("Ignoring File " + f + ": does not exist.");
165 }
166 }
167
168 if (infiles.isEmpty()) {
169 File tryhamlet = new File("contrib/src/resources/hamlet.xml");
170 if (tryhamlet.exists()) {
171 System.out.println("Using default file " + tryhamlet);
172 infiles.add(tryhamlet);
173 }
174 }
175
176 System.out.printf("Processing %d files.\n", infiles.size());
177
178 StringBuilder html = new StringBuilder();
179
180 perfloop(infiles, html);
181 perfloop(infiles, html);
182 System.out.println("Ignore the above warm-up results!\n\n");
183
184 html.setLength(0);
185 html.append("\n\t<hr/>\n\t<p/>\n\tDescription - change me\n\t<br />\n\t<table border=\"1\">\n\t\t<tr>");
186 for (String h : new String[] {"Input", "JDOM", "SAX", "SAXJ", "DOM", "DOMJ",
187 "StAXS", "StAXSJ", "StAXE", "StAXEJ", "Scan", "Dump",
188 "Dupe", "XPath", "Checked", "UnChecked"}) {
189 html.append("<th>").append(h).append("</th>");
190 }
191 html.append("</tr>\n");
192
193 for (int i = 0; i < 5; i++) {
194 perfloop(infiles, html);
195 }
196
197 html.append("\t</table>\n");
198
199 System.out.println(html.toString());
200 }
201
202 private static final void perfloop(List<File> infiles, StringBuilder html) {
203
204 double mstime = 1000000.0;
205
206 PerfDoc[] docs = new PerfDoc[infiles.size()];
207 int cnt = 0;
208 long bytecnt = 0L;
209 for (File f : infiles) {
210 try {
211 docs[cnt++] = new PerfDoc(f);
212 } catch (IOException e) {
213 throw new IllegalStateException("Unable to load " + f, e);
214 }
215 bytecnt += f.length();
216 }
217
218 long loadmem = 0L;
219 long saxtime = 0L;
220 long saxdtime = 0L;
221
222
223 long startmem = usedMem();
224 for (PerfDoc pd : docs) {
225 try {
226 saxtime += pd.saxLoad();
227 loadmem += pd.getLoadMem();
228 saxdtime += pd.getSaxDTime();
229 // System.out.println("Loaded " + pd.getFile());
230 } catch (Exception e) {
231 System.err.println("Failed to load " + pd);
232 e.printStackTrace();
233 }
234 }
235
236 long actloadmem = usedMem() - startmem;
237
238 double pctdiff = ((actloadmem - loadmem) * 100.0) / actloadmem;
239 if (pctdiff < 0.0) {
240 pctdiff = -1.0 * pctdiff;
241 }
242 if (pctdiff > 1.0) {
243 throw new IllegalStateException(
244 String.format("Memory calculations do not add up direct=%s sum=%s.",
245 formatMem(actloadmem), formatMem(loadmem)));
246 }
247
248 usedMem();
249
250 long domtime = 0L;
251 long domdtime = 0L;
252 for (PerfDoc pd : docs) {
253 try {
254 domtime += pd.domLoad();
255 domdtime += pd.getDomDTime();
256 } catch (Exception e) {
257 System.err.println("Failed to DOM " + pd);
258 e.printStackTrace();
259 }
260 }
261
262 usedMem();
263
264 long staxtime = 0L;
265 long staxdtime = 0L;
266 for (PerfDoc pd : docs) {
267 try {
268 staxtime += pd.staxLoad();
269 staxdtime += pd.getStaxDTime();
270 } catch (Exception e) {
271 System.err.println("Failed to STAX " + pd);
272 e.printStackTrace();
273 }
274 }
275
276 usedMem();
277
278 long staxetime = 0L;
279 long staxdetime = 0L;
280 for (PerfDoc pd : docs) {
281 try {
282 staxetime += pd.staxELoad();
283 staxdetime += pd.getStaxDETime();
284 } catch (Exception e) {
285 System.err.println("Failed to STAX " + pd);
286 e.printStackTrace();
287 }
288 }
289
290 long scantime = 0L;
291 for (PerfDoc pd : docs) {
292 try {
293 scantime += pd.scan();
294 } catch (Exception e) {
295 System.err.println("Failed to scan " + pd);
296 e.printStackTrace();
297 }
298 }
299
300 usedMem();
301
302 long dumptime = 0L;
303 for (PerfDoc pd : docs) {
304 try {
305 dumptime += pd.dump();
306 } catch (Exception e) {
307 System.err.println("Failed to dump " + pd);
308 e.printStackTrace();
309 }
310 }
311
312 usedMem();
313
314 long dupetime = 0L;
315 for (PerfDoc pd : docs) {
316 try {
317 dupetime += pd.duplicate();
318 } catch (Exception e) {
319 System.err.println("Failed to dupe " + pd);
320 e.printStackTrace();
321 }
322 }
323
324 usedMem();
325
326 long xpathtime = 0L;
327 for (PerfDoc pd : docs) {
328 try {
329 xpathtime += pd.xpath();
330 } catch (Exception e) {
331 System.err.println("Failed to xpath " + pd);
332 e.printStackTrace();
333 }
334 }
335
336 usedMem();
337
338 long checkedtime = 0L;
339 for (PerfDoc pd : docs) {
340 try {
341 checkedtime += pd.checkedParse();
342 } catch (Exception e) {
343 System.err.println("Failed to checked-parse " + pd);
344 e.printStackTrace();
345 }
346 }
347
348 long uncheckedtime = 0L;
349 for (PerfDoc pd : docs) {
350 try {
351 uncheckedtime += pd.unCheckedParse();
352 } catch (Exception e) {
353 System.err.println("Failed to unchecked-parse " + pd);
354 e.printStackTrace();
355 }
356 }
357
358 System.out.printf ("PERF: loadbytes=%s loadmem=%s sax=%.2fb(%.2fb) dom=%.2fb(%.2fb) " +
359 "staxs=%.2fb(%.2fb) staxe=%.2fb(%.2fb) " +
360 "scan=%.2fb dump=%.2fb dupe=%.2fb xpath=%.2fb checked=%.2fb unchecked=%.2fb \n",
361 formatMem(bytecnt), formatMem(loadmem), saxtime / mstime, saxdtime / mstime,
362 domtime / mstime, domdtime / mstime, staxtime / mstime, staxdtime / mstime,
363 staxetime / mstime, staxdetime / mstime,
364 scantime / mstime, dumptime / mstime, dupetime / mstime,
365 xpathtime / mstime, checkedtime / mstime, uncheckedtime / mstime);
366
367 html.append("\t\t<tr><td>").append(formatMem(bytecnt)).append("</td><td>")
368 .append(formatMem(loadmem)).append("</td>");
369
370 long[] times = new long[] {saxtime, saxtime - saxdtime, domtime, domtime - domdtime,
371 staxtime, staxtime - staxdtime, staxetime, staxetime - staxdetime,
372 scantime, dumptime, dupetime,
373 xpathtime, checkedtime, uncheckedtime};
374 for (long t : times) {
375 html.append("<td>").append(String.format("%.2fms", t / mstime)).append("</td>");
376 }
377 html.append("</tr>\n");
378
379
380 }
381
382 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55 package org.jdom.contrib.perf;
56
57 import java.io.File;
58 import java.io.FileInputStream;
59 import java.io.IOException;
60 import java.io.InputStreamReader;
61 import java.nio.charset.Charset;
62 import java.util.ArrayList;
63
64 import org.jdom.Verifier;
65
66 /**
67 * This class is designed to test the performance of the JDOM Verifier.
68 * It does that by repeatedly parsing a document through a verifierd JDOM sequence, and then
69 * comparing the time to a non-verified parsing. The time differences is accounted for by
70 * verifying overhead.
71 *
72 * @author Rolf Lear
73 *
74 */
75 public class PerfVerifier {
76
77 @SuppressWarnings("javadoc")
78 public static void main(final String[] args) throws InterruptedException {
79 Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
80 if (args.length != 1) {
81 throw new IllegalArgumentException("We expect a single directory argument.");
82 }
83 final File dir = new File(args[0]);
84 if (!dir.isDirectory()) {
85 throw new IllegalArgumentException("We expect a single directory argument.");
86 }
87
88 final int bestcnt = 50;
89
90 long[] sattnanos = new long[bestcnt];
91 long[] semtnanos = new long[bestcnt];
92 long[] schrnanos = new long[bestcnt];
93 long start = 0L;
94
95 System.out.println("Loading data");
96
97 final String[] attnames = parseFile(new File(dir, "checkAttributeName.txt"));
98 final String[] emtnames = parseFile(new File(dir, "checkElementName.txt"));
99 final String[] chardata = parseFile(new File(dir, "checkCharacterData.txt"));
100
101
102 System.out.println("Stabilize");
103 Thread.sleep(5000);
104 final long prebytes = getMemUsed();
105
106 System.out.println("Launch");
107
108 int i = 0;
109 int cnt = bestcnt * 4;
110 while (--cnt >= 0) {
111 long attnanos = 0L;
112 long emtnanos = 0L;
113 long chrnanos = 0L;
114
115 start = System.nanoTime();
116 for (i = attnames.length - 1; i >= 0; i--) {
117 Verifier.checkAttributeName(attnames[i]);
118 }
119 attnanos = System.nanoTime() - start;
120
121 start = System.nanoTime();
122 for (i = emtnames.length - 1; i >= 0; i--) {
123 Verifier.checkElementName(emtnames[i]);
124 }
125 emtnanos = System.nanoTime() - start;
126
127 start = System.nanoTime();
128
129 for (i = chardata.length - 1; i >= 0; i--) {
130 Verifier.checkCharacterData(chardata[i]);
131 }
132 chrnanos = System.nanoTime() - start;
133
134 System.out.printf(" Loop %2d took: att=%.3fms emt=%.3fms char=%.3fms\n", cnt,
135 attnanos / 1000000.0, emtnanos / 1000000.0, chrnanos / 1000000.0);
136
137 insertTime(sattnanos, attnanos);
138 insertTime(semtnanos, emtnanos);
139 insertTime(schrnanos, chrnanos);
140
141 }
142
143 final long memused = getMemUsed() - prebytes;
144
145 System.out.printf(" Validating took: att=%.3fms emt=%.3fms char=%.3fms mem=%.3fKB\n",
146 avg(sattnanos) / 1000000.0, avg(semtnanos) / 1000000.0, avg(schrnanos) / 1000000.0,
147 memused / 1024.0);
148
149 Verifier.isAllXMLWhitespace(" ");
150 System.out.println("Checks " + (chardata.length + emtnames.length + attnames.length));
151 }
152
153 private static final void insertTime(final long[] array, final long time) {
154 int index = array.length -1;
155 while (index >= 0 && (array[index] == 0L || time < array[index])) {
156 index--;
157 }
158 index++;
159 if (index < array.length) {
160 System.arraycopy(array, index, array, index+1, array.length - index - 1);
161 array[index] = time;
162 }
163 }
164
165 private static final double avg(final long[] values) {
166 long ret = 0L;
167 for (long v : values) {
168 ret += v;
169 }
170 return ret / (double)values.length;
171 }
172
173 private static long getMemUsed() {
174 long minused = Long.MAX_VALUE;
175 int cnt = 0;
176 final Runtime rt = Runtime.getRuntime();
177 try {
178 while (cnt < 3) {
179 System.gc();
180 Thread.yield();
181 Thread.sleep(100);
182 long used = rt.totalMemory() - rt.freeMemory();
183 if (used < minused) {
184 cnt = 0;
185 minused = used;
186 } else {
187 cnt++;
188 }
189 }
190 } catch (InterruptedException ie) {
191 throw new IllegalStateException("Interrupted", ie);
192 }
193 return minused;
194 }
195
196 private static final String[] parseFile(File file) {
197 try {
198 final StringBuilder sb = new StringBuilder(1024);
199 final ArrayList<String> vals = new ArrayList<String>(10240);
200 final FileInputStream fis = new FileInputStream(file);
201 final InputStreamReader isr = new InputStreamReader(fis, Charset.forName("UTF-8"));
202 System.out.println("Loading " + file.getPath());
203 int c = 0;
204 while ((c = isr.read()) >= 0) {
205 if (c == 0) {
206 vals.add(sb.toString());
207 sb.setLength(0);
208 } else {
209 sb.append((char)c);
210 }
211 }
212 fis.close();
213
214 final String[] ret = new String[vals.size()];
215 vals.toArray(ret);
216 return ret;
217 } catch (IOException ioe) {
218 ioe.printStackTrace();
219 return null;
220 }
221 }
222
223 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.perf;
55
56 import java.io.BufferedWriter;
57 import java.io.FileOutputStream;
58 import java.io.IOException;
59 import java.io.OutputStreamWriter;
60 import java.io.Writer;
61 import java.nio.charset.Charset;
62 import java.util.*;
63 import java.util.concurrent.atomic.AtomicBoolean;
64
65 import org.jdom.Attribute;
66 import org.jdom.CDATA;
67 import org.jdom.Comment;
68 import org.jdom.DocType;
69 import org.jdom.Element;
70 import org.jdom.EntityRef;
71 import org.jdom.Namespace;
72 import org.jdom.ProcessingInstruction;
73
74 /**
75 * NOTE
76 * ====
77 * This is a clone of the pre-bitmask Verifier.java file, and then modified to 'save' the
78 * checked data from the verifier. Used with PerfVerifier to test the Verfier performance.
79 *
80 *
81 * Old Comments:
82 * =============
83 * A utility class to handle well-formedness checks on names, data, and other
84 * verification tasks for JDOM. The class is final and may not be subclassed.
85 *
86 * @author Brett McLaughlin
87 * @author Elliotte Rusty Harold
88 * @author Jason Hunter
89 * @author Bradley S. Huffman
90 * @author Rolf Lear
91 */
92 final public class SavingVerifier {
93
94 private static final AtomicBoolean open = new AtomicBoolean(true);
95
96 private static final Writer getWriter(final String name) {
97 try {
98 final FileOutputStream fos = new FileOutputStream(name);
99 final OutputStreamWriter osw = new OutputStreamWriter(fos, Charset.forName("UTF-8"));
100 return new BufferedWriter(osw);
101 } catch (IOException ioe) {
102 ioe.printStackTrace();
103 open.set(false);
104 return null;
105 }
106 }
107
108 private static final void write(Writer writer, String value) {
109 if (open.get()) {
110 try {
111 writer.write(value);
112 writer.write((char)0);
113 } catch (IOException e) {
114 e.printStackTrace();
115 }
116 }
117 }
118
119 private static final String elementfilename = "checkElementName.txt";
120 private static final String attributefilename = "checkAttributeName.txt";
121 private static final String chardatafilename = "checkCharacterData.txt";
122
123 private static final Writer elementnamewriter = getWriter(elementfilename);
124 private static final Writer attributenamewriter = getWriter(attributefilename);
125 private static final Writer characterdatawriter = getWriter(chardatafilename);
126
127 @SuppressWarnings("javadoc")
128 public static final void closeWriters() throws IOException {
129 if (!open.getAndSet(false)) {
130 return;
131 }
132 open.set(false);
133 elementnamewriter.flush();
134 elementnamewriter.close();
135 attributenamewriter.flush();
136 attributenamewriter.close();
137 characterdatawriter.flush();
138 characterdatawriter.close();
139 }
140
141 /**
142 * Ensure instantation cannot occur.
143 */
144 private SavingVerifier() { }
145
146 /**
147 * This will check the supplied name to see if it is legal for use as
148 * a JDOM <code>{@link Element}</code> name.
149 *
150 * @param name <code>String</code> name to check.
151 * @return <code>String</code> reason name is illegal, or
152 * <code>null</code> if name is OK.
153 */
154 public static String checkElementName(final String name) {
155
156 write(elementnamewriter, name);
157
158 // Check basic XML name rules first
159 if (checkXMLName(name) != null) {
160 return checkXMLName(name);
161 }
162
163 // No colons allowed, since elements handle this internally
164 if (name.indexOf(":") != -1) {
165 return "Element names cannot contain colons";
166 }
167
168 // If we got here, everything is OK
169 return null;
170 }
171
172 /**
173 * This will check the supplied name to see if it is legal for use as
174 * a JDOM <code>{@link Attribute}</code> name.
175 *
176 * @param name <code>String</code> name to check.
177 * @return <code>String</code> reason name is illegal, or
178 * <code>null</code> if name is OK.
179 */
180 public static String checkAttributeName(final String name) {
181
182 write(attributenamewriter, name);
183
184 // Check basic XML name rules first
185 if (checkXMLName(name) != null) {
186 return checkXMLName(name);
187 }
188
189 // No colons are allowed, since attributes handle this internally
190 if (name.indexOf(":") != -1) {
191 return "Attribute names cannot contain colons";
192 }
193
194 // Attribute names may not be xmlns since we do this internally too
195 if (name.equals("xmlns")) {
196 return "An Attribute name may not be \"xmlns\"; " +
197 "use the Namespace class to manage namespaces";
198 }
199
200 // If we got here, everything is OK
201 return null;
202 }
203
204 /**
205 * This will check the supplied string to see if it only contains
206 * characters allowed by the XML 1.0 specification. The C0 controls
207 * (e.g. null, vertical tab, form-feed, etc.) are specifically excluded
208 * except for carriage return, line-feed, and the horizontal tab.
209 * Surrogates are also excluded.
210 * <p>
211 * This method is useful for checking element content and attribute
212 * values. Note that characters
213 * like " and &lt; are allowed in attribute values and element content.
214 * They will simply be escaped as &quot; or &lt;
215 * when the value is serialized.
216 * </p>
217 *
218 * @param text <code>String</code> value to check.
219 * @return <code>String</code> reason name is illegal, or
220 * <code>null</code> if name is OK.
221 */
222 public static String checkCharacterData(final String text) {
223 write(characterdatawriter, text);
224 if (text == null) {
225 return "A null is not a legal XML value";
226 }
227
228 // lowx indicates we expect a low surrogate next.
229 boolean lowx = false;
230 final int len = text.length();
231 for (int i = 0; i < len; i++) {
232 // we are expecting a normal char, but may be a surrogate.
233 if (isXMLCharacter(text.charAt(i))) {
234 if (lowx) {
235 // we got a normal character, but we wanted a low surrogate
236 return String.format("Illegal Surrogate Pair 0x%04x%04x",
237 (int)text.charAt(i - 1), (int)text.charAt(i));
238 }
239 } else {
240 // the character is not a normal character.
241 // we need to sort out what it is. Neither high nor low
242 // surrogate pairs are valid characters, so they will get here.
243
244 if (!lowx && isHighSurrogate(text.charAt(i))) {
245 // we have the valid high char of a pair.
246 // we will expect the low char on the next loop through,
247 // so mark the high char, and move on.
248 lowx = true;
249 } else if (lowx && isLowSurrogate(text.charAt(i))) {
250 // we now have the low char of a pair, decode and validate
251 final int chi = decodeSurrogatePair(
252 text.charAt(i - 1), text.charAt(i));
253 if (!isXMLCharacter(chi)) {
254 // Likely this character can't be easily displayed
255 // because it's a control so we use it'd hexadecimal
256 // representation in the reason.
257 return String.format("0x%06x is not a legal XML character",
258 chi);
259 }
260 lowx = false;
261 } else {
262 // Likely this character can't be easily displayed
263 // because it's a control so we use it's hexadecimal
264 // representation in the reason.
265 return String.format("0x%04x is not a legal XML character",
266 (int)text.charAt(i));
267 }
268 }
269 }
270
271 if (lowx) {
272 return String.format("Truncated Surrogate Pair 0x%04x????",
273 (int)text.charAt(text.length() - 1));
274 }
275
276 // If we got here, everything is OK
277 return null;
278 }
279
280 /**
281 * This will check the supplied data to see if it is legal for use as
282 * JDOM <code>{@link CDATA}</code>.
283 *
284 * @param data <code>String</code> data to check.
285 * @return <code>String</code> reason data is illegal, or
286 * <code>null</code> is name is OK.
287 */
288 public static String checkCDATASection(final String data) {
289 String reason = null;
290 if ((reason = checkCharacterData(data)) != null) {
291 return reason;
292 }
293
294 if (data.indexOf("]]>") != -1) {
295 return "CDATA cannot internally contain a CDATA ending " +
296 "delimiter (]]>)";
297 }
298
299 // If we got here, everything is OK
300 return null;
301 }
302
303 /**
304 * This will check the supplied name to see if it is legal for use as
305 * a JDOM <code>{@link Namespace}</code> prefix.
306 *
307 * @param prefix <code>String</code> prefix to check.
308 * @return <code>String</code> reason name is illegal, or
309 * <code>null</code> if name is OK.
310 */
311 public static String checkNamespacePrefix(final String prefix) {
312 // Manually do rules, since URIs can be null or empty
313 if ((prefix == null) || (prefix.equals(""))) {
314 return null;
315 }
316
317 // Cannot start with a number
318 final char first = prefix.charAt(0);
319 if (isXMLDigit(first)) {
320 return "Namespace prefixes cannot begin with a number";
321 }
322 // Cannot start with a $
323 if (first == '$') {
324 return "Namespace prefixes cannot begin with a dollar sign ($)";
325 }
326 // Cannot start with a -
327 if (first == '-') {
328 return "Namespace prefixes cannot begin with a hyphen (-)";
329 }
330 // Cannot start with a .
331 if (first == '.') {
332 return "Namespace prefixes cannot begin with a period (.)";
333 }
334 // Cannot start with "xml" in any character case
335 if (prefix.toLowerCase().startsWith("xml")) {
336 return "Namespace prefixes cannot begin with " +
337 "\"xml\" in any combination of case";
338 }
339
340 // Ensure legal content
341 for (int i=0, len = prefix.length(); i<len; i++) {
342 final char c = prefix.charAt(i);
343 if (!isXMLNameCharacter(c)) {
344 return "Namespace prefixes cannot contain the character \"" +
345 c + "\"";
346 }
347 }
348
349 // No colons allowed
350 if (prefix.indexOf(":") != -1) {
351 return "Namespace prefixes cannot contain colons";
352 }
353
354 // If we got here, everything is OK
355 return null;
356 }
357
358 /**
359 * This will check the supplied name to see if it is legal for use as
360 * a JDOM <code>{@link Namespace}</code> URI.
361 * <p>
362 * This is a 'light' test of URI's designed to filter out only the worst
363 * illegal URIs. It tests only to ensure the first character is valid. A
364 * comprehensive URI validation process would be impractical.
365 *
366 * @param uri <code>String</code> URI to check.
367 * @return <code>String</code> reason name is illegal, or
368 * <code>null</code> if name is OK.
369 */
370 public static String checkNamespaceURI(final String uri) {
371 // Manually do rules, since URIs can be null or empty
372 if ((uri == null) || (uri.equals(""))) {
373 return null;
374 }
375
376 // Cannot start with a number
377 final char first = uri.charAt(0);
378 if (Character.isDigit(first)) {
379 return "Namespace URIs cannot begin with a number";
380 }
381 // Cannot start with a $
382 if (first == '$') {
383 return "Namespace URIs cannot begin with a dollar sign ($)";
384 }
385 // Cannot start with a -
386 if (first == '-') {
387 return "Namespace URIs cannot begin with a hyphen (-)";
388 }
389
390 // Cannot start with space...
391 if (isXMLWhitespace(first)) {
392 return "Namespace URIs cannot begin with white-space";
393 }
394
395 // If we got here, everything is OK
396 return null;
397 }
398
399 /**
400 * Check if two namespaces collide.
401 *
402 * @param namespace <code>Namespace</code> to check.
403 * @param other <code>Namespace</code> to check against.
404 * @return <code>String</code> reason for collision, or
405 * <code>null</code> if no collision.
406 */
407 public static String checkNamespaceCollision(final Namespace namespace,
408 final Namespace other) {
409 String p1,p2,u1,u2,reason;
410
411 reason = null;
412 p1 = namespace.getPrefix();
413 u1 = namespace.getURI();
414 p2 = other.getPrefix();
415 u2 = other.getURI();
416 if (p1.equals(p2) && !u1.equals(u2)) {
417 reason = "The namespace prefix \"" + p1 + "\" collides";
418 }
419 return reason;
420 }
421
422 /**
423 * Check if <code>{@link Attribute}</code>'s namespace collides with a
424 * <code>{@link Element}</code>'s namespace.
425 *
426 * @param attribute <code>Attribute</code> to check.
427 * @param element <code>Element</code> to check against.
428 * @return <code>String</code> reason for collision, or
429 * <code>null</code> if no collision.
430 */
431 public static String checkNamespaceCollision(final Attribute attribute,
432 final Element element) {
433 return checkNamespaceCollision(attribute, element, -1);
434 }
435
436 /**
437 * Check if <code>{@link Attribute}</code>'s namespace collides with a
438 * <code>{@link Element}</code>'s namespace.
439 *
440 * @param attribute <code>Attribute</code> to check.
441 * @param element <code>Element</code> to check against.
442 * @param ignoreatt Ignore a specific Attribute (if it exists) when
443 * calculating any collisions (used when replacing one attribute
444 * with another).
445 * @return <code>String</code> reason for collision, or
446 * <code>null</code> if no collision.
447 */
448 public static String checkNamespaceCollision(final Attribute attribute,
449 final Element element, final int ignoreatt) {
450 final Namespace namespace = attribute.getNamespace();
451 final String prefix = namespace.getPrefix();
452 if ("".equals(prefix)) {
453 return null;
454 }
455
456 return checkNamespaceCollision(namespace, element, ignoreatt);
457 }
458
459 /**
460 * Check if a <code>{@link Namespace}</code> collides with a
461 * <code>{@link Element}</code>'s namespace.
462 *
463 * @param namespace <code>Namespace</code> to check.
464 * @param element <code>Element</code> to check against.
465 * @return <code>String</code> reason for collision, or
466 * <code>null</code> if no collision.
467 */
468 public static String checkNamespaceCollision(final Namespace namespace,
469 final Element element) {
470 return checkNamespaceCollision(namespace, element, -1);
471 }
472
473 /**
474 * Check if a <code>{@link Namespace}</code> collides with a
475 * <code>{@link Element}</code>'s namespace.
476 *
477 * @param namespace <code>Namespace</code> to check.
478 * @param element <code>Element</code> to check against.
479 * @param ignoreatt Ignore a specific Attribute (if it exists) when
480 * calculating any collisions (used when replacing one attribute
481 * with another).
482 * @return <code>String</code> reason for collision, or
483 * <code>null</code> if no collision.
484 */
485 public static String checkNamespaceCollision(final Namespace namespace,
486 final Element element, final int ignoreatt) {
487 String reason = checkNamespaceCollision(namespace,
488 element.getNamespace());
489 if (reason != null) {
490 return reason + " with the element namespace prefix";
491 }
492
493 if (element.hasAdditionalNamespaces()) {
494 reason = checkNamespaceCollision(namespace,
495 element.getAdditionalNamespaces());
496 if (reason != null) {
497 return reason;
498 }
499 }
500
501 if (element.hasAttributes()) {
502 reason = checkNamespaceCollision(namespace, element.getAttributes(), ignoreatt);
503 if (reason != null) {
504 return reason;
505 }
506 }
507
508 return null;
509 }
510
511 /**
512 * Check if a <code>{@link Namespace}</code> collides with a
513 * <code>{@link Attribute}</code>'s namespace.
514 *
515 * @param namespace <code>Namespace</code> to check.
516 * @param attribute <code>Attribute</code> to check against.
517 * @return <code>String</code> reason for collision, or
518 * <code>null</code> if no collision.
519 */
520 public static String checkNamespaceCollision(final Namespace namespace,
521 final Attribute attribute) {
522 String reason = null;
523 if (!attribute.getNamespace().equals(Namespace.NO_NAMESPACE)) {
524 reason = checkNamespaceCollision(namespace,
525 attribute.getNamespace());
526 if (reason != null) {
527 reason += " with an attribute namespace prefix on the element";
528 }
529 }
530 return reason;
531 }
532
533 /**
534 * Check if a <code>{@link Namespace}</code> collides with any namespace
535 * from a list of objects.
536 *
537 * @param namespace <code>Namespace</code> to check.
538 * @param list <code>List</code> to check against.
539 * @return <code>String</code> reason for collision, or
540 * <code>null</code> if no collision.
541 */
542 public static String checkNamespaceCollision(final Namespace namespace,
543 final List<?> list) {
544 return checkNamespaceCollision(namespace, list, -1);
545 }
546
547 /**
548 * Check if a <code>{@link Namespace}</code> collides with any namespace
549 * from a list of objects.
550 *
551 * @param namespace <code>Namespace</code> to check.
552 * @param list <code>List</code> to check against.
553 * @param ignoreatt Ignore a specific Attribute (if it exists) when
554 * calculating any collisions (used when replacing one attribute
555 * with another).
556 * @return <code>String</code> reason for collision, or
557 * <code>null</code> if no collision.
558 */
559 public static String checkNamespaceCollision(final Namespace namespace,
560 final List<?> list, final int ignoreatt) {
561 if (list == null) {
562 return null;
563 }
564
565 String reason = null;
566 final Iterator<?> i = list.iterator();
567 int cnt = -1;
568 while ((reason == null) && i.hasNext()) {
569 final Object obj = i.next();
570 cnt++;
571 if (obj instanceof Attribute) {
572 if (cnt == ignoreatt) {
573 continue;
574 }
575 reason = checkNamespaceCollision(namespace, (Attribute) obj);
576 }
577 else if (obj instanceof Element) {
578 reason = checkNamespaceCollision(namespace, (Element) obj);
579 }
580 else if (obj instanceof Namespace) {
581 reason = checkNamespaceCollision(namespace, (Namespace) obj);
582 if (reason != null) {
583 reason += " with an additional namespace declared" +
584 " by the element";
585 }
586 }
587 }
588 return reason;
589 }
590
591 /**
592 * This will check the supplied data to see if it is legal for use as
593 * a JDOM <code>{@link ProcessingInstruction}</code> target.
594 *
595 * @param target <code>String</code> target to check.
596 * @return <code>String</code> reason target is illegal, or
597 * <code>null</code> if target is OK.
598 */
599 public static String checkProcessingInstructionTarget(final String target) {
600 // Check basic XML name rules first
601 String reason;
602 if ((reason = checkXMLName(target)) != null) {
603 return reason;
604 }
605
606 // No colons allowed, per Namespace Specification Section 6
607 if (target.indexOf(":") != -1) {
608 return "Processing instruction targets cannot contain colons";
609 }
610
611 // Cannot begin with 'xml' in any case
612 if (target.equalsIgnoreCase("xml")) {
613 return "Processing instructions cannot have a target of " +
614 "\"xml\" in any combination of case. (Note that the " +
615 "\"<?xml ... ?>\" declaration at the beginning of a " +
616 "document is not a processing instruction and should not " +
617 "be added as one; it is written automatically during " +
618 "output, e.g. by XMLOutputter.)";
619 }
620
621 // If we got here, everything is OK
622 return null;
623 }
624
625 /**
626 * This will check the supplied data to see if it is legal for use as
627 * <code>{@link ProcessingInstruction}</code> data. Besides checking that
628 * all the characters are allowed in XML, this also checks
629 * that the data does not contain the PI end-string "?&gt;".
630 *
631 * @param data <code>String</code> data to check.
632 * @return <code>String</code> reason data is illegal, or
633 * <code>null</code> if data is OK.
634 */
635 public static String checkProcessingInstructionData(final String data) {
636 // Check basic XML name rules first
637 final String reason = checkCharacterData(data);
638
639 if (reason == null) {
640 if (data.indexOf("?>") >= 0) {
641 return "Processing instructions cannot contain " +
642 "the string \"?>\"";
643 }
644 }
645
646 return reason;
647 }
648
649 /**
650 * This will check the supplied data to see if it is legal for use as
651 * JDOM <code>{@link Comment}</code> data.
652 *
653 * @param data <code>String</code> data to check.
654 * @return <code>String</code> reason data is illegal, or
655 * <code>null</code> if data is OK.
656 */
657 public static String checkCommentData(final String data) {
658 String reason = null;
659 if ((reason = checkCharacterData(data)) != null) {
660 return reason;
661 }
662
663 if (data.indexOf("--") != -1) {
664 return "Comments cannot contain double hyphens (--)";
665 }
666 if (data.endsWith("-")) {
667 return "Comment data cannot end with a hyphen.";
668 }
669
670 // If we got here, everything is OK
671 return null;
672 }
673 /**
674 * This is a utility function to decode a non-BMP
675 * UTF-16 surrogate pair.
676 * @param high high 16 bits
677 * @param low low 16 bits
678 * @return decoded character
679 */
680 public static int decodeSurrogatePair(final char high, final char low) {
681 return 0x10000 + (high - 0xD800) * 0x400 + (low - 0xDC00);
682 }
683
684 /**
685 * This will check the supplied data to see if it is legal for use as
686 * PublicID (in a {@link DocType} or {@link EntityRef}).
687 *
688 * @param c the character to validate
689 * @return <code>String</code> reason <i>c</i> is illegal, or
690 * <code>null</code> if <i>c</i> is OK.
691 */
692 public static boolean isXMLPublicIDCharacter(final char c) {
693 // [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] |
694 // [-'()+,./:=?;*#@$_%]
695
696 if (c >= 'a' && c <= 'z') return true;
697 if (c >= '?' && c <= 'Z') return true;
698 if (c >= '\'' && c <= ';') return true;
699
700 if (c == ' ') return true;
701 if (c == '!') return true;
702 if (c == '=') return true;
703 if (c == '#') return true;
704 if (c == '$') return true;
705 if (c == '_') return true;
706 if (c == '%') return true;
707 if (c == '\n') return true;
708 if (c == '\r') return true;
709 if (c == '\t') return true;
710
711 return false;
712 }
713
714 /**
715 * This will ensure that the data for a public identifier
716 * is legal.
717 *
718 * @param publicID <code>String</code> public ID to check.
719 * @return <code>String</code> reason public ID is illegal, or
720 * <code>null</code> if public ID is OK.
721 */
722 public static String checkPublicID(final String publicID) {
723 String reason = null;
724
725 if (publicID == null) return null;
726 // This indicates there is no public ID
727
728 for (int i = 0; i < publicID.length(); i++) {
729 final char c = publicID.charAt(i);
730 if (!isXMLPublicIDCharacter(c)) {
731 reason = c + " is not a legal character in public IDs";
732 break;
733 }
734 }
735
736 return reason;
737 }
738
739
740 /**
741 * This will ensure that the data for a system literal
742 * is legal.
743 *
744 * @param systemLiteral <code>String</code> system literal to check.
745 * @return <code>String</code> reason system literal is illegal, or
746 * <code>null</code> if system literal is OK.
747 */
748 public static String checkSystemLiteral(final String systemLiteral) {
749 String reason = null;
750
751 if (systemLiteral == null) return null;
752 // This indicates there is no system ID
753
754 if (systemLiteral.indexOf('\'') != -1
755 && systemLiteral.indexOf('"') != -1) {
756 reason =
757 "System literals cannot simultaneously contain both single and double quotes.";
758 }
759 else {
760 reason = checkCharacterData(systemLiteral);
761 }
762
763 return reason;
764 }
765
766 /**
767 * This is a utility function for sharing the base process of checking
768 * any XML name.
769 *
770 * @param name <code>String</code> to check for XML name compliance.
771 * @return <code>String</code> reason the name is illegal, or
772 * <code>null</code> if OK.
773 */
774 public static String checkXMLName(final String name) {
775 // Cannot be empty or null
776 if ((name == null)) {
777 return "XML names cannot be null";
778 }
779
780 final int len = name.length();
781 if (len == 0) {
782 return "XML names cannot be empty";
783 }
784
785
786 // Cannot start with a number
787 if (!isXMLNameStartCharacter(name.charAt(0))) {
788 return "XML names cannot begin with the character \"" +
789 name.charAt(0) + "\"";
790 }
791 // Ensure legal content for non-first chars
792 for (int i = 1; i < len; i++) {
793 if (!isXMLNameCharacter(name.charAt(i))) {
794 return "XML names cannot contain the character \"" + name.charAt(i) + "\"";
795 }
796 }
797
798 // We got here, so everything is OK
799 return null;
800 }
801
802 /**
803 * <p>
804 * Checks a string to see if it is a legal RFC 2396 URI.
805 * Both absolute and relative URIs are supported.
806 * </p>
807 *
808 * @param uri <code>String</code> to check.
809 * @return <code>String</code> reason the URI is illegal, or
810 * <code>null</code> if OK.
811 */
812 public static String checkURI(final String uri) {
813 // URIs can be null or empty
814 if ((uri == null) || (uri.equals(""))) {
815 return null;
816 }
817
818 for (int i = 0; i < uri.length(); i++) {
819 final char test = uri.charAt(i);
820 if (!isURICharacter(test)) {
821 String msgNumber = "0x" + Integer.toHexString(test);
822 if (test <= 0x09) msgNumber = "0x0" + Integer.toHexString(test);
823 return "URIs cannot contain " + msgNumber;
824 } // end if
825 if (test == '%') { // must be followed by two hexadecimal digits
826 try {
827 final char firstDigit = uri.charAt(i+1);
828 final char secondDigit = uri.charAt(i+2);
829 if (!isHexDigit(firstDigit) ||
830 !isHexDigit(secondDigit)) {
831 return "Percent signs in URIs must be followed by "
832 + "exactly two hexadecimal digits.";
833 }
834
835 }
836 catch (final StringIndexOutOfBoundsException e) {
837 return "Percent signs in URIs must be followed by "
838 + "exactly two hexadecimal digits.";
839 }
840 }
841 } // end for
842
843 // If we got here, everything is OK
844 return null;
845 }
846
847 /**
848 * <p>
849 * This is a utility function for determining whether a specified
850 * Unicode character is a hexadecimal digit as defined in RFC 2396;
851 * that is, one of the ASCII characters 0-9, a-f, or A-F.
852 * </p>
853 *
854 * @param c to check for hex digit.
855 * @return true if it's allowed, false otherwise.
856 */
857 public static boolean isHexDigit(final char c) {
858
859 // I suspect most characters passed to this method will be
860 // correct hexadecimal digits, so I test for the true cases
861 // first. If this proves to be a performance bottleneck
862 // a switch statement or lookup table
863 // might optimize this.
864 if (c >= '0' && c <= '9') return true;
865 if (c >= 'A' && c <= 'F') return true;
866 if (c >= 'a' && c <= 'f') return true;
867
868 return false;
869 }
870
871 /**
872 * This is a function for determining whether the
873 * specified character is the high 16 bits in a
874 * UTF-16 surrogate pair.
875 * @param ch character to check
876 * @return true if the character is a high surrogate, false otherwise
877 */
878 public static boolean isHighSurrogate(final char ch) {
879 // faster way to do it is with bit manipulation....
880 // return (ch >= 0xD800 && ch <= 0xDBFF);
881 // A high surrogate has the bit pattern:
882 // 110110xx xxxxxxxx
883 // ch & 0xFC00 does a bit-mask of the most significant 6 bits (110110)
884 // return 0xD800 == (ch & 0xFC00);
885 // as it happens, it is faster to do a bit-shift,
886 return 0x36 == ch >>> 10;
887 }
888
889 /**
890 * This is a function for determining whether the
891 * specified character is the low 16 bits in a
892 * UTF-16 surrogate pair.
893 * @param ch character to check
894 * @return true if the character is a low surrogate, false otherwise.
895 */
896 public static boolean isLowSurrogate(final char ch) {
897 // faster way to do it is with bit manipulation....
898 // return (ch >= 0xDC00 && ch <= 0xDFFF);
899 return 0x37 == ch >>> 10;
900 }
901
902 /**
903 * <p>
904 * This is a utility function for determining whether
905 * a specified Unicode character is legal in URI references
906 * as determined by RFC 2396.
907 * </p>
908 *
909 * @param c <code>char</code> to check for URI reference compliance.
910 * @return true if it's allowed, false otherwise.
911 */
912 public static boolean isURICharacter(final char c) {
913 if (c >= 'a' && c <= 'z') return true;
914 if (c >= 'A' && c <= 'Z') return true;
915 if (c >= '0' && c <= '9') return true;
916 if (c == '/') return true;
917 if (c == '-') return true;
918 if (c == '.') return true;
919 if (c == '?') return true;
920 if (c == ':') return true;
921 if (c == '@') return true;
922 if (c == '&') return true;
923 if (c == '=') return true;
924 if (c == '+') return true;
925 if (c == '$') return true;
926 if (c == ',') return true;
927 if (c == '%') return true;
928
929 if (c == '_') return true;
930 if (c == '!') return true;
931 if (c == '~') return true;
932 if (c == '*') return true;
933 if (c == '\'') return true;
934 if (c == '(') return true;
935 if (c == ')') return true;
936 return false;
937 }
938
939 /**
940 * This is a utility function for determining whether a specified
941 * character is a character according to production 2 of the
942 * XML 1.0 specification.
943 *
944 * @param c <code>char</code> to check for XML compliance
945 * @return <code>boolean</code> true if it's a character,
946 * false otherwise
947 */
948 public static boolean isXMLCharacter(final int c) {
949
950 if (c == '\n') return true;
951 if (c == '\r') return true;
952 if (c == '\t') return true;
953
954 if (c < 0x20) return false; if (c <= 0xD7FF) return true;
955 if (c < 0xE000) return false; if (c <= 0xFFFD) return true;
956 if (c < 0x10000) return false; if (c <= 0x10FFFF) return true;
957
958 return false;
959 }
960
961
962 /**
963 * This is a utility function for determining whether a specified
964 * character is a name character according to production 4 of the
965 * XML 1.0 specification.
966 *
967 * @param c <code>char</code> to check for XML name compliance.
968 * @return <code>boolean</code> true if it's a name character,
969 * false otherwise.
970 */
971 public static boolean isXMLNameCharacter(final char c) {
972
973 return (isXMLLetter(c) || isXMLDigit(c) || c == '.' || c == '-'
974 || c == '_' || c == ':' || isXMLCombiningChar(c)
975 || isXMLExtender(c));
976 }
977
978 /**
979 * This is a utility function for determining whether a specified
980 * character is a legal name start character according to production 5
981 * of the XML 1.0 specification. This production does allow names
982 * to begin with colons which the Namespaces in XML Recommendation
983 * disallows.
984 *
985 * @param c <code>char</code> to check for XML name start compliance.
986 * @return <code>boolean</code> true if it's a name start character,
987 * false otherwise.
988 */
989 public static boolean isXMLNameStartCharacter(final char c) {
990
991 return (isXMLLetter(c) || c == '_' || c ==':');
992
993 }
994
995 /**
996 * This is a utility function for determining whether a specified
997 * character is a letter or digit according to productions 84 and 88
998 * of the XML 1.0 specification.
999 *
1000 * @param c <code>char</code> to check.
1001 * @return <code>boolean</code> true if it's letter or digit,
1002 * false otherwise.
1003 */
1004 public static boolean isXMLLetterOrDigit(final char c) {
1005
1006 return (isXMLLetter(c) || isXMLDigit(c));
1007
1008 }
1009
1010 /**
1011 * This is a utility function for determining whether a specified character
1012 * is a letter according to production 84 of the XML 1.0 specification.
1013 *
1014 * @param c <code>char</code> to check for XML name compliance.
1015 * @return <code>String</code> true if it's a letter, false otherwise.
1016 */
1017 public static boolean isXMLLetter(final char c) {
1018 // Note that order is very important here. The search proceeds
1019 // from lowest to highest values, so that no searching occurs
1020 // above the character's value. BTW, the first line is equivalent to:
1021 // if (c >= 0x0041 && c <= 0x005A) return true;
1022
1023 if (c < 0x0041) return false; if (c <= 0x005a) return true;
1024 if (c < 0x0061) return false; if (c <= 0x007A) return true;
1025 if (c < 0x00C0) return false; if (c <= 0x00D6) return true;
1026 if (c < 0x00D8) return false; if (c <= 0x00F6) return true;
1027 if (c < 0x00F8) return false; if (c <= 0x00FF) return true;
1028 if (c < 0x0100) return false; if (c <= 0x0131) return true;
1029 if (c < 0x0134) return false; if (c <= 0x013E) return true;
1030 if (c < 0x0141) return false; if (c <= 0x0148) return true;
1031 if (c < 0x014A) return false; if (c <= 0x017E) return true;
1032 if (c < 0x0180) return false; if (c <= 0x01C3) return true;
1033 if (c < 0x01CD) return false; if (c <= 0x01F0) return true;
1034 if (c < 0x01F4) return false; if (c <= 0x01F5) return true;
1035 if (c < 0x01FA) return false; if (c <= 0x0217) return true;
1036 if (c < 0x0250) return false; if (c <= 0x02A8) return true;
1037 if (c < 0x02BB) return false; if (c <= 0x02C1) return true;
1038 if (c == 0x0386) return true;
1039 if (c < 0x0388) return false; if (c <= 0x038A) return true;
1040 if (c == 0x038C) return true;
1041 if (c < 0x038E) return false; if (c <= 0x03A1) return true;
1042 if (c < 0x03A3) return false; if (c <= 0x03CE) return true;
1043 if (c < 0x03D0) return false; if (c <= 0x03D6) return true;
1044 if (c == 0x03DA) return true;
1045 if (c == 0x03DC) return true;
1046 if (c == 0x03DE) return true;
1047 if (c == 0x03E0) return true;
1048 if (c < 0x03E2) return false; if (c <= 0x03F3) return true;
1049 if (c < 0x0401) return false; if (c <= 0x040C) return true;
1050 if (c < 0x040E) return false; if (c <= 0x044F) return true;
1051 if (c < 0x0451) return false; if (c <= 0x045C) return true;
1052 if (c < 0x045E) return false; if (c <= 0x0481) return true;
1053 if (c < 0x0490) return false; if (c <= 0x04C4) return true;
1054 if (c < 0x04C7) return false; if (c <= 0x04C8) return true;
1055 if (c < 0x04CB) return false; if (c <= 0x04CC) return true;
1056 if (c < 0x04D0) return false; if (c <= 0x04EB) return true;
1057 if (c < 0x04EE) return false; if (c <= 0x04F5) return true;
1058 if (c < 0x04F8) return false; if (c <= 0x04F9) return true;
1059 if (c < 0x0531) return false; if (c <= 0x0556) return true;
1060 if (c == 0x0559) return true;
1061 if (c < 0x0561) return false; if (c <= 0x0586) return true;
1062 if (c < 0x05D0) return false; if (c <= 0x05EA) return true;
1063 if (c < 0x05F0) return false; if (c <= 0x05F2) return true;
1064 if (c < 0x0621) return false; if (c <= 0x063A) return true;
1065 if (c < 0x0641) return false; if (c <= 0x064A) return true;
1066 if (c < 0x0671) return false; if (c <= 0x06B7) return true;
1067 if (c < 0x06BA) return false; if (c <= 0x06BE) return true;
1068 if (c < 0x06C0) return false; if (c <= 0x06CE) return true;
1069 if (c < 0x06D0) return false; if (c <= 0x06D3) return true;
1070 if (c == 0x06D5) return true;
1071 if (c < 0x06E5) return false; if (c <= 0x06E6) return true;
1072 if (c < 0x0905) return false; if (c <= 0x0939) return true;
1073 if (c == 0x093D) return true;
1074 if (c < 0x0958) return false; if (c <= 0x0961) return true;
1075 if (c < 0x0985) return false; if (c <= 0x098C) return true;
1076 if (c < 0x098F) return false; if (c <= 0x0990) return true;
1077 if (c < 0x0993) return false; if (c <= 0x09A8) return true;
1078 if (c < 0x09AA) return false; if (c <= 0x09B0) return true;
1079 if (c == 0x09B2) return true;
1080 if (c < 0x09B6) return false; if (c <= 0x09B9) return true;
1081 if (c < 0x09DC) return false; if (c <= 0x09DD) return true;
1082 if (c < 0x09DF) return false; if (c <= 0x09E1) return true;
1083 if (c < 0x09F0) return false; if (c <= 0x09F1) return true;
1084 if (c < 0x0A05) return false; if (c <= 0x0A0A) return true;
1085 if (c < 0x0A0F) return false; if (c <= 0x0A10) return true;
1086 if (c < 0x0A13) return false; if (c <= 0x0A28) return true;
1087 if (c < 0x0A2A) return false; if (c <= 0x0A30) return true;
1088 if (c < 0x0A32) return false; if (c <= 0x0A33) return true;
1089 if (c < 0x0A35) return false; if (c <= 0x0A36) return true;
1090 if (c < 0x0A38) return false; if (c <= 0x0A39) return true;
1091 if (c < 0x0A59) return false; if (c <= 0x0A5C) return true;
1092 if (c == 0x0A5E) return true;
1093 if (c < 0x0A72) return false; if (c <= 0x0A74) return true;
1094 if (c < 0x0A85) return false; if (c <= 0x0A8B) return true;
1095 if (c == 0x0A8D) return true;
1096 if (c < 0x0A8F) return false; if (c <= 0x0A91) return true;
1097 if (c < 0x0A93) return false; if (c <= 0x0AA8) return true;
1098 if (c < 0x0AAA) return false; if (c <= 0x0AB0) return true;
1099 if (c < 0x0AB2) return false; if (c <= 0x0AB3) return true;
1100 if (c < 0x0AB5) return false; if (c <= 0x0AB9) return true;
1101 if (c == 0x0ABD) return true;
1102 if (c == 0x0AE0) return true;
1103 if (c < 0x0B05) return false; if (c <= 0x0B0C) return true;
1104 if (c < 0x0B0F) return false; if (c <= 0x0B10) return true;
1105 if (c < 0x0B13) return false; if (c <= 0x0B28) return true;
1106 if (c < 0x0B2A) return false; if (c <= 0x0B30) return true;
1107 if (c < 0x0B32) return false; if (c <= 0x0B33) return true;
1108 if (c < 0x0B36) return false; if (c <= 0x0B39) return true;
1109 if (c == 0x0B3D) return true;
1110 if (c < 0x0B5C) return false; if (c <= 0x0B5D) return true;
1111 if (c < 0x0B5F) return false; if (c <= 0x0B61) return true;
1112 if (c < 0x0B85) return false; if (c <= 0x0B8A) return true;
1113 if (c < 0x0B8E) return false; if (c <= 0x0B90) return true;
1114 if (c < 0x0B92) return false; if (c <= 0x0B95) return true;
1115 if (c < 0x0B99) return false; if (c <= 0x0B9A) return true;
1116 if (c == 0x0B9C) return true;
1117 if (c < 0x0B9E) return false; if (c <= 0x0B9F) return true;
1118 if (c < 0x0BA3) return false; if (c <= 0x0BA4) return true;
1119 if (c < 0x0BA8) return false; if (c <= 0x0BAA) return true;
1120 if (c < 0x0BAE) return false; if (c <= 0x0BB5) return true;
1121 if (c < 0x0BB7) return false; if (c <= 0x0BB9) return true;
1122 if (c < 0x0C05) return false; if (c <= 0x0C0C) return true;
1123 if (c < 0x0C0E) return false; if (c <= 0x0C10) return true;
1124 if (c < 0x0C12) return false; if (c <= 0x0C28) return true;
1125 if (c < 0x0C2A) return false; if (c <= 0x0C33) return true;
1126 if (c < 0x0C35) return false; if (c <= 0x0C39) return true;
1127 if (c < 0x0C60) return false; if (c <= 0x0C61) return true;
1128 if (c < 0x0C85) return false; if (c <= 0x0C8C) return true;
1129 if (c < 0x0C8E) return false; if (c <= 0x0C90) return true;
1130 if (c < 0x0C92) return false; if (c <= 0x0CA8) return true;
1131 if (c < 0x0CAA) return false; if (c <= 0x0CB3) return true;
1132 if (c < 0x0CB5) return false; if (c <= 0x0CB9) return true;
1133 if (c == 0x0CDE) return true;
1134 if (c < 0x0CE0) return false; if (c <= 0x0CE1) return true;
1135 if (c < 0x0D05) return false; if (c <= 0x0D0C) return true;
1136 if (c < 0x0D0E) return false; if (c <= 0x0D10) return true;
1137 if (c < 0x0D12) return false; if (c <= 0x0D28) return true;
1138 if (c < 0x0D2A) return false; if (c <= 0x0D39) return true;
1139 if (c < 0x0D60) return false; if (c <= 0x0D61) return true;
1140 if (c < 0x0E01) return false; if (c <= 0x0E2E) return true;
1141 if (c == 0x0E30) return true;
1142 if (c < 0x0E32) return false; if (c <= 0x0E33) return true;
1143 if (c < 0x0E40) return false; if (c <= 0x0E45) return true;
1144 if (c < 0x0E81) return false; if (c <= 0x0E82) return true;
1145 if (c == 0x0E84) return true;
1146 if (c < 0x0E87) return false; if (c <= 0x0E88) return true;
1147 if (c == 0x0E8A) return true;
1148 if (c == 0x0E8D) return true;
1149 if (c < 0x0E94) return false; if (c <= 0x0E97) return true;
1150 if (c < 0x0E99) return false; if (c <= 0x0E9F) return true;
1151 if (c < 0x0EA1) return false; if (c <= 0x0EA3) return true;
1152 if (c == 0x0EA5) return true;
1153 if (c == 0x0EA7) return true;
1154 if (c < 0x0EAA) return false; if (c <= 0x0EAB) return true;
1155 if (c < 0x0EAD) return false; if (c <= 0x0EAE) return true;
1156 if (c == 0x0EB0) return true;
1157 if (c < 0x0EB2) return false; if (c <= 0x0EB3) return true;
1158 if (c == 0x0EBD) return true;
1159 if (c < 0x0EC0) return false; if (c <= 0x0EC4) return true;
1160 if (c < 0x0F40) return false; if (c <= 0x0F47) return true;
1161 if (c < 0x0F49) return false; if (c <= 0x0F69) return true;
1162 if (c < 0x10A0) return false; if (c <= 0x10C5) return true;
1163 if (c < 0x10D0) return false; if (c <= 0x10F6) return true;
1164 if (c == 0x1100) return true;
1165 if (c < 0x1102) return false; if (c <= 0x1103) return true;
1166 if (c < 0x1105) return false; if (c <= 0x1107) return true;
1167 if (c == 0x1109) return true;
1168 if (c < 0x110B) return false; if (c <= 0x110C) return true;
1169 if (c < 0x110E) return false; if (c <= 0x1112) return true;
1170 if (c == 0x113C) return true;
1171 if (c == 0x113E) return true;
1172 if (c == 0x1140) return true;
1173 if (c == 0x114C) return true;
1174 if (c == 0x114E) return true;
1175 if (c == 0x1150) return true;
1176 if (c < 0x1154) return false; if (c <= 0x1155) return true;
1177 if (c == 0x1159) return true;
1178 if (c < 0x115F) return false; if (c <= 0x1161) return true;
1179 if (c == 0x1163) return true;
1180 if (c == 0x1165) return true;
1181 if (c == 0x1167) return true;
1182 if (c == 0x1169) return true;
1183 if (c < 0x116D) return false; if (c <= 0x116E) return true;
1184 if (c < 0x1172) return false; if (c <= 0x1173) return true;
1185 if (c == 0x1175) return true;
1186 if (c == 0x119E) return true;
1187 if (c == 0x11A8) return true;
1188 if (c == 0x11AB) return true;
1189 if (c < 0x11AE) return false; if (c <= 0x11AF) return true;
1190 if (c < 0x11B7) return false; if (c <= 0x11B8) return true;
1191 if (c == 0x11BA) return true;
1192 if (c < 0x11BC) return false; if (c <= 0x11C2) return true;
1193 if (c == 0x11EB) return true;
1194 if (c == 0x11F0) return true;
1195 if (c == 0x11F9) return true;
1196 if (c < 0x1E00) return false; if (c <= 0x1E9B) return true;
1197 if (c < 0x1EA0) return false; if (c <= 0x1EF9) return true;
1198 if (c < 0x1F00) return false; if (c <= 0x1F15) return true;
1199 if (c < 0x1F18) return false; if (c <= 0x1F1D) return true;
1200 if (c < 0x1F20) return false; if (c <= 0x1F45) return true;
1201 if (c < 0x1F48) return false; if (c <= 0x1F4D) return true;
1202 if (c < 0x1F50) return false; if (c <= 0x1F57) return true;
1203 if (c == 0x1F59) return true;
1204 if (c == 0x1F5B) return true;
1205 if (c == 0x1F5D) return true;
1206 if (c < 0x1F5F) return false; if (c <= 0x1F7D) return true;
1207 if (c < 0x1F80) return false; if (c <= 0x1FB4) return true;
1208 if (c < 0x1FB6) return false; if (c <= 0x1FBC) return true;
1209 if (c == 0x1FBE) return true;
1210 if (c < 0x1FC2) return false; if (c <= 0x1FC4) return true;
1211 if (c < 0x1FC6) return false; if (c <= 0x1FCC) return true;
1212 if (c < 0x1FD0) return false; if (c <= 0x1FD3) return true;
1213 if (c < 0x1FD6) return false; if (c <= 0x1FDB) return true;
1214 if (c < 0x1FE0) return false; if (c <= 0x1FEC) return true;
1215 if (c < 0x1FF2) return false; if (c <= 0x1FF4) return true;
1216 if (c < 0x1FF6) return false; if (c <= 0x1FFC) return true;
1217 if (c == 0x2126) return true;
1218 if (c < 0x212A) return false; if (c <= 0x212B) return true;
1219 if (c == 0x212E) return true;
1220 if (c < 0x2180) return false; if (c <= 0x2182) return true;
1221 if (c == 0x3007) return true; // ideographic
1222 if (c < 0x3021) return false; if (c <= 0x3029) return true; // ideo
1223 if (c < 0x3041) return false; if (c <= 0x3094) return true;
1224 if (c < 0x30A1) return false; if (c <= 0x30FA) return true;
1225 if (c < 0x3105) return false; if (c <= 0x312C) return true;
1226 if (c < 0x4E00) return false; if (c <= 0x9FA5) return true; // ideo
1227 if (c < 0xAC00) return false; if (c <= 0xD7A3) return true;
1228
1229 return false;
1230
1231 }
1232
1233 /**
1234 * This is a utility function for determining whether a specified character
1235 * is a combining character according to production 87
1236 * of the XML 1.0 specification.
1237 *
1238 * @param c <code>char</code> to check.
1239 * @return <code>boolean</code> true if it's a combining character,
1240 * false otherwise.
1241 */
1242 public static boolean isXMLCombiningChar(final char c) {
1243 // CombiningChar
1244 if (c < 0x0300) return false; if (c <= 0x0345) return true;
1245 if (c < 0x0360) return false; if (c <= 0x0361) return true;
1246 if (c < 0x0483) return false; if (c <= 0x0486) return true;
1247 if (c < 0x0591) return false; if (c <= 0x05A1) return true;
1248
1249 if (c < 0x05A3) return false; if (c <= 0x05B9) return true;
1250 if (c < 0x05BB) return false; if (c <= 0x05BD) return true;
1251 if (c == 0x05BF) return true;
1252 if (c < 0x05C1) return false; if (c <= 0x05C2) return true;
1253
1254 if (c == 0x05C4) return true;
1255 if (c < 0x064B) return false; if (c <= 0x0652) return true;
1256 if (c == 0x0670) return true;
1257 if (c < 0x06D6) return false; if (c <= 0x06DC) return true;
1258
1259 if (c < 0x06DD) return false; if (c <= 0x06DF) return true;
1260 if (c < 0x06E0) return false; if (c <= 0x06E4) return true;
1261 if (c < 0x06E7) return false; if (c <= 0x06E8) return true;
1262
1263 if (c < 0x06EA) return false; if (c <= 0x06ED) return true;
1264 if (c < 0x0901) return false; if (c <= 0x0903) return true;
1265 if (c == 0x093C) return true;
1266 if (c < 0x093E) return false; if (c <= 0x094C) return true;
1267
1268 if (c == 0x094D) return true;
1269 if (c < 0x0951) return false; if (c <= 0x0954) return true;
1270 if (c < 0x0962) return false; if (c <= 0x0963) return true;
1271 if (c < 0x0981) return false; if (c <= 0x0983) return true;
1272
1273 if (c == 0x09BC) return true;
1274 if (c == 0x09BE) return true;
1275 if (c == 0x09BF) return true;
1276 if (c < 0x09C0) return false; if (c <= 0x09C4) return true;
1277 if (c < 0x09C7) return false; if (c <= 0x09C8) return true;
1278
1279 if (c < 0x09CB) return false; if (c <= 0x09CD) return true;
1280 if (c == 0x09D7) return true;
1281 if (c < 0x09E2) return false; if (c <= 0x09E3) return true;
1282 if (c == 0x0A02) return true;
1283 if (c == 0x0A3C) return true;
1284
1285 if (c == 0x0A3E) return true;
1286 if (c == 0x0A3F) return true;
1287 if (c < 0x0A40) return false; if (c <= 0x0A42) return true;
1288 if (c < 0x0A47) return false; if (c <= 0x0A48) return true;
1289
1290 if (c < 0x0A4B) return false; if (c <= 0x0A4D) return true;
1291 if (c < 0x0A70) return false; if (c <= 0x0A71) return true;
1292 if (c < 0x0A81) return false; if (c <= 0x0A83) return true;
1293 if (c == 0x0ABC) return true;
1294
1295 if (c < 0x0ABE) return false; if (c <= 0x0AC5) return true;
1296 if (c < 0x0AC7) return false; if (c <= 0x0AC9) return true;
1297 if (c < 0x0ACB) return false; if (c <= 0x0ACD) return true;
1298
1299 if (c < 0x0B01) return false; if (c <= 0x0B03) return true;
1300 if (c == 0x0B3C) return true;
1301 if (c < 0x0B3E) return false; if (c <= 0x0B43) return true;
1302 if (c < 0x0B47) return false; if (c <= 0x0B48) return true;
1303
1304 if (c < 0x0B4B) return false; if (c <= 0x0B4D) return true;
1305 if (c < 0x0B56) return false; if (c <= 0x0B57) return true;
1306 if (c < 0x0B82) return false; if (c <= 0x0B83) return true;
1307
1308 if (c < 0x0BBE) return false; if (c <= 0x0BC2) return true;
1309 if (c < 0x0BC6) return false; if (c <= 0x0BC8) return true;
1310 if (c < 0x0BCA) return false; if (c <= 0x0BCD) return true;
1311 if (c == 0x0BD7) return true;
1312
1313 if (c < 0x0C01) return false; if (c <= 0x0C03) return true;
1314 if (c < 0x0C3E) return false; if (c <= 0x0C44) return true;
1315 if (c < 0x0C46) return false; if (c <= 0x0C48) return true;
1316
1317 if (c < 0x0C4A) return false; if (c <= 0x0C4D) return true;
1318 if (c < 0x0C55) return false; if (c <= 0x0C56) return true;
1319 if (c < 0x0C82) return false; if (c <= 0x0C83) return true;
1320
1321 if (c < 0x0CBE) return false; if (c <= 0x0CC4) return true;
1322 if (c < 0x0CC6) return false; if (c <= 0x0CC8) return true;
1323 if (c < 0x0CCA) return false; if (c <= 0x0CCD) return true;
1324
1325 if (c < 0x0CD5) return false; if (c <= 0x0CD6) return true;
1326 if (c < 0x0D02) return false; if (c <= 0x0D03) return true;
1327 if (c < 0x0D3E) return false; if (c <= 0x0D43) return true;
1328
1329 if (c < 0x0D46) return false; if (c <= 0x0D48) return true;
1330 if (c < 0x0D4A) return false; if (c <= 0x0D4D) return true;
1331 if (c == 0x0D57) return true;
1332 if (c == 0x0E31) return true;
1333
1334 if (c < 0x0E34) return false; if (c <= 0x0E3A) return true;
1335 if (c < 0x0E47) return false; if (c <= 0x0E4E) return true;
1336 if (c == 0x0EB1) return true;
1337 if (c < 0x0EB4) return false; if (c <= 0x0EB9) return true;
1338
1339 if (c < 0x0EBB) return false; if (c <= 0x0EBC) return true;
1340 if (c < 0x0EC8) return false; if (c <= 0x0ECD) return true;
1341 if (c < 0x0F18) return false; if (c <= 0x0F19) return true;
1342 if (c == 0x0F35) return true;
1343
1344 if (c == 0x0F37) return true;
1345 if (c == 0x0F39) return true;
1346 if (c == 0x0F3E) return true;
1347 if (c == 0x0F3F) return true;
1348 if (c < 0x0F71) return false; if (c <= 0x0F84) return true;
1349
1350 if (c < 0x0F86) return false; if (c <= 0x0F8B) return true;
1351 if (c < 0x0F90) return false; if (c <= 0x0F95) return true;
1352 if (c == 0x0F97) return true;
1353 if (c < 0x0F99) return false; if (c <= 0x0FAD) return true;
1354
1355 if (c < 0x0FB1) return false; if (c <= 0x0FB7) return true;
1356 if (c == 0x0FB9) return true;
1357 if (c < 0x20D0) return false; if (c <= 0x20DC) return true;
1358 if (c == 0x20E1) return true;
1359
1360 if (c < 0x302A) return false; if (c <= 0x302F) return true;
1361 if (c == 0x3099) return true;
1362 if (c == 0x309A) return true;
1363
1364 return false;
1365
1366 }
1367
1368 /**
1369 * This is a utility function for determining whether a specified
1370 * character is an extender according to production 88 of the XML 1.0
1371 * specification.
1372 *
1373 * @param c <code>char</code> to check.
1374 * @return <code>String</code> true if it's an extender, false otherwise.
1375 */
1376 public static boolean isXMLExtender(final char c) {
1377
1378 if (c < 0x00B6) return false; // quick short circuit
1379
1380 // Extenders
1381 if (c == 0x00B7) return true;
1382 if (c == 0x02D0) return true;
1383 if (c == 0x02D1) return true;
1384 if (c == 0x0387) return true;
1385 if (c == 0x0640) return true;
1386 if (c == 0x0E46) return true;
1387 if (c == 0x0EC6) return true;
1388 if (c == 0x3005) return true;
1389
1390 if (c < 0x3031) return false; if (c <= 0x3035) return true;
1391 if (c < 0x309D) return false; if (c <= 0x309E) return true;
1392 if (c < 0x30FC) return false; if (c <= 0x30FE) return true;
1393
1394 return false;
1395
1396 }
1397
1398 /**
1399 * This is a utility function for determining whether a specified
1400 * Unicode character
1401 * is a digit according to production 88 of the XML 1.0 specification.
1402 *
1403 * @param c <code>char</code> to check for XML digit compliance
1404 * @return <code>boolean</code> true if it's a digit, false otherwise
1405 */
1406 public static boolean isXMLDigit(final char c) {
1407
1408 if (c < 0x0030) return false; if (c <= 0x0039) return true;
1409 if (c < 0x0660) return false; if (c <= 0x0669) return true;
1410 if (c < 0x06F0) return false; if (c <= 0x06F9) return true;
1411 if (c < 0x0966) return false; if (c <= 0x096F) return true;
1412
1413 if (c < 0x09E6) return false; if (c <= 0x09EF) return true;
1414 if (c < 0x0A66) return false; if (c <= 0x0A6F) return true;
1415 if (c < 0x0AE6) return false; if (c <= 0x0AEF) return true;
1416
1417 if (c < 0x0B66) return false; if (c <= 0x0B6F) return true;
1418 if (c < 0x0BE7) return false; if (c <= 0x0BEF) return true;
1419 if (c < 0x0C66) return false; if (c <= 0x0C6F) return true;
1420
1421 if (c < 0x0CE6) return false; if (c <= 0x0CEF) return true;
1422 if (c < 0x0D66) return false; if (c <= 0x0D6F) return true;
1423 if (c < 0x0E50) return false; if (c <= 0x0E59) return true;
1424
1425 if (c < 0x0ED0) return false; if (c <= 0x0ED9) return true;
1426 if (c < 0x0F20) return false; if (c <= 0x0F29) return true;
1427
1428 return false;
1429 }
1430
1431 /**
1432 * This is a utility function for determining whether a specified
1433 * Unicode character is a whitespace character according to production 3
1434 * of the XML 1.0 specification.
1435 *
1436 * @param c <code>char</code> to check for XML whitespace compliance
1437 * @return <code>boolean</code> true if it's a whitespace, false otherwise
1438 */
1439 public static boolean isXMLWhitespace(final char c) {
1440 // the following if is faster than switch statements.
1441 // seems the implicit conversion to int is slower than
1442 // the fall-through or's
1443 if (c==' ' || c=='\n' || c=='\t' || c=='\r' ){
1444 return true;
1445 }
1446 return false;
1447 }
1448
1449 /**
1450 * This is a utility function for determining whether a specified
1451 * String is a whitespace character according to production 3
1452 * of the XML 1.0 specification.
1453 * <p>
1454 * This method delegates the individual calls for each character to
1455 * {@link #isXMLWhitespace(char)}.
1456 *
1457 * @param value
1458 * The value to inspect
1459 * @return true if all characters in the input value are all whitespace
1460 * (or the string is the empty-string).
1461 * @since JDOM2
1462 */
1463 public static final boolean isAllXMLWhitespace(final String value) {
1464 // Doing the count-down instead of a count-up saves a single int
1465 // variable declaration.
1466 int i = value.length();
1467 while (--i >= 0) {
1468 if (!isXMLWhitespace(value.charAt(i))) {
1469 return false;
1470 }
1471 }
1472 return true;
1473 }
1474
1475
1476 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.perf;
55
56 interface TimeRunnable {
57 void run() throws Exception;
58 }
0 /*--
1
2 Copyright (C) 2003-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.schema;
55
56 import java.io.File;
57 import java.io.InputStream;
58 import java.io.FileInputStream;
59 import java.io.Reader;
60 import java.io.IOException;
61 import java.util.List;
62 import java.util.ArrayList;
63 import java.util.LinkedList;
64
65 import org.xml.sax.InputSource;
66 import org.xml.sax.Locator;
67 import org.xml.sax.XMLReader;
68 import org.xml.sax.SAXException;
69 import org.xml.sax.SAXParseException;
70 import org.xml.sax.helpers.XMLFilterImpl;
71
72 import org.iso_relax.verifier.Verifier;
73 import org.iso_relax.verifier.VerifierFactory;
74 import org.iso_relax.verifier.VerifierConfigurationException;
75
76 import org.jdom.Document;
77 import org.jdom.Element;
78 import org.jdom.JDOMException;
79 import org.jdom.output.SAXOutputter;
80 import org.jdom.output.JDOMLocator;
81
82 /**
83 * The compiled representation of a schema definition capable of
84 * performing in-memory validation of JDOM documents and elements.
85 * <p>
86 * This class relies on
87 * <a href="http://iso-relax.sourceforge.net/JARV/">JARV</a> (Java
88 * API for RELAX Verifiers) and requires an implementation of this
89 * API at runtime, such as Sun's
90 * <a href="http://wwws.sun.com/software/xml/developers/multischema/">Multi-Schema
91 * Validator</a>.</p>
92 * <p>
93 * To validate a document against a W3C XML Schema definition:</p>
94 * <pre>
95 * import org.jdom.contrib.schema.Schema;
96 *
97 * String uri = &lt;The URL of the schema document&gt;;
98 * Document doc = &lt;a JDOM document&gt;;
99 *
100 * Schema schema = Schema.parse(uri, Schema.W3C_XML_SCHEMA);
101 * List errors = schema.validate(doc);
102 * if (errors != null) {
103 * // Validation errors
104 * for (Iterator i=errors.iterator(); i.hasNext(); ) {
105 * ValidationError e = (ValidationError)(i.next());
106 * System.out.println(e);
107 * }
108 * }
109 * // Else: No error, document is valid.
110 * </pre>
111 * <p>
112 * The current limitations are those of JARV, i&#46;e&#46; no support for
113 * validating a document against multiple schemas. This can be work around
114 * for elements (calling validate(Element) on another Schema) but not for
115 * attributes.</p>
116 *
117 * @author Laurent Bihanic
118 */
119 public class Schema {
120
121 /**
122 * Type for W3C XML Schema definitions.
123 */
124 public final static Type W3C_XML_SCHEMA =
125 new Type("W3C XML Schema", "http://www.w3.org/2001/XMLSchema");
126 /**
127 * Type for RELAX NG schema definitions.
128 */
129 public final static Type RELAX_NG =
130 new Type("RELAX NG", "http://relaxng.org/ns/structure/0.9");
131 /**
132 * Type for RELAX Core schema definitions.
133 */
134 public final static Type RELAX_CORE =
135 new Type("RELAX Core", "http://www.xml.gr.jp/xmlns/relaxCore");
136 /**
137 * Type for RELAX Namespace schema definitions.
138 */
139 public final static Type RELAX_NAMESPACE =
140 new Type("RELAX Namespace",
141 "http://www.xml.gr.jp/xmlns/relaxNamespace");
142 /**
143 * Type for TREX schema definitions.
144 */
145 public final static Type TREX =
146 new Type("TREX", "http://www.thaiopensource.com/trex");
147
148 /**
149 * The URI of the schema document, if known.
150 */
151 private final String uri;
152
153 /**
154 * The schema type.
155 */
156 private final Type type;
157
158 /**
159 * The JARV compiled schema.
160 */
161 private final org.iso_relax.verifier.Schema compiledSchema;
162
163 /**
164 * Compiles a schema definition.
165 *
166 * @param source the SAX input source to read the schema
167 * definition from.
168 * @param type the schema type.
169 *
170 * @throws JDOMException if the schema document can not be
171 * parsed according to the specfied type.
172 * @throws IOException if an I/O error occurred while reading
173 * the schema document.
174 */
175 private Schema(InputSource source, Type type)
176 throws JDOMException, IOException {
177
178 if ((source == null) || (type == null)) {
179 throw new IllegalArgumentException("source/type/compiledSchema");
180 }
181 this.uri = source.getSystemId();
182 this.type = type;
183
184 try {
185 VerifierFactory vf = VerifierFactory.newInstance(type.getLanguage());
186
187 this.compiledSchema = vf.compileSchema(source);
188 }
189 catch (IOException e) {
190 throw e;
191 }
192 catch (Exception e) {
193 throw new JDOMException("Failed to parse schema \"" + this.uri +
194 "\": " + e.getMessage(), e);
195 }
196 }
197
198 /**
199 * Returns the location of the schema document, if known.
200 *
201 * @return the location of the schema document or
202 * <code>null</code> if inknown.
203 */
204 public String getURI() {
205 return this.uri;
206 }
207
208 /**
209 * Returns the schema type.
210 *
211 * @return the schema type.
212 */
213 public Type getType() {
214 return this.type;
215 }
216
217 /**
218 * Allocates an JARV <code>Verifier</code> object for
219 * validating against this schema.
220 *
221 * @return an JARV <code>Verifier</code> configured with this
222 * schema.
223 *
224 * @throws JDOMException if the verifier allocation failed.
225 */
226 private Verifier newVerifier() throws JDOMException {
227 try {
228 return this.compiledSchema.newVerifier();
229 }
230 catch (VerifierConfigurationException e) {
231 throw new JDOMException(
232 "Failed to allocate schema verifier: " + e.getMessage(), e);
233 }
234 }
235
236 /**
237 * Validates a JDOM document against this schema.
238 *
239 * @param doc the JDOM document to validate.
240 *
241 * @return a list of {@link ValidationError} objects or
242 * <code>null</code> if the document is compliant with
243 * this schema.
244 *
245 * @throws JDOMException if errors were encountered that
246 * prevented the validation to proceed.
247 */
248 public List<ValidationError> validate(Document doc) throws JDOMException {
249 ValidationErrorHandler errorHandler = new ValidationErrorHandler();
250 try {
251 Verifier verifier = this.newVerifier();
252 verifier.setErrorHandler(errorHandler);
253
254 errorHandler.setContentHandler(verifier.getVerifierHandler());
255 new SAXOutputter(errorHandler).output(doc);
256 }
257 catch (SAXException e) { /* Fatal validation error encountered. */
258 }
259
260 // Retrieve validation errors, if any.
261 return errorHandler.getErrors();
262 }
263
264 /**
265 * Validates a JDOM element against this schema.
266 *
267 * @param element the JDOM element to validate.
268 *
269 * @return a list of {@link ValidationError} objects or
270 * <code>null</code> if the element is compliant with
271 * this schema.
272 *
273 * @throws JDOMException if errors were encountered that
274 * prevented the validation to proceed.
275 */
276 public List<ValidationError> validate(Element element) throws JDOMException {
277 ValidationErrorHandler errorHandler = new ValidationErrorHandler();
278 try {
279 Verifier verifier = this.newVerifier();
280 verifier.setErrorHandler(errorHandler);
281
282 List<Element> nodes = new ArrayList<Element>();
283 nodes.add(element);
284
285 errorHandler.setContentHandler(verifier.getVerifierHandler());
286 new SAXOutputter(errorHandler).output(nodes);
287 }
288 catch (SAXException e) { /* Fatal validation error encountered. */
289 }
290
291 // Retrieve validation errors, if any.
292 return errorHandler.getErrors();
293 }
294
295 /**
296 * Parses a schema definition located at the specified URI
297 * according to the specified schema type and returns a compiled
298 * schema object.
299 *
300 * @param uri the location of the schema document.
301 * @param type the schema type.
302 *
303 * @return the compiled schema.
304 *
305 * @throws JDOMException if the schema document can not be
306 * parsed according to the specfied type.
307 * @throws IOException if an I/O error occurred while reading
308 * the schema document.
309 */
310 public static Schema parse(String uri, Type type)
311 throws JDOMException, IOException {
312 return parse(new InputSource(uri), type);
313 }
314
315 /**
316 * Parses a schema definition from the specified byte stream
317 * according to the specified schema type and returns a compiled
318 * schema object.
319 *
320 * @param byteStream the byte stream to read the schema
321 * definition from.
322 * @param type the schema type.
323 * @param uri the location of the schema document
324 * (optional).
325 *
326 * @return the compiled schema.
327 *
328 * @throws JDOMException if the schema document can not be
329 * parsed according to the specfied type.
330 * @throws IOException if an I/O error occurred while reading
331 * the schema document.
332 */
333 public static Schema parse(InputStream byteStream, Type type, String uri)
334 throws JDOMException, IOException {
335 InputSource source = new InputSource(byteStream);
336 source.setSystemId(uri);
337
338 return parse(source, type);
339 }
340
341 /**
342 * Parses a schema definition from the specified character stream
343 * according to the specified schema type and returns a compiled
344 * schema object.
345 *
346 * @param reader the character stream to read the schema
347 * definition from.
348 * @param type the schema type.
349 * @param uri the location of the schema document
350 * (optional).
351 *
352 * @return the compiled schema.
353 *
354 * @throws JDOMException if the schema document can not be
355 * parsed according to the specfied type.
356 * @throws IOException if an I/O error occurred while reading
357 * the schema document.
358 */
359 public static Schema parse(Reader reader, Type type, String uri)
360 throws JDOMException, IOException {
361 InputSource source = new InputSource(reader);
362 source.setSystemId(uri);
363
364 return parse(source, type);
365 }
366
367 /**
368 * Parses a schema definition from the specified file
369 * according to the specified schema type and returns a compiled
370 * schema object.
371 *
372 * @param file the file to read the schema definition from.
373 * @param type the schema type.
374 *
375 * @return the compiled schema.
376 *
377 * @throws JDOMException if the schema document can not be
378 * parsed according to the specfied type.
379 * @throws IOException if an I/O error occurred while reading
380 * the schema document.
381 */
382 public static Schema parse(File file, Type type)
383 throws JDOMException, IOException {
384 InputSource source = new InputSource(new FileInputStream(file));
385 source.setSystemId(file.getAbsolutePath());
386
387 return parse(source, type);
388 }
389
390 /**
391 * Parses a schema definition from the specified SAX input source
392 * according to the specified schema type and returns a compiled
393 * schema object.
394 *
395 * @param source the SAX inout source to read the schema
396 * definition from.
397 * @param type the schema type.
398 *
399 * @return the compiled schema.
400 *
401 * @throws JDOMException if the schema document can not be
402 * parsed according to the specfied type.
403 * @throws IOException if an I/O error occurred while reading
404 * the schema document.
405 */
406 public static Schema parse(InputSource source, Type type)
407 throws JDOMException, IOException {
408 return new Schema(source, type);
409 }
410
411
412 /**
413 * A SAX XML filter implementation to capture the document locator
414 * and make all validation errors and warnings available once the
415 * validation is complete.
416 */
417 private static final class ValidationErrorHandler extends XMLFilterImpl {
418 /** The list of validation errors. */
419 private List<ValidationError> errors = new LinkedList<ValidationError>();
420 /** The JDOM locator object provided by SAXOutputter. */
421 private JDOMLocator locator = null;
422
423 /**
424 * Constructs a new ValidationErrorHandler XML filter with no
425 * parent.
426 */
427 public ValidationErrorHandler() {
428 super();
429 }
430
431 /**
432 * Constructs a new ValidationErrorHandler XML filter with the
433 * specified parent.
434 *
435 * @param parent the parent XMLReader or XMLFilter.
436 */
437 @SuppressWarnings("unused")
438 public ValidationErrorHandler(XMLReader parent) {
439 super(parent);
440 }
441
442 /**
443 * Returns the list of validation errors reported during
444 * document validation.
445 *
446 * @return the list of validation errors or <code>null</code>
447 * if the document is valid.
448 */
449 public List<ValidationError> getErrors() {
450 return (this.errors.size() == 0) ? null : this.errors;
451 }
452
453 /**
454 * Returns the JDOM node currently being ouputted by
455 * SAXOuputter.
456 *
457 * @return the current JDOM node.
458 */
459 private Object getCurrentNode() {
460 return (this.locator != null) ? this.locator.getNode() : null;
461 }
462
463 /**
464 * <i>[ContentHandler interface support]</i> Sets the locator
465 * object for locating the origin of SAX document events.
466 *
467 * @param locator an object that can return the location of
468 * any SAX document event.
469 */
470 @Override
471 public void setDocumentLocator(Locator locator) {
472 if (locator instanceof JDOMLocator) {
473 this.locator = (JDOMLocator) locator;
474 }
475 }
476
477 /**
478 * <i>[ErrorHandler interface support]</i> Receives
479 * notification of a non-recoverable error.
480 *
481 * @param e the error information encapsulated in a SAX
482 * parse exception.
483 *
484 * @throws SAXException any SAX exception, possibly wrapping
485 * another exception.
486 */
487 @Override
488 public void fatalError(SAXParseException e) throws SAXException {
489 this.errors.add(new ValidationError(ValidationError.FATAL,
490 e.getMessage(), this.getCurrentNode()));
491 throw e;
492 }
493
494 /**
495 * <i>[ErrorHandler interface support]</i> Receives
496 * notification of a recoverable error.
497 *
498 * @param e the error information encapsulated in a SAX
499 * parse exception.
500 *
501 * @throws SAXException any SAX exception, possibly wrapping
502 * another exception.
503 */
504 @Override
505 public void error(SAXParseException e) throws SAXException {
506 this.errors.add(new ValidationError(ValidationError.ERROR,
507 e.getMessage(), this.getCurrentNode()));
508 }
509
510 /**
511 * <i>[ErrorHandler interface support]</i> Receives
512 * notification of a warning.
513 *
514 * @param e the warning information encapsulated in a SAX
515 * parse exception.
516 *
517 * @throws SAXException any SAX exception, possibly wrapping
518 * another exception.
519 */
520 @Override
521 public void warning(SAXParseException e) throws SAXException {
522 this.errors.add(new ValidationError(ValidationError.WARNING,
523 e.getMessage(), this.getCurrentNode()));
524 }
525 }
526
527
528 /**
529 * Class to support type-safe enumeration design pattern to
530 * represent schema types
531 */
532 public static final class Type {
533 /** Schema type name. */
534 private final String name;
535 /** JARV schema type identifier. */
536 private final String language;
537
538 /**
539 * Type constructor, private on purpose.
540 *
541 * @param name the schema type printable name.
542 * @param language the unique identifier for the schema
543 * type (URI).
544 */
545 protected Type(String name, String language) {
546 this.name = name;
547 this.language = language;
548 }
549
550 /**
551 * Returns the printable name of this schema type.
552 *
553 * @return the schema type name.
554 */
555 public String getName() {
556 return this.name;
557 }
558
559 /**
560 * Returns the URI that uniquemy identifies this schema type.
561 *
562 * @return the schema type identifier.
563 */
564 public String getLanguage() {
565 return this.language;
566 }
567
568 /**
569 * Returns a unique identifier for this type.
570 *
571 * @return a unique identifier for this type.
572 *
573 * @see java.lang.Object#hashCode()
574 */
575 @Override
576 public int hashCode() {
577 return this.language.hashCode();
578 }
579
580 /**
581 * Returns a string representation of this type suitable for
582 * debugging and diagnosis.
583 *
584 * @return a string representation of this type.
585 *
586 * @see java.lang.Object#toString()
587 */
588 @Override
589 public String toString() {
590 return this.language;
591 }
592
593 /**
594 * Tests for type equality. This is only necessary to handle
595 * cases where two <code>Type</code> objects are loaded by
596 * different class loaders.
597 *
598 * @param o the object compared for equality to this type.
599 *
600 * @return <code>true</code> if and only if <code>o</code>
601 * represents the same type as this object.
602 *
603 * @see java.lang.Object#equals(Object)
604 */
605 @Override
606 public boolean equals(Object o) {
607 return ((o == this) ||
608 ((o != null) && (this.hashCode() == o.hashCode()) &&
609 (this.getClass().getName().equals(o.getClass().getName()))));
610 }
611 }
612 }
613
0 /*--
1
2 Copyright (C) 2003-2004 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.schema;
55
56 /**
57 * A ValidationError object encapsulates a schema validation error or
58 * warning.
59 *
60 * @author Laurent Bihanic
61 */
62 public class ValidationError {
63 /** The severity for warnings. */
64 public final static Severity WARNING = new Severity(0);
65 /** The severity for recoverable validation errors. */
66 public final static Severity ERROR = new Severity(1);
67 /** The severity for non-recoverable validation errors. */
68 public final static Severity FATAL = new Severity(2);
69
70 /**
71 * The error severity.
72 */
73 private final Severity severity;
74
75 /**
76 * The detailed error message.
77 */
78 private final String message;
79
80 /**
81 * The JDOM node that caused the error.
82 */
83 private final Object node;
84
85 /**
86 * Creates a new validation error.
87 *
88 * @param severity the error severity.
89 * @param message the detailed error message.
90 */
91 public ValidationError(Severity severity, String message) {
92 this(severity, message, null);
93 }
94
95 /**
96 * Creates a new validation error.
97 *
98 * @param severity the error severity.
99 * @param message the detailed error message.
100 * @param node the JDOM node that caused the error.
101 */
102 public ValidationError(Severity severity, String message, Object node) {
103 this.severity = severity;
104 this.message = message;
105 this.node = node;
106 }
107
108 /**
109 * Returns the severity of this error.
110 *
111 * @return the severity of this error.
112 */
113 public Severity getSeverity() {
114 return this.severity;
115 }
116
117 /**
118 * Returns the detailed error message.
119 *
120 * @return the detailed error message.
121 */
122 public String getMessage() {
123 return this.message;
124 }
125
126 /**
127 * Returns the JDOM node that caused the error.
128 *
129 * @return the JDOM node that caused the error.
130 */
131 public Object getNode() {
132 return this.node;
133 }
134
135 /**
136 * Returns a string representation of this error suitable for
137 * debugging and diagnosis.
138 *
139 * @return a string representation of this error.
140 *
141 * @see java.lang.Object#toString()
142 */
143 @Override
144 public String toString() {
145 StringBuilder buf = new StringBuilder();
146
147 buf.append('[');
148 if (this.severity == WARNING) {
149 buf.append("WARNING");
150 }
151 else if (this.severity == ERROR) {
152 buf.append("ERROR");
153 }
154 else if (this.severity == FATAL) {
155 buf.append("FATAL");
156 }
157 buf.append("] message: \"").append(this.getMessage());
158
159 if (this.getNode() != null) {
160 buf.append("\", location: \"").append(this.getNode().toString());
161 }
162 buf.append("\"");
163
164 return buf.toString();
165 }
166
167
168 /**
169 * Class to support type-safe enumeration design pattern to
170 * represent severity levels of validation errors.
171 */
172 public static final class Severity {
173 /** The severity of the error. */
174 private final int level;
175
176 /**
177 * Severity constructor, private on purpose.
178 *
179 * @param level the severity level.
180 */
181 protected Severity(int level) {
182 this.level = level;
183 }
184
185 /**
186 * Returns a unique identifier for this severity.
187 *
188 * @return a unique identifier for this severity.
189 *
190 * @see java.lang.Object#hashCode()
191 */
192 @Override
193 public int hashCode() {
194 return this.level;
195 }
196
197 /**
198 * Returns a string representation of this severity suitable
199 * for debugging and diagnosis.
200 *
201 * @return a string representation of this severity.
202 *
203 * @see java.lang.Object#toString()
204 */
205 @Override
206 public String toString() {
207 return "[" + this.getClass().getName() + "] " + this.level;
208 }
209
210 /**
211 * Tests for severity equality. This is only necessary to
212 * handle cases where two <code>Type</code> objects are loaded
213 * by different class loaders.
214 *
215 * @param o the object compared for equality to this
216 * severity.
217 *
218 * @return <code>true</code> if and only if <code>o</code>
219 * represents the same severity as this object.
220 *
221 * @see java.lang.Object#equals(Object)
222 */
223 @Override
224 public boolean equals(Object o) {
225 return ((o == this) ||
226 ((o != null) && (this.hashCode() == o.hashCode()) &&
227 (this.getClass().getName().equals(o.getClass().getName()))));
228 }
229 }
230 }
231
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.verifier;
55
56 import org.jdom.Verifier;
57
58 /**
59 * A utility class to build the data component of the main
60 * org.jdom.Verifier class. This class contains all the character
61 * identification/classification routines.
62 * <p>
63 * This class is based on the content of the main Verifier.java class
64 * prior to this optimization.
65 *
66 * @author Brett McLaughlin
67 * @author Elliotte Rusty Harold
68 * @author Jason Hunter
69 * @author Bradley S. Huffman
70 * @author Rolf Lear
71 */
72 final public class VerifierBuilder {
73
74 /**
75 * Ensure instantation cannot occur.
76 */
77 private VerifierBuilder() { }
78
79
80 private static final int charcnt = Character.MAX_VALUE + 1;
81 private static final byte maskxmlcharacter = 1 << 0;
82 private static final byte maskxmlletter = 1 << 1;
83 private static final byte maskxmlstart = 1 << 2;
84 private static final byte maskxmlnamecharacter = 1 << 3;
85 private static final byte maskxmldigit = 1 << 4;
86 private static final byte maskxmlcombining = 1 << 5;
87 private static final byte maskuricharacter = 1 << 6;
88
89 @SuppressWarnings("javadoc")
90 public static void main(String[] args) {
91 // populate the flags array.
92 final byte[] flags = new byte[charcnt];
93
94 for (int i = 0; i < charcnt; i++) {
95 if (isXMLCharacter(i)) {
96 flags[i] |= maskxmlcharacter;
97 }
98
99 final char c = (char)i;
100
101 if (isXMLLetter(c)) {
102 flags[i] |= maskxmlletter;
103 }
104 if (isXMLNameCharacter(c)) {
105 flags[i] |= maskxmlnamecharacter;
106 }
107 if (isXMLNameStartCharacter(c)) {
108 flags[i] |= maskxmlstart;
109 }
110 if (isXMLDigit(c)) {
111 flags[i] |= maskxmldigit;
112 }
113 if (isXMLCombiningChar(c)) {
114 flags[i] |= maskxmlcombining;
115 }
116 if (isURICharacter(c)) {
117 flags[i] |= maskuricharacter;
118 }
119
120 if (flags[i] != 0) {
121 if ((flags[i] & maskxmlcharacter) == 0) {
122 // for performance reasons, the testing of CharacterData
123 // in the final Verifier code does not use the bit-mask for it,
124 // but rather just checks for a non-zero flag. It does not need to
125 // check the actual bit because there are no characters flagged for
126 // any other role (name chars, uri's, etc.) that are not also a pure
127 // subset of the Character Data set.
128 throw new IllegalStateException("Flagged non-xmlchar '" + (char)i + "'.");
129 }
130 }
131 }
132
133 // OK, now 'condense' the flags array to something usable.
134 byte[] vals = new byte[flags.length];
135 int[] lens = new int[flags.length];
136 int index = 0;
137 byte val = flags[0];
138 int cnt = 0;
139
140 for (int i = 0; i < flags.length; i++) {
141 if (flags[i] == val) {
142 cnt++;
143 } else {
144 vals[index] = val;
145 lens[index] = cnt;
146 val = flags[i];
147 cnt = 1;
148 index++;
149 }
150 }
151 vals[index] = val;
152 lens[index] = cnt;
153 index++;
154
155 int ci = 0;
156 for (int i = 0; i < index; i++) {
157 int l = lens[i];
158 final byte v = vals[i];
159 while (--l >= 0) {
160 if (flags[ci] != v) {
161 throw new IllegalStateException(String.format(
162 "Failed to calculate byte 0x%02x at index %d. Calculated 0x%02x instead.",
163 flags[ci], ci, v));
164 }
165 ci++;
166 }
167 }
168
169 System.out.println("There are " + index + " transitions.");
170
171 StringBuilder sbval = new StringBuilder();
172 StringBuilder sblen = new StringBuilder();
173
174 sbval.append("private static final byte[] VALCONST = new byte[] {");
175 sblen.append("private static final int [] LENCONST = new int [] {");
176
177 for (int i = 0; i < index; i++) {
178 if (i > 0) {
179 sbval.append(", ");
180 sblen.append(", ");
181 }
182 if ((i % 8) == 0) {
183 sbval.append("\n ");
184 sblen.append("\n ");
185 }
186 if ((vals[i] & (byte)0x80) != 0) {
187 sbval.append("(byte)");
188 }
189 sbval.append(String.format("0x%02x", vals[i]));
190 sblen.append(String.format("%5d", lens[i]));
191 }
192
193 sbval.append("};\n");
194 sblen.append("};\n");
195
196 System.out.println(sbval.toString());
197 System.out.println(sblen.toString());
198
199 }
200
201
202 /**
203 * <p>
204 * This is a utility function for determining whether a specified
205 * Unicode character is a hexadecimal digit as defined in RFC 2396;
206 * that is, one of the ASCII characters 0-9, a-f, or A-F.
207 * </p>
208 *
209 * @param c to check for hex digit.
210 * @return true if it's allowed, false otherwise.
211 */
212 public static boolean isHexDigit(final char c) {
213
214 // I suspect most characters passed to this method will be
215 // correct hexadecimal digits, so I test for the true cases
216 // first. If this proves to be a performance bottleneck
217 // a switch statement or lookup table
218 // might optimize this.
219 if (c >= '0' && c <= '9') return true;
220 if (c >= 'A' && c <= 'F') return true;
221 if (c >= 'a' && c <= 'f') return true;
222
223 return false;
224 }
225
226 /**
227 * <p>
228 * This is a utility function for determining whether
229 * a specified Unicode character is legal in URI references
230 * as determined by RFC 2396.
231 * </p>
232 *
233 * @param c <code>char</code> to check for URI reference compliance.
234 * @return true if it's allowed, false otherwise.
235 */
236 public static boolean isURICharacter(final char c) {
237 if (c >= 'a' && c <= 'z') return true;
238 if (c >= 'A' && c <= 'Z') return true;
239 if (c >= '0' && c <= '9') return true;
240 if (c == '/') return true;
241 if (c == '-') return true;
242 if (c == '.') return true;
243 if (c == '?') return true;
244 if (c == ':') return true;
245 if (c == '@') return true;
246 if (c == '&') return true;
247 if (c == '=') return true;
248 if (c == '+') return true;
249 if (c == '$') return true;
250 if (c == ',') return true;
251 if (c == '%') return true;
252
253 if (c == '_') return true;
254 if (c == '!') return true;
255 if (c == '~') return true;
256 if (c == '*') return true;
257 if (c == '\'') return true;
258 if (c == '(') return true;
259 if (c == ')') return true;
260 return false;
261 }
262
263 /**
264 * This is a utility function for determining whether a specified
265 * character is a character according to production 2 of the
266 * XML 1.0 specification.
267 *
268 * @param c <code>char</code> to check for XML compliance
269 * @return <code>boolean</code> true if it's a character,
270 * false otherwise
271 */
272 public static boolean isXMLCharacter(final int c) {
273
274 if (c == '\n') return true;
275 if (c == '\r') return true;
276 if (c == '\t') return true;
277
278 if (c < 0x20) return false; if (c <= 0xD7FF) return true;
279 if (c < 0xE000) return false; if (c <= 0xFFFD) return true;
280 if (c < 0x10000) return false; if (c <= 0x10FFFF) return true;
281
282 return false;
283 }
284
285
286 /**
287 * This is a utility function for determining whether a specified
288 * character is a name character according to production 4 of the
289 * XML 1.0 specification.
290 *
291 * @param c <code>char</code> to check for XML name compliance.
292 * @return <code>boolean</code> true if it's a name character,
293 * false otherwise.
294 */
295 public static boolean isXMLNameCharacter(final char c) {
296
297 // remove check for || c == ':'
298 // JDOM Attributes and Elements cannot start with ':' since JDOM
299 // seperates the prefix from the name.
300 // we do not want ':' in the bitmask, instead we add it later.
301
302 return (isXMLLetter(c) || isXMLDigit(c) || c == '.' || c == '-'
303 || c == '_' || isXMLCombiningChar(c)
304 || Verifier.isXMLExtender(c));
305 }
306
307 /**
308 * This is a utility function for determining whether a specified
309 * character is a legal name start character according to production 5
310 * of the XML 1.0 specification. This production does allow names
311 * to begin with colons which the Namespaces in XML Recommendation
312 * disallows.
313 *
314 * @param c <code>char</code> to check for XML name start compliance.
315 * @return <code>boolean</code> true if it's a name start character,
316 * false otherwise.
317 */
318 public static boolean isXMLNameStartCharacter(final char c) {
319
320 // remove check for || c == ':'
321 // JDOM Attributes and Elements cannot start with ':' since JDOM
322 // seperates the prefix from the name.
323 // we do not want ':' in the bitmask, instead we add it later.
324
325 return (isXMLLetter(c) || c == '_');
326
327 }
328
329 /**
330 * This is a utility function for determining whether a specified character
331 * is a letter according to production 84 of the XML 1.0 specification.
332 *
333 * @param c <code>char</code> to check for XML name compliance.
334 * @return <code>String</code> true if it's a letter, false otherwise.
335 */
336 public static boolean isXMLLetter(final char c) {
337 // Note that order is very important here. The search proceeds
338 // from lowest to highest values, so that no searching occurs
339 // above the character's value. BTW, the first line is equivalent to:
340 // if (c >= 0x0041 && c <= 0x005A) return true;
341
342 if (c < 0x0041) return false; if (c <= 0x005a) return true;
343 if (c < 0x0061) return false; if (c <= 0x007A) return true;
344 if (c < 0x00C0) return false; if (c <= 0x00D6) return true;
345 if (c < 0x00D8) return false; if (c <= 0x00F6) return true;
346 if (c < 0x00F8) return false; if (c <= 0x00FF) return true;
347 if (c < 0x0100) return false; if (c <= 0x0131) return true;
348 if (c < 0x0134) return false; if (c <= 0x013E) return true;
349 if (c < 0x0141) return false; if (c <= 0x0148) return true;
350 if (c < 0x014A) return false; if (c <= 0x017E) return true;
351 if (c < 0x0180) return false; if (c <= 0x01C3) return true;
352 if (c < 0x01CD) return false; if (c <= 0x01F0) return true;
353 if (c < 0x01F4) return false; if (c <= 0x01F5) return true;
354 if (c < 0x01FA) return false; if (c <= 0x0217) return true;
355 if (c < 0x0250) return false; if (c <= 0x02A8) return true;
356 if (c < 0x02BB) return false; if (c <= 0x02C1) return true;
357 if (c == 0x0386) return true;
358 if (c < 0x0388) return false; if (c <= 0x038A) return true;
359 if (c == 0x038C) return true;
360 if (c < 0x038E) return false; if (c <= 0x03A1) return true;
361 if (c < 0x03A3) return false; if (c <= 0x03CE) return true;
362 if (c < 0x03D0) return false; if (c <= 0x03D6) return true;
363 if (c == 0x03DA) return true;
364 if (c == 0x03DC) return true;
365 if (c == 0x03DE) return true;
366 if (c == 0x03E0) return true;
367 if (c < 0x03E2) return false; if (c <= 0x03F3) return true;
368 if (c < 0x0401) return false; if (c <= 0x040C) return true;
369 if (c < 0x040E) return false; if (c <= 0x044F) return true;
370 if (c < 0x0451) return false; if (c <= 0x045C) return true;
371 if (c < 0x045E) return false; if (c <= 0x0481) return true;
372 if (c < 0x0490) return false; if (c <= 0x04C4) return true;
373 if (c < 0x04C7) return false; if (c <= 0x04C8) return true;
374 if (c < 0x04CB) return false; if (c <= 0x04CC) return true;
375 if (c < 0x04D0) return false; if (c <= 0x04EB) return true;
376 if (c < 0x04EE) return false; if (c <= 0x04F5) return true;
377 if (c < 0x04F8) return false; if (c <= 0x04F9) return true;
378 if (c < 0x0531) return false; if (c <= 0x0556) return true;
379 if (c == 0x0559) return true;
380 if (c < 0x0561) return false; if (c <= 0x0586) return true;
381 if (c < 0x05D0) return false; if (c <= 0x05EA) return true;
382 if (c < 0x05F0) return false; if (c <= 0x05F2) return true;
383 if (c < 0x0621) return false; if (c <= 0x063A) return true;
384 if (c < 0x0641) return false; if (c <= 0x064A) return true;
385 if (c < 0x0671) return false; if (c <= 0x06B7) return true;
386 if (c < 0x06BA) return false; if (c <= 0x06BE) return true;
387 if (c < 0x06C0) return false; if (c <= 0x06CE) return true;
388 if (c < 0x06D0) return false; if (c <= 0x06D3) return true;
389 if (c == 0x06D5) return true;
390 if (c < 0x06E5) return false; if (c <= 0x06E6) return true;
391 if (c < 0x0905) return false; if (c <= 0x0939) return true;
392 if (c == 0x093D) return true;
393 if (c < 0x0958) return false; if (c <= 0x0961) return true;
394 if (c < 0x0985) return false; if (c <= 0x098C) return true;
395 if (c < 0x098F) return false; if (c <= 0x0990) return true;
396 if (c < 0x0993) return false; if (c <= 0x09A8) return true;
397 if (c < 0x09AA) return false; if (c <= 0x09B0) return true;
398 if (c == 0x09B2) return true;
399 if (c < 0x09B6) return false; if (c <= 0x09B9) return true;
400 if (c < 0x09DC) return false; if (c <= 0x09DD) return true;
401 if (c < 0x09DF) return false; if (c <= 0x09E1) return true;
402 if (c < 0x09F0) return false; if (c <= 0x09F1) return true;
403 if (c < 0x0A05) return false; if (c <= 0x0A0A) return true;
404 if (c < 0x0A0F) return false; if (c <= 0x0A10) return true;
405 if (c < 0x0A13) return false; if (c <= 0x0A28) return true;
406 if (c < 0x0A2A) return false; if (c <= 0x0A30) return true;
407 if (c < 0x0A32) return false; if (c <= 0x0A33) return true;
408 if (c < 0x0A35) return false; if (c <= 0x0A36) return true;
409 if (c < 0x0A38) return false; if (c <= 0x0A39) return true;
410 if (c < 0x0A59) return false; if (c <= 0x0A5C) return true;
411 if (c == 0x0A5E) return true;
412 if (c < 0x0A72) return false; if (c <= 0x0A74) return true;
413 if (c < 0x0A85) return false; if (c <= 0x0A8B) return true;
414 if (c == 0x0A8D) return true;
415 if (c < 0x0A8F) return false; if (c <= 0x0A91) return true;
416 if (c < 0x0A93) return false; if (c <= 0x0AA8) return true;
417 if (c < 0x0AAA) return false; if (c <= 0x0AB0) return true;
418 if (c < 0x0AB2) return false; if (c <= 0x0AB3) return true;
419 if (c < 0x0AB5) return false; if (c <= 0x0AB9) return true;
420 if (c == 0x0ABD) return true;
421 if (c == 0x0AE0) return true;
422 if (c < 0x0B05) return false; if (c <= 0x0B0C) return true;
423 if (c < 0x0B0F) return false; if (c <= 0x0B10) return true;
424 if (c < 0x0B13) return false; if (c <= 0x0B28) return true;
425 if (c < 0x0B2A) return false; if (c <= 0x0B30) return true;
426 if (c < 0x0B32) return false; if (c <= 0x0B33) return true;
427 if (c < 0x0B36) return false; if (c <= 0x0B39) return true;
428 if (c == 0x0B3D) return true;
429 if (c < 0x0B5C) return false; if (c <= 0x0B5D) return true;
430 if (c < 0x0B5F) return false; if (c <= 0x0B61) return true;
431 if (c < 0x0B85) return false; if (c <= 0x0B8A) return true;
432 if (c < 0x0B8E) return false; if (c <= 0x0B90) return true;
433 if (c < 0x0B92) return false; if (c <= 0x0B95) return true;
434 if (c < 0x0B99) return false; if (c <= 0x0B9A) return true;
435 if (c == 0x0B9C) return true;
436 if (c < 0x0B9E) return false; if (c <= 0x0B9F) return true;
437 if (c < 0x0BA3) return false; if (c <= 0x0BA4) return true;
438 if (c < 0x0BA8) return false; if (c <= 0x0BAA) return true;
439 if (c < 0x0BAE) return false; if (c <= 0x0BB5) return true;
440 if (c < 0x0BB7) return false; if (c <= 0x0BB9) return true;
441 if (c < 0x0C05) return false; if (c <= 0x0C0C) return true;
442 if (c < 0x0C0E) return false; if (c <= 0x0C10) return true;
443 if (c < 0x0C12) return false; if (c <= 0x0C28) return true;
444 if (c < 0x0C2A) return false; if (c <= 0x0C33) return true;
445 if (c < 0x0C35) return false; if (c <= 0x0C39) return true;
446 if (c < 0x0C60) return false; if (c <= 0x0C61) return true;
447 if (c < 0x0C85) return false; if (c <= 0x0C8C) return true;
448 if (c < 0x0C8E) return false; if (c <= 0x0C90) return true;
449 if (c < 0x0C92) return false; if (c <= 0x0CA8) return true;
450 if (c < 0x0CAA) return false; if (c <= 0x0CB3) return true;
451 if (c < 0x0CB5) return false; if (c <= 0x0CB9) return true;
452 if (c == 0x0CDE) return true;
453 if (c < 0x0CE0) return false; if (c <= 0x0CE1) return true;
454 if (c < 0x0D05) return false; if (c <= 0x0D0C) return true;
455 if (c < 0x0D0E) return false; if (c <= 0x0D10) return true;
456 if (c < 0x0D12) return false; if (c <= 0x0D28) return true;
457 if (c < 0x0D2A) return false; if (c <= 0x0D39) return true;
458 if (c < 0x0D60) return false; if (c <= 0x0D61) return true;
459 if (c < 0x0E01) return false; if (c <= 0x0E2E) return true;
460 if (c == 0x0E30) return true;
461 if (c < 0x0E32) return false; if (c <= 0x0E33) return true;
462 if (c < 0x0E40) return false; if (c <= 0x0E45) return true;
463 if (c < 0x0E81) return false; if (c <= 0x0E82) return true;
464 if (c == 0x0E84) return true;
465 if (c < 0x0E87) return false; if (c <= 0x0E88) return true;
466 if (c == 0x0E8A) return true;
467 if (c == 0x0E8D) return true;
468 if (c < 0x0E94) return false; if (c <= 0x0E97) return true;
469 if (c < 0x0E99) return false; if (c <= 0x0E9F) return true;
470 if (c < 0x0EA1) return false; if (c <= 0x0EA3) return true;
471 if (c == 0x0EA5) return true;
472 if (c == 0x0EA7) return true;
473 if (c < 0x0EAA) return false; if (c <= 0x0EAB) return true;
474 if (c < 0x0EAD) return false; if (c <= 0x0EAE) return true;
475 if (c == 0x0EB0) return true;
476 if (c < 0x0EB2) return false; if (c <= 0x0EB3) return true;
477 if (c == 0x0EBD) return true;
478 if (c < 0x0EC0) return false; if (c <= 0x0EC4) return true;
479 if (c < 0x0F40) return false; if (c <= 0x0F47) return true;
480 if (c < 0x0F49) return false; if (c <= 0x0F69) return true;
481 if (c < 0x10A0) return false; if (c <= 0x10C5) return true;
482 if (c < 0x10D0) return false; if (c <= 0x10F6) return true;
483 if (c == 0x1100) return true;
484 if (c < 0x1102) return false; if (c <= 0x1103) return true;
485 if (c < 0x1105) return false; if (c <= 0x1107) return true;
486 if (c == 0x1109) return true;
487 if (c < 0x110B) return false; if (c <= 0x110C) return true;
488 if (c < 0x110E) return false; if (c <= 0x1112) return true;
489 if (c == 0x113C) return true;
490 if (c == 0x113E) return true;
491 if (c == 0x1140) return true;
492 if (c == 0x114C) return true;
493 if (c == 0x114E) return true;
494 if (c == 0x1150) return true;
495 if (c < 0x1154) return false; if (c <= 0x1155) return true;
496 if (c == 0x1159) return true;
497 if (c < 0x115F) return false; if (c <= 0x1161) return true;
498 if (c == 0x1163) return true;
499 if (c == 0x1165) return true;
500 if (c == 0x1167) return true;
501 if (c == 0x1169) return true;
502 if (c < 0x116D) return false; if (c <= 0x116E) return true;
503 if (c < 0x1172) return false; if (c <= 0x1173) return true;
504 if (c == 0x1175) return true;
505 if (c == 0x119E) return true;
506 if (c == 0x11A8) return true;
507 if (c == 0x11AB) return true;
508 if (c < 0x11AE) return false; if (c <= 0x11AF) return true;
509 if (c < 0x11B7) return false; if (c <= 0x11B8) return true;
510 if (c == 0x11BA) return true;
511 if (c < 0x11BC) return false; if (c <= 0x11C2) return true;
512 if (c == 0x11EB) return true;
513 if (c == 0x11F0) return true;
514 if (c == 0x11F9) return true;
515 if (c < 0x1E00) return false; if (c <= 0x1E9B) return true;
516 if (c < 0x1EA0) return false; if (c <= 0x1EF9) return true;
517 if (c < 0x1F00) return false; if (c <= 0x1F15) return true;
518 if (c < 0x1F18) return false; if (c <= 0x1F1D) return true;
519 if (c < 0x1F20) return false; if (c <= 0x1F45) return true;
520 if (c < 0x1F48) return false; if (c <= 0x1F4D) return true;
521 if (c < 0x1F50) return false; if (c <= 0x1F57) return true;
522 if (c == 0x1F59) return true;
523 if (c == 0x1F5B) return true;
524 if (c == 0x1F5D) return true;
525 if (c < 0x1F5F) return false; if (c <= 0x1F7D) return true;
526 if (c < 0x1F80) return false; if (c <= 0x1FB4) return true;
527 if (c < 0x1FB6) return false; if (c <= 0x1FBC) return true;
528 if (c == 0x1FBE) return true;
529 if (c < 0x1FC2) return false; if (c <= 0x1FC4) return true;
530 if (c < 0x1FC6) return false; if (c <= 0x1FCC) return true;
531 if (c < 0x1FD0) return false; if (c <= 0x1FD3) return true;
532 if (c < 0x1FD6) return false; if (c <= 0x1FDB) return true;
533 if (c < 0x1FE0) return false; if (c <= 0x1FEC) return true;
534 if (c < 0x1FF2) return false; if (c <= 0x1FF4) return true;
535 if (c < 0x1FF6) return false; if (c <= 0x1FFC) return true;
536 if (c == 0x2126) return true;
537 if (c < 0x212A) return false; if (c <= 0x212B) return true;
538 if (c == 0x212E) return true;
539 if (c < 0x2180) return false; if (c <= 0x2182) return true;
540 if (c == 0x3007) return true; // ideographic
541 if (c < 0x3021) return false; if (c <= 0x3029) return true; // ideo
542 if (c < 0x3041) return false; if (c <= 0x3094) return true;
543 if (c < 0x30A1) return false; if (c <= 0x30FA) return true;
544 if (c < 0x3105) return false; if (c <= 0x312C) return true;
545 if (c < 0x4E00) return false; if (c <= 0x9FA5) return true; // ideo
546 if (c < 0xAC00) return false; if (c <= 0xD7A3) return true;
547
548 return false;
549
550 }
551
552 /**
553 * This is a utility function for determining whether a specified character
554 * is a combining character according to production 87
555 * of the XML 1.0 specification.
556 *
557 * @param c <code>char</code> to check.
558 * @return <code>boolean</code> true if it's a combining character,
559 * false otherwise.
560 */
561 public static boolean isXMLCombiningChar(final char c) {
562 // CombiningChar
563 if (c < 0x0300) return false; if (c <= 0x0345) return true;
564 if (c < 0x0360) return false; if (c <= 0x0361) return true;
565 if (c < 0x0483) return false; if (c <= 0x0486) return true;
566 if (c < 0x0591) return false; if (c <= 0x05A1) return true;
567
568 if (c < 0x05A3) return false; if (c <= 0x05B9) return true;
569 if (c < 0x05BB) return false; if (c <= 0x05BD) return true;
570 if (c == 0x05BF) return true;
571 if (c < 0x05C1) return false; if (c <= 0x05C2) return true;
572
573 if (c == 0x05C4) return true;
574 if (c < 0x064B) return false; if (c <= 0x0652) return true;
575 if (c == 0x0670) return true;
576 if (c < 0x06D6) return false; if (c <= 0x06DC) return true;
577
578 if (c < 0x06DD) return false; if (c <= 0x06DF) return true;
579 if (c < 0x06E0) return false; if (c <= 0x06E4) return true;
580 if (c < 0x06E7) return false; if (c <= 0x06E8) return true;
581
582 if (c < 0x06EA) return false; if (c <= 0x06ED) return true;
583 if (c < 0x0901) return false; if (c <= 0x0903) return true;
584 if (c == 0x093C) return true;
585 if (c < 0x093E) return false; if (c <= 0x094C) return true;
586
587 if (c == 0x094D) return true;
588 if (c < 0x0951) return false; if (c <= 0x0954) return true;
589 if (c < 0x0962) return false; if (c <= 0x0963) return true;
590 if (c < 0x0981) return false; if (c <= 0x0983) return true;
591
592 if (c == 0x09BC) return true;
593 if (c == 0x09BE) return true;
594 if (c == 0x09BF) return true;
595 if (c < 0x09C0) return false; if (c <= 0x09C4) return true;
596 if (c < 0x09C7) return false; if (c <= 0x09C8) return true;
597
598 if (c < 0x09CB) return false; if (c <= 0x09CD) return true;
599 if (c == 0x09D7) return true;
600 if (c < 0x09E2) return false; if (c <= 0x09E3) return true;
601 if (c == 0x0A02) return true;
602 if (c == 0x0A3C) return true;
603
604 if (c == 0x0A3E) return true;
605 if (c == 0x0A3F) return true;
606 if (c < 0x0A40) return false; if (c <= 0x0A42) return true;
607 if (c < 0x0A47) return false; if (c <= 0x0A48) return true;
608
609 if (c < 0x0A4B) return false; if (c <= 0x0A4D) return true;
610 if (c < 0x0A70) return false; if (c <= 0x0A71) return true;
611 if (c < 0x0A81) return false; if (c <= 0x0A83) return true;
612 if (c == 0x0ABC) return true;
613
614 if (c < 0x0ABE) return false; if (c <= 0x0AC5) return true;
615 if (c < 0x0AC7) return false; if (c <= 0x0AC9) return true;
616 if (c < 0x0ACB) return false; if (c <= 0x0ACD) return true;
617
618 if (c < 0x0B01) return false; if (c <= 0x0B03) return true;
619 if (c == 0x0B3C) return true;
620 if (c < 0x0B3E) return false; if (c <= 0x0B43) return true;
621 if (c < 0x0B47) return false; if (c <= 0x0B48) return true;
622
623 if (c < 0x0B4B) return false; if (c <= 0x0B4D) return true;
624 if (c < 0x0B56) return false; if (c <= 0x0B57) return true;
625 if (c < 0x0B82) return false; if (c <= 0x0B83) return true;
626
627 if (c < 0x0BBE) return false; if (c <= 0x0BC2) return true;
628 if (c < 0x0BC6) return false; if (c <= 0x0BC8) return true;
629 if (c < 0x0BCA) return false; if (c <= 0x0BCD) return true;
630 if (c == 0x0BD7) return true;
631
632 if (c < 0x0C01) return false; if (c <= 0x0C03) return true;
633 if (c < 0x0C3E) return false; if (c <= 0x0C44) return true;
634 if (c < 0x0C46) return false; if (c <= 0x0C48) return true;
635
636 if (c < 0x0C4A) return false; if (c <= 0x0C4D) return true;
637 if (c < 0x0C55) return false; if (c <= 0x0C56) return true;
638 if (c < 0x0C82) return false; if (c <= 0x0C83) return true;
639
640 if (c < 0x0CBE) return false; if (c <= 0x0CC4) return true;
641 if (c < 0x0CC6) return false; if (c <= 0x0CC8) return true;
642 if (c < 0x0CCA) return false; if (c <= 0x0CCD) return true;
643
644 if (c < 0x0CD5) return false; if (c <= 0x0CD6) return true;
645 if (c < 0x0D02) return false; if (c <= 0x0D03) return true;
646 if (c < 0x0D3E) return false; if (c <= 0x0D43) return true;
647
648 if (c < 0x0D46) return false; if (c <= 0x0D48) return true;
649 if (c < 0x0D4A) return false; if (c <= 0x0D4D) return true;
650 if (c == 0x0D57) return true;
651 if (c == 0x0E31) return true;
652
653 if (c < 0x0E34) return false; if (c <= 0x0E3A) return true;
654 if (c < 0x0E47) return false; if (c <= 0x0E4E) return true;
655 if (c == 0x0EB1) return true;
656 if (c < 0x0EB4) return false; if (c <= 0x0EB9) return true;
657
658 if (c < 0x0EBB) return false; if (c <= 0x0EBC) return true;
659 if (c < 0x0EC8) return false; if (c <= 0x0ECD) return true;
660 if (c < 0x0F18) return false; if (c <= 0x0F19) return true;
661 if (c == 0x0F35) return true;
662
663 if (c == 0x0F37) return true;
664 if (c == 0x0F39) return true;
665 if (c == 0x0F3E) return true;
666 if (c == 0x0F3F) return true;
667 if (c < 0x0F71) return false; if (c <= 0x0F84) return true;
668
669 if (c < 0x0F86) return false; if (c <= 0x0F8B) return true;
670 if (c < 0x0F90) return false; if (c <= 0x0F95) return true;
671 if (c == 0x0F97) return true;
672 if (c < 0x0F99) return false; if (c <= 0x0FAD) return true;
673
674 if (c < 0x0FB1) return false; if (c <= 0x0FB7) return true;
675 if (c == 0x0FB9) return true;
676 if (c < 0x20D0) return false; if (c <= 0x20DC) return true;
677 if (c == 0x20E1) return true;
678
679 if (c < 0x302A) return false; if (c <= 0x302F) return true;
680 if (c == 0x3099) return true;
681 if (c == 0x309A) return true;
682
683 return false;
684
685 }
686
687 /**
688 * This is a utility function for determining whether a specified
689 * Unicode character
690 * is a digit according to production 88 of the XML 1.0 specification.
691 *
692 * @param c <code>char</code> to check for XML digit compliance
693 * @return <code>boolean</code> true if it's a digit, false otherwise
694 */
695 public static boolean isXMLDigit(final char c) {
696
697 if (c < 0x0030) return false; if (c <= 0x0039) return true;
698 if (c < 0x0660) return false; if (c <= 0x0669) return true;
699 if (c < 0x06F0) return false; if (c <= 0x06F9) return true;
700 if (c < 0x0966) return false; if (c <= 0x096F) return true;
701
702 if (c < 0x09E6) return false; if (c <= 0x09EF) return true;
703 if (c < 0x0A66) return false; if (c <= 0x0A6F) return true;
704 if (c < 0x0AE6) return false; if (c <= 0x0AEF) return true;
705
706 if (c < 0x0B66) return false; if (c <= 0x0B6F) return true;
707 if (c < 0x0BE7) return false; if (c <= 0x0BEF) return true;
708 if (c < 0x0C66) return false; if (c <= 0x0C6F) return true;
709
710 if (c < 0x0CE6) return false; if (c <= 0x0CEF) return true;
711 if (c < 0x0D66) return false; if (c <= 0x0D6F) return true;
712 if (c < 0x0E50) return false; if (c <= 0x0E59) return true;
713
714 if (c < 0x0ED0) return false; if (c <= 0x0ED9) return true;
715 if (c < 0x0F20) return false; if (c <= 0x0F29) return true;
716
717 return false;
718 }
719
720 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.xpath.java;
55
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.Map;
61
62 import javax.xml.namespace.NamespaceContext;
63 import javax.xml.namespace.QName;
64 import javax.xml.xpath.XPath;
65 import javax.xml.xpath.XPathConstants;
66 import javax.xml.xpath.XPathExpressionException;
67 import javax.xml.xpath.XPathFactory;
68 import javax.xml.xpath.XPathVariableResolver;
69
70 import org.w3c.dom.Attr;
71 import org.w3c.dom.NodeList;
72
73 import org.jdom.Attribute;
74 import org.jdom.CDATA;
75 import org.jdom.Comment;
76 import org.jdom.Content;
77 import org.jdom.DocType;
78 import org.jdom.Document;
79 import org.jdom.Element;
80 import org.jdom.EntityRef;
81 import org.jdom.JDOMConstants;
82 import org.jdom.Namespace;
83 import org.jdom.ProcessingInstruction;
84 import org.jdom.Text;
85 import org.jdom.contrib.dom.DOM;
86 import org.jdom.contrib.dom.Wrapper;
87 import org.jdom.filter2.Filter;
88 import org.jdom.internal.ArrayCopy;
89 import org.jdom.xpath.util.AbstractXPathCompiled;
90
91 /**
92 * An XPathExpression that uses the native Java5 javax.xml.xpath mechanisms
93 * to implement XPath.
94 *
95 * @author Rolf Lear
96 *
97 * @param <T> the type of the coerced results.
98 */
99 class JavaXPathExpression<T> extends AbstractXPathCompiled <T>
100 implements XPathVariableResolver, NamespaceContext {
101
102 private static final Namespace[] EMPTYNS = new Namespace[0];
103
104 final javax.xml.xpath.XPathExpression rawexpression;
105 final Namespace[] nsraw;
106
107 /**
108 * Construct the XPathExpression.
109 * @param query The XPath query to create.
110 * @param filter The coercion filter.
111 * @param variables The variable map
112 * @param namespaces The scope namespaces.
113 * @param fac The XMLFactory to use for construction.
114 */
115 public JavaXPathExpression(final String query, final Filter<T> filter,
116 final Map<String, Object> variables, final Namespace[] namespaces,
117 final XPathFactory fac) {
118 super(query, filter, variables, namespaces);
119 nsraw = namespaces == null ? EMPTYNS :
120 ArrayCopy.copyOf(namespaces, namespaces.length);
121 final XPath xp = fac.newXPath();
122 xp.setNamespaceContext(this);
123 xp.setXPathVariableResolver(this);
124 try {
125 rawexpression = xp.compile(query);
126 } catch (XPathExpressionException e) {
127 throw new IllegalArgumentException(
128 "Unable to compile expression: " + query, e);
129 }
130 }
131
132 @Override
133 public String getNamespaceURI(String prefix) {
134 return getNamespace(prefix).getURI();
135 }
136
137 @Override
138 public String getPrefix(String namespaceURI) {
139 if (namespaceURI == null) {
140 // the API doc for NamespaceContext says to throw IllegalArgument
141 // not NullPointer.
142 throw new IllegalArgumentException("Null namespaceURI");
143 }
144 if (JDOMConstants.NS_URI_XML.equals(namespaceURI)) {
145 return JDOMConstants.NS_PREFIX_XML;
146 }
147 if (JDOMConstants.NS_URI_XMLNS.equals(namespaceURI)) {
148 return JDOMConstants.NS_PREFIX_XMLNS;
149 }
150 for (Namespace ns : nsraw) {
151 if (namespaceURI.equals(ns.getURI())) {
152 return ns.getPrefix();
153 }
154 }
155 return null;
156 }
157
158 @Override
159 public Iterator<String> getPrefixes(String namespaceURI) {
160 if (namespaceURI == null) {
161 // the API doc for NamespaceContext says to throw IllegalArgument
162 // not NullPointer.
163 throw new IllegalArgumentException("Null namespaceURI");
164 }
165 if (JDOMConstants.NS_URI_XML.equals(namespaceURI)) {
166 return Collections.singleton(JDOMConstants.NS_PREFIX_XML).iterator();
167 }
168 if (JDOMConstants.NS_URI_XMLNS.equals(namespaceURI)) {
169 return Collections.singleton(JDOMConstants.NS_PREFIX_XMLNS).iterator();
170 }
171 ArrayList<String> pfx = new ArrayList<String>();
172 for (Namespace ns : nsraw) {
173 if (namespaceURI.equals(ns.getURI())) {
174 pfx.add(ns.getPrefix());
175 }
176 }
177 return Collections.unmodifiableList(pfx).iterator();
178 }
179
180 @Override
181 public Object resolveVariable(QName variableName) {
182 return getVariable(variableName.getLocalPart(),
183 Namespace.getNamespace(variableName.getNamespaceURI()));
184 }
185
186 private Object wrapContext(Object context) {
187 if (context instanceof Content) {
188 switch (((Content)context).getCType()) {
189 case CDATA :
190 return DOM.wrap((CDATA)context);
191 case Comment:
192 return DOM.wrap((Comment)context);
193 case DocType:
194 return DOM.wrap((DocType)context);
195 case Element:
196 return DOM.wrap((Element)context);
197 case EntityRef:
198 return DOM.wrap((EntityRef)context);
199 case ProcessingInstruction:
200 return DOM.wrap((ProcessingInstruction)context);
201 case Text:
202 return DOM.wrap((Text)context);
203 }
204 throw new IllegalStateException("Should never break out of swich");
205 } else if (context instanceof Attribute) {
206 return DOM.wrap((Attribute)context);
207 } else if (context instanceof Document) {
208 return DOM.wrap((Document)context);
209 } else {
210 throw new IllegalArgumentException(
211 "Unable to process context: " + context);
212 }
213 }
214
215 private Object unWrap(final Object o) {
216 if (o instanceof Wrapper) {
217 return ((Wrapper)o).getWrapped();
218 }
219 if (o instanceof Attr) {
220 // odd one....
221 // DOM has no node for Namespaces, so the typical XPath engine on
222 // DOM nodes returns an Attr representation for the Namespace.
223 // easy to check....
224 Attr a = (Attr)o;
225 if (JDOMConstants.NS_URI_XMLNS.equals(a.getNamespaceURI())) {
226 // it is an xml declaration.
227 return Namespace.getNamespace(a.getLocalName(), a.getValue());
228 }
229 if (JDOMConstants.NS_PREFIX_DEFAULT.equals(a.getNamespaceURI()) &&
230 JDOMConstants.NS_PREFIX_XMLNS.equals(a.getLocalName())) {
231 return Namespace.getNamespace(a.getValue());
232 }
233 }
234 return o;
235 }
236
237 @Override
238 protected List<?> evaluateRawAll(Object context) {
239 final Object ctx = wrapContext(context);
240 try {
241 final NodeList nl = (NodeList)rawexpression.evaluate(
242 ctx, XPathConstants.NODESET);
243 final int sz = nl.getLength();
244 ArrayList<Object> ret = new ArrayList<Object>(sz);
245 for (int i = 0; i < sz; i++) {
246 ret.add(unWrap(nl.item(i)));
247 }
248 return ret;
249 } catch (XPathExpressionException e) {
250 throw new IllegalStateException(
251 "Unable to evaluate expression: " + this.toString(), e);
252 }
253 }
254
255 @Override
256 protected Object evaluateRawFirst(Object context) {
257 final Object ctx = wrapContext(context);
258 try {
259 final NodeList nl = (NodeList)rawexpression.evaluate(
260 ctx, XPathConstants.NODESET);
261 if (nl.getLength() == 0) {
262 return null;
263 }
264 return unWrap(nl.item(0));
265 } catch (XPathExpressionException e) {
266 throw new IllegalStateException(
267 "Unable to evaluate expression: " + this.toString(), e);
268 }
269 }
270
271 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.xpath.java;
55
56 import java.util.Map;
57
58 import javax.xml.xpath.XPathFactory;
59
60 import org.jdom.Namespace;
61 import org.jdom.filter2.Filter;
62 import org.jdom.xpath.XPathExpression;
63
64 /**
65 * An XPathFactory using the underlying infrastructure in javax.xml.xpath.*
66 * to process the XPath expressions against the JDOM content.
67 * @author Rolf Lear
68 *
69 */
70 public class JavaXPathFactory extends org.jdom.xpath.XPathFactory {
71
72 ThreadLocal<XPathFactory> localfac =
73 new ThreadLocal<XPathFactory>();
74
75 @Override
76 public <T> XPathExpression<T> compile(String expression, Filter<T> filter,
77 Map<String, Object> variables, Namespace... namespaces) {
78 // Java XPath factories are not thread safe... use a thread-local.
79 XPathFactory fac = localfac.get();
80 if (fac == null) {
81 fac = XPathFactory.newInstance();
82 localfac.set(fac);
83 }
84 return new JavaXPathExpression<T>(
85 expression, filter, variables, namespaces, fac);
86 }
87
88 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.xpath.xalan;
55
56 import java.util.Collections;
57 import java.util.List;
58
59 import javax.xml.transform.SourceLocator;
60
61 import org.apache.xml.dtm.DTM;
62 import org.apache.xml.dtm.DTMManager;
63 import org.apache.xml.dtm.DTMWSFilter;
64 import org.apache.xml.dtm.ref.DTMDefaultBaseIterators;
65 import org.apache.xml.dtm.ref.DTMManagerDefault;
66 import org.apache.xml.dtm.ref.ExpandedNameTable;
67 import org.apache.xml.res.XMLErrorResources;
68 import org.apache.xml.res.XMLMessages;
69 import org.apache.xml.utils.XMLString;
70 import org.apache.xml.utils.XMLStringFactory;
71 import org.xml.sax.ContentHandler;
72 import org.xml.sax.DTDHandler;
73 import org.xml.sax.EntityResolver;
74 import org.xml.sax.ErrorHandler;
75 import org.xml.sax.SAXException;
76 import org.xml.sax.ext.DeclHandler;
77 import org.xml.sax.ext.LexicalHandler;
78
79 import org.jdom.Attribute;
80 import org.jdom.Content;
81 import org.jdom.DocType;
82 import org.jdom.Document;
83 import org.jdom.Element;
84 import org.jdom.Namespace;
85 import org.jdom.NamespaceAware;
86 import org.jdom.Parent;
87 import org.jdom.internal.ArrayCopy;
88 import org.jdom.transform.JDOMSource;
89 import org.jdom.util.NamespaceStack;
90
91 /**
92 * ***********************************************
93 * THIS CODE IS NOT COMPLETE... DO NOT USE IT
94 * Marked Deprecated
95 * ***********************************************
96 *
97 *
98 *
99 *
100 * Create a DTM navigator to a JDOM document
101 *
102 * @author Rolf Lear
103 *
104 */
105 @Deprecated
106 public class JDOM2DTM extends DTMDefaultBaseIterators {
107
108 private static final int getType(NamespaceAware nsa) {
109 if (nsa instanceof Content) {
110 switch (((Content)nsa).getCType()) {
111 case CDATA:
112 return DTM.CDATA_SECTION_NODE;
113 case Comment:
114 return DTM.COMMENT_NODE;
115 case DocType:
116 return DTM.DOCUMENT_TYPE_NODE;
117 case Element:
118 return DTM.ELEMENT_NODE;
119 case EntityRef:
120 return DTM.ENTITY_REFERENCE_NODE;
121 case ProcessingInstruction:
122 return DTM.PROCESSING_INSTRUCTION_NODE;
123 case Text:
124 return DTM.TEXT_NODE;
125 }
126 } else if (nsa instanceof Document) {
127 return DTM.DOCUMENT_NODE;
128 } else if (nsa instanceof Attribute) {
129 return DTM.ATTRIBUTE_NODE;
130 } else if (nsa instanceof NamespacePointer) {
131 return DTM.NAMESPACE_NODE;
132 }
133 throw new IllegalStateException("Unknonw node type " + nsa);
134 }
135
136 private NamespaceAware[] i_nodes = new NamespaceAware[1024];
137
138 private final String systemId, publicID;
139
140 /**
141 * @param mgr The DTMManager
142 * @param source The Source
143 * @param dtmIdentity The dtmIdentity
144 * @param whiteSpaceFilter the whitespace filter
145 * @param xstringfactory the xstringfactory
146 * @param doIndexing the indexing flag.
147 */
148 public JDOM2DTM(DTMManager mgr, JDOMSource source, int dtmIdentity,
149 DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory,
150 boolean doIndexing) {
151 super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, doIndexing);
152 String pid = null, sid = null;
153 Parent root = source.getDocument();
154 final NamespaceStack nstack = new NamespaceStack();
155 // we do not play around with 'on-demand' building of the tree.
156 // we build the whole thing 'one-shot'. maybe at some point we can
157 // make the process on-demand.
158 if (root != null) {
159 // the root is a document node.
160 final Document doc = (Document)root;
161 setDocumentBaseURI(doc.getBaseURI());
162 DocType dt = doc.getDocType();
163 if (dt != null) {
164 sid = dt.getSystemID();
165 pid = dt.getPublicID();
166 }
167 if (sid == null) {
168 sid = doc.getBaseURI();
169 }
170
171 addNodes(nstack, NULL, Collections.singletonList(doc));
172 } else {
173 addNodes(nstack, NULL, source.getNodes());
174 }
175 systemId = sid;
176 publicID = pid;
177 }
178
179 private int addNode(final NamespaceStack nstack, final int parent,
180 final int prevsib, final NamespaceAware nsa) {
181
182 final int nodeIndex = m_size++;
183 if (nodeIndex >= i_nodes.length) {
184 // add 50%
185 i_nodes = ArrayCopy.copyOf(i_nodes, nodeIndex + (nodeIndex >> 1) + 1);
186 }
187 i_nodes[nodeIndex] = nsa;
188
189 // copied from DOM2DTM.java .. not sure what this does....
190 // Have we overflowed a DTM Identity's addressing range?
191 if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS)) {
192 if(m_mgr==null) {
193 //"No more DTM IDs are available";
194 error(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_DTMIDS_AVAIL, null));
195 }
196
197 // Handle as Extended Addressing
198 final DTMManagerDefault mgrD=(DTMManagerDefault)m_mgr;
199 final int id=mgrD.getFirstFreeDTMID();
200 mgrD.addDTM(this,id,nodeIndex);
201 m_dtmIdent.addElement(id<<DTMManager.IDENT_DTM_NODE_BITS);
202 }
203
204 m_firstch.setElementAt(NOTPROCESSED,nodeIndex);
205 m_nextsib.setElementAt(NOTPROCESSED,nodeIndex);
206 m_prevsib.setElementAt(prevsib,nodeIndex);
207 m_parent.setElementAt(parent,nodeIndex);
208
209 if (((nsa instanceof Content) || (nsa instanceof Document)) &&
210 NOTPROCESSED == m_firstch.elementAt(parent)) {
211 // we are the first child.
212 // more than that, the 'Content/Document' test excludes Namespace
213 // and Attribute nodes... which do not form part of the XPath tree
214 m_firstch.setElementAt(nodeIndex, parent);
215 }
216
217 String localname = null;
218 String nsuri = null;
219 if (nsa instanceof Element) {
220 localname = ((Element)nsa).getName();
221 nsuri = ((Element)nsa).getNamespaceURI();
222 } else if (nsa instanceof Attribute) {
223 localname = ((Attribute)nsa).getName();
224 nsuri = ((Attribute)nsa).getNamespaceURI();
225 }
226
227 final ExpandedNameTable exnt = m_expandedNameTable;
228 final int ntype = getType(nsa);
229
230 final int expandedNameID = (localname == null) ?
231 exnt.getExpandedTypeID(ntype) :
232 exnt.getExpandedTypeID(nsuri, localname, ntype);
233
234 m_exptype.setElementAt(expandedNameID,nodeIndex);
235 indexNode(expandedNameID, nodeIndex);
236
237 if (nsa instanceof Parent) {
238 // recurse through the child content.
239 final Parent pn = (Parent)nsa;
240 if (pn instanceof Element) {
241 final Element element = (Element)pn;
242 nstack.push(element);
243 try {
244 int pns = NULL;
245 int nsid = NULL;
246 for (Namespace ns : nstack.addedForward()) {
247 nsid = addNode(nstack, nodeIndex, pns,
248 new NamespacePointer(ns));
249 if (pns != NULL) {
250 m_nextsib.setElementAt(nsid, pns);
251 }
252 pns = nsid;
253 }
254 if (nsid != NULL) {
255 // Set the last namespace sibling to NULL next.
256 m_nextsib.setElementAt(NULL, nsid);
257 }
258 if (element.hasAttributes()) {
259 int patt = NULL;
260 int attid = NULL;
261 for (Attribute att : element.getAttributes()) {
262 attid = addNode(nstack, nodeIndex, patt, att);
263 if (patt != NULL) {
264 m_nextsib.setElementAt(attid, patt);
265 }
266 patt = attid;
267 }
268 if (attid != NULL) {
269 // set the last attribute sibling to NULL next
270 m_nextsib.setElementAt(NULL, attid);
271 }
272 }
273 if (element.getContentSize() > 0) {
274 addNodes(nstack, nodeIndex, element.getContent());
275 }
276 } finally {
277 nstack.pop();
278 }
279 } else {
280 // must be Document.
281 if (pn.getContentSize() > 0) {
282 addNodes(nstack, nodeIndex, pn.getContent());
283 }
284 }
285 }
286
287 return nodeIndex;
288 }
289
290 private void addNodes(NamespaceStack nstack, int parentIndex,
291 List<? extends NamespaceAware> list) {
292 final int cs = list.size();
293 if (cs > 0) {
294 int pvid = NULL;
295 int cid = NULL;
296 for (int i = 0; i < cs; i++) {
297 final NamespaceAware c = list.get(i);
298 cid = addNode(nstack, parentIndex, pvid, c);
299 if (pvid == NULL) {
300 m_firstch.setElementAt(cid, parentIndex);
301 } else {
302 m_nextsib.setElementAt(cid, pvid);
303 }
304 pvid = cid;
305 }
306 if (cid != NULL) {
307 m_nextsib.setElementAt(NULL, cid);
308 }
309 }
310
311 }
312
313 @Override
314 protected int getNextNodeIdentity(int identity) {
315 identity += 1;
316
317 if (identity >= m_size) {
318 identity = DTM.NULL;
319 }
320
321 return identity;
322 }
323
324 @Override
325 protected boolean nextNode() {
326 // we pre-build the entire node, so this is always false.
327 return false;
328 }
329
330 @Override
331 protected int getNumberOfNodes() {
332 // we prebuild, so always false.
333 return m_size;
334 }
335
336 @Override
337 public int getAttributeNode(int nodeHandle, String namespaceURI, String name) {
338
339 return 0;
340 }
341
342 @Override
343 public XMLString getStringValue(int nodeHandle) {
344 // TODO Auto-generated method stub
345 return null;
346 }
347
348 @Override
349 public String getNodeName(int nodeHandle) {
350 // TODO Auto-generated method stub
351 return null;
352 }
353
354 @Override
355 public String getLocalName(int nodeHandle) {
356 // TODO Auto-generated method stub
357 return null;
358 }
359
360 @Override
361 public String getPrefix(int nodeHandle) {
362 // TODO Auto-generated method stub
363 return null;
364 }
365
366 @Override
367 public String getNamespaceURI(int nodeHandle) {
368 // TODO Auto-generated method stub
369 return null;
370 }
371
372 @Override
373 public String getNodeValue(int nodeHandle) {
374 // TODO Auto-generated method stub
375 return null;
376 }
377
378 @Override
379 public String getDocumentTypeDeclarationSystemIdentifier() {
380 return systemId;
381 }
382
383 @Override
384 public String getDocumentTypeDeclarationPublicIdentifier() {
385 return publicID;
386 }
387
388 @Override
389 public int getElementById(String elementId) {
390 // TODO Auto-generated method stub
391 return 0;
392 }
393
394 @Override
395 public String getUnparsedEntityURI(String name) {
396 // TODO Auto-generated method stub
397 return null;
398 }
399
400 @Override
401 public boolean isAttributeSpecified(int attributeHandle) {
402 // all attributes are specified
403 return true;
404 }
405
406 @Override
407 public SourceLocator getSourceLocatorFor(int node) {
408 return null;
409 }
410
411 @Override
412 public void setProperty(String property, Object value) {
413 // nothing.
414 }
415
416 @Override
417 public boolean needsTwoThreads() {
418 return false;
419 }
420
421
422 /* ***************************************************
423 * Unneeded SAX-Based methods.
424 * *************************************************** */
425
426 @Override
427 public ContentHandler getContentHandler() {
428 // nothing
429 return null;
430 }
431
432 @Override
433 public LexicalHandler getLexicalHandler() {
434 // nothing
435 return null;
436 }
437
438 @Override
439 public EntityResolver getEntityResolver() {
440 // nothing
441 return null;
442 }
443
444 @Override
445 public DTDHandler getDTDHandler() {
446 // nothing
447 return null;
448 }
449
450 @Override
451 public ErrorHandler getErrorHandler() {
452 // nothing
453 return null;
454 }
455
456 @Override
457 public DeclHandler getDeclHandler() {
458 // nothing
459 return null;
460 }
461
462 @Override
463 public void dispatchCharactersEvents(int nodeHandle, ContentHandler ch,
464 boolean normalize) throws SAXException {
465 // nothing
466 }
467
468 @Override
469 public void dispatchToEvents(int nodeHandle, ContentHandler ch)
470 throws SAXException {
471 // nothing
472 }
473
474 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.xpath.xalan;
55
56 import java.util.List;
57
58 import org.jdom.Namespace;
59 import org.jdom.NamespaceAware;
60
61 /**
62 * ***********************************************
63 * THIS CODE IS NOT COMPLETE... DO NOT USE IT
64 * Marked Deprecated
65 * ***********************************************
66 *
67 *
68 *
69 *
70 * Simple class to wrap a Namespace declaration.
71 *
72 * @author Rolf Lear
73 *
74 */
75 @Deprecated
76 class NamespacePointer implements NamespaceAware {
77
78 private final Namespace namespace;
79
80 /**
81 * @param namespace The namespace to point to.
82 */
83 public NamespacePointer(Namespace namespace) {
84 super();
85 this.namespace = namespace;
86 }
87
88 /**
89 * Get the underlyng namespace
90 * @return the underlying namespace
91 */
92 public Namespace getNamespace() {
93 return namespace;
94 }
95
96
97
98 @Override
99 public List<Namespace> getNamespacesInScope() {
100 return null;
101 }
102
103 @Override
104 public List<Namespace> getNamespacesIntroduced() {
105 return null;
106 }
107
108 @Override
109 public List<Namespace> getNamespacesInherited() {
110 return null;
111 }
112
113 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.xpath.xalan;
55
56 import java.util.ArrayList;
57 import java.util.List;
58 import java.util.Map;
59
60 import javax.xml.transform.TransformerException;
61
62 import org.apache.xml.utils.PrefixResolver;
63 import org.apache.xml.utils.QName;
64 import org.apache.xpath.VariableStack;
65 import org.apache.xpath.XPath;
66 import org.apache.xpath.XPathContext;
67 import org.apache.xpath.axes.NodeSequence;
68 import org.apache.xpath.objects.XObject;
69 import org.w3c.dom.Attr;
70 import org.w3c.dom.Node;
71 import org.w3c.dom.NodeList;
72
73 import org.jdom.Attribute;
74 import org.jdom.CDATA;
75 import org.jdom.Comment;
76 import org.jdom.Content;
77 import org.jdom.DocType;
78 import org.jdom.Document;
79 import org.jdom.Element;
80 import org.jdom.EntityRef;
81 import org.jdom.Namespace;
82 import org.jdom.NamespaceAware;
83 import org.jdom.ProcessingInstruction;
84 import org.jdom.Text;
85 import org.jdom.contrib.dom.DOM;
86 import org.jdom.contrib.dom.Wrapper;
87 import org.jdom.filter2.Filter;
88 import org.jdom.xpath.util.AbstractXPathCompiled;
89
90 /**
91 * An XPathExpression that wraps the JDOM content in DOM wrappers
92 * and then uses the Direct Xalan API to implement XPath.
93 *
94 * @author Rolf Lear
95 *
96 * @param <T> the type of the coerced results.
97 */
98 class XalanXPathExpression<T> extends AbstractXPathCompiled <T> implements PrefixResolver {
99
100 private final XPath xpath;
101
102 private final VariableStack variables = new VariableStack() {
103 @Override
104 public XObject getVariableOrParam(XPathContext xctxt, QName qname)
105 throws TransformerException {
106 if (qname == null) {
107 throw new IllegalArgumentException("Null qname");
108 }
109 final Object varValue = getVariable(qname.getLocalName(),
110 Namespace.getNamespace(qname.getNamespaceURI()));
111 if ( varValue == null ) {
112 throw new TransformerException(
113 "No such variable " + qname.toNamespacedString());
114 }
115 return XObject.create(varValue, xctxt);
116 }
117 };
118
119 /**
120 * Construct the XPathExpression.
121 * @param query The XPath query to create.
122 * @param filter The coercion filter.
123 * @param variables The variable map
124 * @param namespaces The scope namespaces.
125 */
126 public XalanXPathExpression(final String query, final Filter<T> filter,
127 final Map<String, Object> variables, final Namespace[] namespaces) {
128 super(query, filter, variables, namespaces);
129
130 // Create an object to resolve namespace prefixes.
131 // XPath namespaces are resolved from the input context node's document element
132 // if it is a root node, or else the current context node (for lack of a better
133 // resolution space, given the simplicity of this sample code).
134
135 // Create the XPath object.
136 try {
137 xpath = new XPath(query, null, this, XPath.SELECT, null);
138 } catch (TransformerException e) {
139 throw new IllegalArgumentException("Unable to parse: " + query, e);
140 }
141
142 }
143
144 private final Node wrap(Object context) {
145 if (context == null) {
146 return DOM.wrap(new Document(), false);
147 }
148 if (context instanceof Document) {
149 return DOM.wrap((Document)context);
150 }
151 if (context instanceof Content) {
152 switch (((Content)context).getCType()) {
153 case CDATA:
154 return DOM.wrap((CDATA)context);
155 case Comment:
156 return DOM.wrap((Comment)context);
157 case DocType:
158 return DOM.wrap((DocType)context);
159 case Element:
160 return DOM.wrap((Element)context);
161 case EntityRef:
162 return DOM.wrap((EntityRef)context);
163 case ProcessingInstruction:
164 return DOM.wrap((ProcessingInstruction)context);
165 case Text:
166 return DOM.wrap((Text)context);
167 }
168 }
169 if (context instanceof Attribute) {
170 return DOM.wrap((Attribute)context);
171 }
172 throw new IllegalArgumentException("Unable to wrap context: " + context);
173 }
174
175 @Override
176 protected List<?> evaluateRawAll(Object context) {
177
178 // Execute the XPath, and have it return the result
179 // return xpath.execute(xpathSupport, contextNode, prefixResolver);
180 final XPathContext xpathSupport = new XPathContext(false);
181 xpathSupport.setVarStack(variables);
182
183 final Node contextNode = wrap(context);
184 final int ctxtNode = xpathSupport.getDTMHandleFromNode(contextNode);
185
186 try {
187 final XObject xo = xpath.execute(xpathSupport, ctxtNode, this);
188 ArrayList<Object> ret = new ArrayList<Object>();
189 if (xo instanceof NodeSequence) {
190 final NodeList nl = ((NodeSequence)xo).nodelist();
191 final int len = nl.getLength();
192 for (int i = 0; i < len; i++) {
193 Node n = nl.item(i);
194 if (n instanceof Wrapper) {
195 ret.add(((Wrapper)n).getWrapped());
196 } else if (n instanceof Attr) {
197 // probably a Namespace in the form of an Attr.
198 final Attr nsa = (Attr)n;
199 if ("xmlns".equals(nsa.getLocalName())) {
200 ret.add(Namespace.getNamespace(nsa.getValue()));
201 } else if (nsa.getName().startsWith("xmlns")) {
202 ret.add(Namespace.getNamespace(
203 nsa.getLocalName(), nsa.getValue()));
204 } else {
205 throw new IllegalStateException(
206 "Unexpected Attribute " + nsa.getName() +
207 "=\"" + nsa.getValue() + "\"");
208 }
209 } else {
210 throw new IllegalStateException(
211 "Unexpected Node " + n.getNodeName());
212 }
213 }
214 } else {
215 ret.add(xo.object());
216 }
217
218 return ret;
219 } catch (TransformerException te) {
220 throw new IllegalArgumentException("Unable to process xpath.", te);
221 }
222 }
223
224 @Override
225 protected Object evaluateRawFirst(Object context) {
226 List<?> raw = evaluateRawAll(context);
227 if (raw.isEmpty()) {
228 return null;
229 }
230 return raw.get(0);
231 }
232
233
234 @Override
235 public String getNamespaceForPrefix(String prefix) {
236 return getNamespace(prefix).getURI();
237 }
238
239 @Override
240 public String getNamespaceForPrefix(String prefix, Node context) {
241 if (context == null) {
242 return getNamespace(prefix).getPrefix();
243 }
244 if (prefix == null) {
245 prefix = "";
246 }
247 if (context instanceof Wrapper) {
248 Object o = ((Wrapper)context).getWrapped();
249 if ((o instanceof NamespaceAware)) {
250 for (Namespace ns : ((NamespaceAware)o).getNamespacesInScope()) {
251 if (ns.getPrefix().equals(prefix)) {
252 return ns.getURI();
253 }
254 }
255 }
256 }
257 return null;
258 }
259
260 @Override
261 public String getBaseIdentifier() {
262 return null;
263 }
264
265 @Override
266 public boolean handlesNullPrefixes() {
267 return false;
268 }
269
270
271 }
0 /*--
1
2 Copyright (C) 2011-2014 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.contrib.xpath.xalan;
55
56 import java.util.Map;
57
58 import org.jdom.Namespace;
59 import org.jdom.filter2.Filter;
60 import org.jdom.xpath.XPathExpression;
61
62 /**
63 * An XPathFactory that wraps the JDOM content in a thin DOM layer, and then
64 * uses that to seed the Xalan API for XPath processing.
65 * @author Rolf Lear
66 *
67 */
68 public class XalanXPathFactory extends org.jdom.xpath.XPathFactory {
69
70 @Override
71 public <T> XPathExpression<T> compile(String expression, Filter<T> filter,
72 Map<String, Object> variables, Namespace... namespaces) {
73 // Java XPath factories are not thread safe... use a thread-local.
74 return new XalanXPathExpression<T>(
75 expression, filter, variables, namespaces);
76 }
77
78 }
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!ELEMENT root (#PCDATA)>
2 <!ATTLIST root
3 test CDATA #IMPLIED
4 def CDATA "defval" >
5
0 <?xml version="1.0" ?>
1 <!DOCTYPE root SYSTEM "DTDAttributeDefault.dtd" >
2
3 <root test="boo" />
0 <?xml version="1.0"?>
1 <!-- DOCTYPE play PUBLIC "-//Free Text Project//DTD Play//EN" -->
2
3 <PLAY>
4 <TITLE>The Tragedy of Hamlet, Prince of Denmark</TITLE>
5
6 <fm>
7 <p>Text placed in the public domain by Moby Lexical Tools, 1992.</p>
8 <p>SGML markup by Jon Bosak, 1992-1994.</p>
9 <p>XML version by Jon Bosak, 1996-1997.</p>
10 <p>This work may be freely copied and distributed worldwide.</p>
11 </fm>
12
13
14 <PERSONAE>
15 <TITLE>Dramatis Personae</TITLE>
16
17 <PERSONA>CLAUDIUS, king of Denmark. </PERSONA>
18 <PERSONA>HAMLET, son to the late, and nephew to the present king.</PERSONA>
19 <PERSONA>POLONIUS, lord chamberlain. </PERSONA>
20 <PERSONA>HORATIO, friend to Hamlet.</PERSONA>
21 <PERSONA>LAERTES, son to Polonius.</PERSONA>
22 <PERSONA>LUCIANUS, nephew to the king.</PERSONA>
23
24 <PGROUP>
25 <PERSONA>VOLTIMAND</PERSONA>
26 <PERSONA>CORNELIUS</PERSONA>
27 <PERSONA>ROSENCRANTZ</PERSONA>
28 <PERSONA>GUILDENSTERN</PERSONA>
29 <PERSONA>OSRIC</PERSONA>
30 <GRPDESCR>courtiers.</GRPDESCR>
31 </PGROUP>
32
33 <PERSONA>A Gentleman</PERSONA>
34 <PERSONA>A Priest. </PERSONA>
35
36 <PGROUP>
37 <PERSONA>MARCELLUS</PERSONA>
38 <PERSONA>BERNARDO</PERSONA>
39 <GRPDESCR>officers.</GRPDESCR>
40 </PGROUP>
41
42 <PERSONA>FRANCISCO, a soldier.</PERSONA>
43 <PERSONA>REYNALDO, servant to Polonius.</PERSONA>
44 <PERSONA>Players.</PERSONA>
45 <PERSONA>Two Clowns, grave-diggers.</PERSONA>
46 <PERSONA>FORTINBRAS, prince of Norway. </PERSONA>
47 <PERSONA>A Captain.</PERSONA>
48 <PERSONA>English Ambassadors. </PERSONA>
49 <PERSONA>GERTRUDE, queen of Denmark, and mother to Hamlet. </PERSONA>
50 <PERSONA>OPHELIA, daughter to Polonius.</PERSONA>
51 <PERSONA>Lords, Ladies, Officers, Soldiers, Sailors, Messengers, and other Attendants.</PERSONA>
52 <PERSONA>Ghost of Hamlet's Father. </PERSONA>
53 </PERSONAE>
54
55 <SCNDESCR>SCENE Denmark.</SCNDESCR>
56
57 <PLAYSUBT>HAMLET</PLAYSUBT>
58
59 <ACT><TITLE>ACT I</TITLE>
60
61 <SCENE><TITLE>SCENE I. Elsinore. A platform before the castle.</TITLE>
62 <STAGEDIR>FRANCISCO at his post. Enter to him BERNARDO</STAGEDIR>
63
64 <SPEECH>
65 <SPEAKER>BERNARDO</SPEAKER>
66 <LINE>Who's there?</LINE>
67 </SPEECH>
68
69 <SPEECH>
70 <SPEAKER>FRANCISCO</SPEAKER>
71 <LINE>Nay, answer me: stand, and unfold yourself.</LINE>
72 </SPEECH>
73
74 <SPEECH>
75 <SPEAKER>BERNARDO</SPEAKER>
76 <LINE>Long live the king!</LINE>
77 </SPEECH>
78
79 <SPEECH>
80 <SPEAKER>FRANCISCO</SPEAKER>
81 <LINE>Bernardo?</LINE>
82 </SPEECH>
83
84 <SPEECH>
85 <SPEAKER>BERNARDO</SPEAKER>
86 <LINE>He.</LINE>
87 </SPEECH>
88
89 <SPEECH>
90 <SPEAKER>FRANCISCO</SPEAKER>
91 <LINE>You come most carefully upon your hour.</LINE>
92 </SPEECH>
93
94 <SPEECH>
95 <SPEAKER>BERNARDO</SPEAKER>
96 <LINE>'Tis now struck twelve; get thee to bed, Francisco.</LINE>
97 </SPEECH>
98
99 <SPEECH>
100 <SPEAKER>FRANCISCO</SPEAKER>
101 <LINE>For this relief much thanks: 'tis bitter cold,</LINE>
102 <LINE>And I am sick at heart.</LINE>
103 </SPEECH>
104
105 <SPEECH>
106 <SPEAKER>BERNARDO</SPEAKER>
107 <LINE>Have you had quiet guard?</LINE>
108 </SPEECH>
109
110 <SPEECH>
111 <SPEAKER>FRANCISCO</SPEAKER>
112 <LINE>Not a mouse stirring.</LINE>
113 </SPEECH>
114
115 <SPEECH>
116 <SPEAKER>BERNARDO</SPEAKER>
117 <LINE>Well, good night.</LINE>
118 <LINE>If you do meet Horatio and Marcellus,</LINE>
119 <LINE>The rivals of my watch, bid them make haste.</LINE>
120 </SPEECH>
121
122 <SPEECH>
123 <SPEAKER>FRANCISCO</SPEAKER>
124 <LINE>I think I hear them. Stand, ho! Who's there?</LINE>
125 </SPEECH>
126
127
128 <STAGEDIR>Enter HORATIO and MARCELLUS</STAGEDIR>
129
130 <SPEECH>
131 <SPEAKER>HORATIO</SPEAKER>
132 <LINE>Friends to this ground.</LINE>
133 </SPEECH>
134
135 <SPEECH>
136 <SPEAKER>MARCELLUS</SPEAKER>
137 <LINE>And liegemen to the Dane.</LINE>
138 </SPEECH>
139
140 <SPEECH>
141 <SPEAKER>FRANCISCO</SPEAKER>
142 <LINE>Give you good night.</LINE>
143 </SPEECH>
144
145 <SPEECH>
146 <SPEAKER>MARCELLUS</SPEAKER>
147 <LINE>O, farewell, honest soldier:</LINE>
148 <LINE>Who hath relieved you?</LINE>
149 </SPEECH>
150
151 <SPEECH>
152 <SPEAKER>FRANCISCO</SPEAKER>
153 <LINE>Bernardo has my place.</LINE>
154 <LINE>Give you good night.</LINE>
155 </SPEECH>
156
157
158 <STAGEDIR>Exit</STAGEDIR>
159
160 <SPEECH>
161 <SPEAKER>MARCELLUS</SPEAKER>
162 <LINE>Holla! Bernardo!</LINE>
163 </SPEECH>
164
165 <SPEECH>
166 <SPEAKER>BERNARDO</SPEAKER>
167 <LINE>Say,</LINE>
168 <LINE>What, is Horatio there?</LINE>
169 </SPEECH>
170
171 <SPEECH>
172 <SPEAKER>HORATIO</SPEAKER>
173 <LINE>A piece of him.</LINE>
174 </SPEECH>
175
176 <SPEECH>
177 <SPEAKER>BERNARDO</SPEAKER>
178 <LINE>Welcome, Horatio: welcome, good Marcellus.</LINE>
179 </SPEECH>
180
181 <SPEECH>
182 <SPEAKER>MARCELLUS</SPEAKER>
183 <LINE>What, has this thing appear'd again to-night?</LINE>
184 </SPEECH>
185
186 <SPEECH>
187 <SPEAKER>BERNARDO</SPEAKER>
188 <LINE>I have seen nothing.</LINE>
189 </SPEECH>
190
191 <SPEECH>
192 <SPEAKER>MARCELLUS</SPEAKER>
193 <LINE>Horatio says 'tis but our fantasy,</LINE>
194 <LINE>And will not let belief take hold of him</LINE>
195 <LINE>Touching this dreaded sight, twice seen of us:</LINE>
196 <LINE>Therefore I have entreated him along</LINE>
197 <LINE>With us to watch the minutes of this night;</LINE>
198 <LINE>That if again this apparition come,</LINE>
199 <LINE>He may approve our eyes and speak to it.</LINE>
200 </SPEECH>
201
202 <SPEECH>
203 <SPEAKER>HORATIO</SPEAKER>
204 <LINE>Tush, tush, 'twill not appear.</LINE>
205 </SPEECH>
206
207 <SPEECH>
208 <SPEAKER>BERNARDO</SPEAKER>
209 <LINE>Sit down awhile;</LINE>
210 <LINE>And let us once again assail your ears,</LINE>
211 <LINE>That are so fortified against our story</LINE>
212 <LINE>What we have two nights seen.</LINE>
213 </SPEECH>
214
215 <SPEECH>
216 <SPEAKER>HORATIO</SPEAKER>
217 <LINE>Well, sit we down,</LINE>
218 <LINE>And let us hear Bernardo speak of this.</LINE>
219 </SPEECH>
220
221 <SPEECH>
222 <SPEAKER>BERNARDO</SPEAKER>
223 <LINE>Last night of all,</LINE>
224 <LINE>When yond same star that's westward from the pole</LINE>
225 <LINE>Had made his course to illume that part of heaven</LINE>
226 <LINE>Where now it burns, Marcellus and myself,</LINE>
227 <LINE>The bell then beating one,--</LINE>
228 </SPEECH>
229
230
231 <STAGEDIR>Enter Ghost</STAGEDIR>
232
233 <SPEECH>
234 <SPEAKER>MARCELLUS</SPEAKER>
235 <LINE>Peace, break thee off; look, where it comes again!</LINE>
236 </SPEECH>
237
238 <SPEECH>
239 <SPEAKER>BERNARDO</SPEAKER>
240 <LINE>In the same figure, like the king that's dead.</LINE>
241 </SPEECH>
242
243 <SPEECH>
244 <SPEAKER>MARCELLUS</SPEAKER>
245 <LINE>Thou art a scholar; speak to it, Horatio.</LINE>
246 </SPEECH>
247
248 <SPEECH>
249 <SPEAKER>BERNARDO</SPEAKER>
250 <LINE>Looks it not like the king? mark it, Horatio.</LINE>
251 </SPEECH>
252
253 <SPEECH>
254 <SPEAKER>HORATIO</SPEAKER>
255 <LINE>Most like: it harrows me with fear and wonder.</LINE>
256 </SPEECH>
257
258 <SPEECH>
259 <SPEAKER>BERNARDO</SPEAKER>
260 <LINE>It would be spoke to.</LINE>
261 </SPEECH>
262
263 <SPEECH>
264 <SPEAKER>MARCELLUS</SPEAKER>
265 <LINE>Question it, Horatio.</LINE>
266 </SPEECH>
267
268 <SPEECH>
269 <SPEAKER>HORATIO</SPEAKER>
270 <LINE>What art thou that usurp'st this time of night,</LINE>
271 <LINE>Together with that fair and warlike form</LINE>
272 <LINE>In which the majesty of buried Denmark</LINE>
273 <LINE>Did sometimes march? by heaven I charge thee, speak!</LINE>
274 </SPEECH>
275
276 <SPEECH>
277 <SPEAKER>MARCELLUS</SPEAKER>
278 <LINE>It is offended.</LINE>
279 </SPEECH>
280
281 <SPEECH>
282 <SPEAKER>BERNARDO</SPEAKER>
283 <LINE>See, it stalks away!</LINE>
284 </SPEECH>
285
286 <SPEECH>
287 <SPEAKER>HORATIO</SPEAKER>
288 <LINE>Stay! speak, speak! I charge thee, speak!</LINE>
289 </SPEECH>
290
291
292 <STAGEDIR>Exit Ghost</STAGEDIR>
293
294 <SPEECH>
295 <SPEAKER>MARCELLUS</SPEAKER>
296 <LINE>'Tis gone, and will not answer.</LINE>
297 </SPEECH>
298
299 <SPEECH>
300 <SPEAKER>BERNARDO</SPEAKER>
301 <LINE>How now, Horatio! you tremble and look pale:</LINE>
302 <LINE>Is not this something more than fantasy?</LINE>
303 <LINE>What think you on't?</LINE>
304 </SPEECH>
305
306 <SPEECH>
307 <SPEAKER>HORATIO</SPEAKER>
308 <LINE>Before my God, I might not this believe</LINE>
309 <LINE>Without the sensible and true avouch</LINE>
310 <LINE>Of mine own eyes.</LINE>
311 </SPEECH>
312
313 <SPEECH>
314 <SPEAKER>MARCELLUS</SPEAKER>
315 <LINE>Is it not like the king?</LINE>
316 </SPEECH>
317
318 <SPEECH>
319 <SPEAKER>HORATIO</SPEAKER>
320 <LINE>As thou art to thyself:</LINE>
321 <LINE>Such was the very armour he had on</LINE>
322 <LINE>When he the ambitious Norway combated;</LINE>
323 <LINE>So frown'd he once, when, in an angry parle,</LINE>
324 <LINE>He smote the sledded Polacks on the ice.</LINE>
325 <LINE>'Tis strange.</LINE>
326 </SPEECH>
327
328 <SPEECH>
329 <SPEAKER>MARCELLUS</SPEAKER>
330 <LINE>Thus twice before, and jump at this dead hour,</LINE>
331 <LINE>With martial stalk hath he gone by our watch.</LINE>
332 </SPEECH>
333
334 <SPEECH>
335 <SPEAKER>HORATIO</SPEAKER>
336 <LINE>In what particular thought to work I know not;</LINE>
337 <LINE>But in the gross and scope of my opinion,</LINE>
338 <LINE>This bodes some strange eruption to our state.</LINE>
339 </SPEECH>
340
341 <SPEECH>
342 <SPEAKER>MARCELLUS</SPEAKER>
343 <LINE>Good now, sit down, and tell me, he that knows,</LINE>
344 <LINE>Why this same strict and most observant watch</LINE>
345 <LINE>So nightly toils the subject of the land,</LINE>
346 <LINE>And why such daily cast of brazen cannon,</LINE>
347 <LINE>And foreign mart for implements of war;</LINE>
348 <LINE>Why such impress of shipwrights, whose sore task</LINE>
349 <LINE>Does not divide the Sunday from the week;</LINE>
350 <LINE>What might be toward, that this sweaty haste</LINE>
351 <LINE>Doth make the night joint-labourer with the day:</LINE>
352 <LINE>Who is't that can inform me?</LINE>
353 </SPEECH>
354
355 <SPEECH>
356 <SPEAKER>HORATIO</SPEAKER>
357 <LINE>That can I;</LINE>
358 <LINE>At least, the whisper goes so. Our last king,</LINE>
359 <LINE>Whose image even but now appear'd to us,</LINE>
360 <LINE>Was, as you know, by Fortinbras of Norway,</LINE>
361 <LINE>Thereto prick'd on by a most emulate pride,</LINE>
362 <LINE>Dared to the combat; in which our valiant Hamlet--</LINE>
363 <LINE>For so this side of our known world esteem'd him--</LINE>
364 <LINE>Did slay this Fortinbras; who by a seal'd compact,</LINE>
365 <LINE>Well ratified by law and heraldry,</LINE>
366 <LINE>Did forfeit, with his life, all those his lands</LINE>
367 <LINE>Which he stood seized of, to the conqueror:</LINE>
368 <LINE>Against the which, a moiety competent</LINE>
369 <LINE>Was gaged by our king; which had return'd</LINE>
370 <LINE>To the inheritance of Fortinbras,</LINE>
371 <LINE>Had he been vanquisher; as, by the same covenant,</LINE>
372 <LINE>And carriage of the article design'd,</LINE>
373 <LINE>His fell to Hamlet. Now, sir, young Fortinbras,</LINE>
374 <LINE>Of unimproved mettle hot and full,</LINE>
375 <LINE>Hath in the skirts of Norway here and there</LINE>
376 <LINE>Shark'd up a list of lawless resolutes,</LINE>
377 <LINE>For food and diet, to some enterprise</LINE>
378 <LINE>That hath a stomach in't; which is no other--</LINE>
379 <LINE>As it doth well appear unto our state--</LINE>
380 <LINE>But to recover of us, by strong hand</LINE>
381 <LINE>And terms compulsatory, those foresaid lands</LINE>
382 <LINE>So by his father lost: and this, I take it,</LINE>
383 <LINE>Is the main motive of our preparations,</LINE>
384 <LINE>The source of this our watch and the chief head</LINE>
385 <LINE>Of this post-haste and romage in the land.</LINE>
386 </SPEECH>
387
388 <SPEECH>
389 <SPEAKER>BERNARDO</SPEAKER>
390 <LINE>I think it be no other but e'en so:</LINE>
391 <LINE>Well may it sort that this portentous figure</LINE>
392 <LINE>Comes armed through our watch; so like the king</LINE>
393 <LINE>That was and is the question of these wars.</LINE>
394 </SPEECH>
395
396 <SPEECH>
397 <SPEAKER>HORATIO</SPEAKER>
398 <LINE>A mote it is to trouble the mind's eye.</LINE>
399 <LINE>In the most high and palmy state of Rome,</LINE>
400 <LINE>A little ere the mightiest Julius fell,</LINE>
401 <LINE>The graves stood tenantless and the sheeted dead</LINE>
402 <LINE>Did squeak and gibber in the Roman streets:</LINE>
403 <LINE>As stars with trains of fire and dews of blood,</LINE>
404 <LINE>Disasters in the sun; and the moist star</LINE>
405 <LINE>Upon whose influence Neptune's empire stands</LINE>
406 <LINE>Was sick almost to doomsday with eclipse:</LINE>
407 <LINE>And even the like precurse of fierce events,</LINE>
408 <LINE>As harbingers preceding still the fates</LINE>
409 <LINE>And prologue to the omen coming on,</LINE>
410 <LINE>Have heaven and earth together demonstrated</LINE>
411 <LINE>Unto our climatures and countrymen.--</LINE>
412 <LINE>But soft, behold! lo, where it comes again!</LINE>
413 <STAGEDIR>Re-enter Ghost</STAGEDIR>
414 <LINE>I'll cross it, though it blast me. Stay, illusion!</LINE>
415 <LINE>If thou hast any sound, or use of voice,</LINE>
416 <LINE>Speak to me:</LINE>
417 <LINE>If there be any good thing to be done,</LINE>
418 <LINE>That may to thee do ease and grace to me,</LINE>
419 <LINE>Speak to me:</LINE>
420 <STAGEDIR>Cock crows</STAGEDIR>
421 <LINE>If thou art privy to thy country's fate,</LINE>
422 <LINE>Which, happily, foreknowing may avoid, O, speak!</LINE>
423 <LINE>Or if thou hast uphoarded in thy life</LINE>
424 <LINE>Extorted treasure in the womb of earth,</LINE>
425 <LINE>For which, they say, you spirits oft walk in death,</LINE>
426 <LINE>Speak of it: stay, and speak! Stop it, Marcellus.</LINE>
427 </SPEECH>
428
429 <SPEECH>
430 <SPEAKER>MARCELLUS</SPEAKER>
431 <LINE>Shall I strike at it with my partisan?</LINE>
432 </SPEECH>
433
434 <SPEECH>
435 <SPEAKER>HORATIO</SPEAKER>
436 <LINE>Do, if it will not stand.</LINE>
437 </SPEECH>
438
439 <SPEECH>
440 <SPEAKER>BERNARDO</SPEAKER>
441 <LINE>'Tis here!</LINE>
442 </SPEECH>
443
444 <SPEECH>
445 <SPEAKER>HORATIO</SPEAKER>
446 <LINE>'Tis here!</LINE>
447 </SPEECH>
448
449 <SPEECH>
450 <SPEAKER>MARCELLUS</SPEAKER>
451 <LINE>'Tis gone!</LINE>
452 <STAGEDIR>Exit Ghost</STAGEDIR>
453 <LINE>We do it wrong, being so majestical,</LINE>
454 <LINE>To offer it the show of violence;</LINE>
455 <LINE>For it is, as the air, invulnerable,</LINE>
456 <LINE>And our vain blows malicious mockery.</LINE>
457 </SPEECH>
458
459 <SPEECH>
460 <SPEAKER>BERNARDO</SPEAKER>
461 <LINE>It was about to speak, when the cock crew.</LINE>
462 </SPEECH>
463
464 <SPEECH>
465 <SPEAKER>HORATIO</SPEAKER>
466 <LINE>And then it started like a guilty thing</LINE>
467 <LINE>Upon a fearful summons. I have heard,</LINE>
468 <LINE>The cock, that is the trumpet to the morn,</LINE>
469 <LINE>Doth with his lofty and shrill-sounding throat</LINE>
470 <LINE>Awake the god of day; and, at his warning,</LINE>
471 <LINE>Whether in sea or fire, in earth or air,</LINE>
472 <LINE>The extravagant and erring spirit hies</LINE>
473 <LINE>To his confine: and of the truth herein</LINE>
474 <LINE>This present object made probation.</LINE>
475 </SPEECH>
476
477 <SPEECH>
478 <SPEAKER>MARCELLUS</SPEAKER>
479 <LINE>It faded on the crowing of the cock.</LINE>
480 <LINE>Some say that ever 'gainst that season comes</LINE>
481 <LINE>Wherein our Saviour's birth is celebrated,</LINE>
482 <LINE>The bird of dawning singeth all night long:</LINE>
483 <LINE>And then, they say, no spirit dares stir abroad;</LINE>
484 <LINE>The nights are wholesome; then no planets strike,</LINE>
485 <LINE>No fairy takes, nor witch hath power to charm,</LINE>
486 <LINE>So hallow'd and so gracious is the time.</LINE>
487 </SPEECH>
488
489 <SPEECH>
490 <SPEAKER>HORATIO</SPEAKER>
491 <LINE>So have I heard and do in part believe it.</LINE>
492 <LINE>But, look, the morn, in russet mantle clad,</LINE>
493 <LINE>Walks o'er the dew of yon high eastward hill:</LINE>
494 <LINE>Break we our watch up; and by my advice,</LINE>
495 <LINE>Let us impart what we have seen to-night</LINE>
496 <LINE>Unto young Hamlet; for, upon my life,</LINE>
497 <LINE>This spirit, dumb to us, will speak to him.</LINE>
498 <LINE>Do you consent we shall acquaint him with it,</LINE>
499 <LINE>As needful in our loves, fitting our duty?</LINE>
500 </SPEECH>
501
502 <SPEECH>
503 <SPEAKER>MARCELLUS</SPEAKER>
504 <LINE>Let's do't, I pray; and I this morning know</LINE>
505 <LINE>Where we shall find him most conveniently.</LINE>
506 </SPEECH>
507
508
509 <STAGEDIR>Exeunt</STAGEDIR>
510 </SCENE>
511
512 <SCENE><TITLE>SCENE II. A room of state in the castle.</TITLE>
513 <STAGEDIR>Enter KING CLAUDIUS, QUEEN GERTRUDE, HAMLET,
514 POLONIUS, LAERTES, VOLTIMAND, CORNELIUS, Lords,
515 and Attendants</STAGEDIR>
516
517 <SPEECH>
518 <SPEAKER>KING CLAUDIUS</SPEAKER>
519 <LINE>Though yet of Hamlet our dear brother's death</LINE>
520 <LINE>The memory be green, and that it us befitted</LINE>
521 <LINE>To bear our hearts in grief and our whole kingdom</LINE>
522 <LINE>To be contracted in one brow of woe,</LINE>
523 <LINE>Yet so far hath discretion fought with nature</LINE>
524 <LINE>That we with wisest sorrow think on him,</LINE>
525 <LINE>Together with remembrance of ourselves.</LINE>
526 <LINE>Therefore our sometime sister, now our queen,</LINE>
527 <LINE>The imperial jointress to this warlike state,</LINE>
528 <LINE>Have we, as 'twere with a defeated joy,--</LINE>
529 <LINE>With an auspicious and a dropping eye,</LINE>
530 <LINE>With mirth in funeral and with dirge in marriage,</LINE>
531 <LINE>In equal scale weighing delight and dole,--</LINE>
532 <LINE>Taken to wife: nor have we herein barr'd</LINE>
533 <LINE>Your better wisdoms, which have freely gone</LINE>
534 <LINE>With this affair along. For all, our thanks.</LINE>
535 <LINE>Now follows, that you know, young Fortinbras,</LINE>
536 <LINE>Holding a weak supposal of our worth,</LINE>
537 <LINE>Or thinking by our late dear brother's death</LINE>
538 <LINE>Our state to be disjoint and out of frame,</LINE>
539 <LINE>Colleagued with the dream of his advantage,</LINE>
540 <LINE>He hath not fail'd to pester us with message,</LINE>
541 <LINE>Importing the surrender of those lands</LINE>
542 <LINE>Lost by his father, with all bonds of law,</LINE>
543 <LINE>To our most valiant brother. So much for him.</LINE>
544 <LINE>Now for ourself and for this time of meeting:</LINE>
545 <LINE>Thus much the business is: we have here writ</LINE>
546 <LINE>To Norway, uncle of young Fortinbras,--</LINE>
547 <LINE>Who, impotent and bed-rid, scarcely hears</LINE>
548 <LINE>Of this his nephew's purpose,--to suppress</LINE>
549 <LINE>His further gait herein; in that the levies,</LINE>
550 <LINE>The lists and full proportions, are all made</LINE>
551 <LINE>Out of his subject: and we here dispatch</LINE>
552 <LINE>You, good Cornelius, and you, Voltimand,</LINE>
553 <LINE>For bearers of this greeting to old Norway;</LINE>
554 <LINE>Giving to you no further personal power</LINE>
555 <LINE>To business with the king, more than the scope</LINE>
556 <LINE>Of these delated articles allow.</LINE>
557 <LINE>Farewell, and let your haste commend your duty.</LINE>
558 </SPEECH>
559
560 <SPEECH>
561 <SPEAKER>CORNELIUS</SPEAKER>
562 <SPEAKER>VOLTIMAND</SPEAKER>
563 <LINE>In that and all things will we show our duty.</LINE>
564 </SPEECH>
565
566 <SPEECH>
567 <SPEAKER>KING CLAUDIUS</SPEAKER>
568 <LINE>We doubt it nothing: heartily farewell.</LINE>
569 <STAGEDIR>Exeunt VOLTIMAND and CORNELIUS</STAGEDIR>
570 <LINE>And now, Laertes, what's the news with you?</LINE>
571 <LINE>You told us of some suit; what is't, Laertes?</LINE>
572 <LINE>You cannot speak of reason to the Dane,</LINE>
573 <LINE>And loose your voice: what wouldst thou beg, Laertes,</LINE>
574 <LINE>That shall not be my offer, not thy asking?</LINE>
575 <LINE>The head is not more native to the heart,</LINE>
576 <LINE>The hand more instrumental to the mouth,</LINE>
577 <LINE>Than is the throne of Denmark to thy father.</LINE>
578 <LINE>What wouldst thou have, Laertes?</LINE>
579 </SPEECH>
580
581 <SPEECH>
582 <SPEAKER>LAERTES</SPEAKER>
583 <LINE>My dread lord,</LINE>
584 <LINE>Your leave and favour to return to France;</LINE>
585 <LINE>From whence though willingly I came to Denmark,</LINE>
586 <LINE>To show my duty in your coronation,</LINE>
587 <LINE>Yet now, I must confess, that duty done,</LINE>
588 <LINE>My thoughts and wishes bend again toward France</LINE>
589 <LINE>And bow them to your gracious leave and pardon.</LINE>
590 </SPEECH>
591
592 <SPEECH>
593 <SPEAKER>KING CLAUDIUS</SPEAKER>
594 <LINE>Have you your father's leave? What says Polonius?</LINE>
595 </SPEECH>
596
597 <SPEECH>
598 <SPEAKER>LORD POLONIUS</SPEAKER>
599 <LINE>He hath, my lord, wrung from me my slow leave</LINE>
600 <LINE>By laboursome petition, and at last</LINE>
601 <LINE>Upon his will I seal'd my hard consent:</LINE>
602 <LINE>I do beseech you, give him leave to go.</LINE>
603 </SPEECH>
604
605 <SPEECH>
606 <SPEAKER>KING CLAUDIUS</SPEAKER>
607 <LINE>Take thy fair hour, Laertes; time be thine,</LINE>
608 <LINE>And thy best graces spend it at thy will!</LINE>
609 <LINE>But now, my cousin Hamlet, and my son,--</LINE>
610 </SPEECH>
611
612 <SPEECH>
613 <SPEAKER>HAMLET</SPEAKER>
614 <LINE><STAGEDIR>Aside</STAGEDIR> A little more than kin, and less than kind.</LINE>
615 </SPEECH>
616
617 <SPEECH>
618 <SPEAKER>KING CLAUDIUS</SPEAKER>
619 <LINE>How is it that the clouds still hang on you?</LINE>
620 </SPEECH>
621
622 <SPEECH>
623 <SPEAKER>HAMLET</SPEAKER>
624 <LINE>Not so, my lord; I am too much i' the sun.</LINE>
625 </SPEECH>
626
627 <SPEECH>
628 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
629 <LINE>Good Hamlet, cast thy nighted colour off,</LINE>
630 <LINE>And let thine eye look like a friend on Denmark.</LINE>
631 <LINE>Do not for ever with thy vailed lids</LINE>
632 <LINE>Seek for thy noble father in the dust:</LINE>
633 <LINE>Thou know'st 'tis common; all that lives must die,</LINE>
634 <LINE>Passing through nature to eternity.</LINE>
635 </SPEECH>
636
637 <SPEECH>
638 <SPEAKER>HAMLET</SPEAKER>
639 <LINE>Ay, madam, it is common.</LINE>
640 </SPEECH>
641
642 <SPEECH>
643 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
644 <LINE>If it be,</LINE>
645 <LINE>Why seems it so particular with thee?</LINE>
646 </SPEECH>
647
648 <SPEECH>
649 <SPEAKER>HAMLET</SPEAKER>
650 <LINE>Seems, madam! nay it is; I know not 'seems.'</LINE>
651 <LINE>'Tis not alone my inky cloak, good mother,</LINE>
652 <LINE>Nor customary suits of solemn black,</LINE>
653 <LINE>Nor windy suspiration of forced breath,</LINE>
654 <LINE>No, nor the fruitful river in the eye,</LINE>
655 <LINE>Nor the dejected 'havior of the visage,</LINE>
656 <LINE>Together with all forms, moods, shapes of grief,</LINE>
657 <LINE>That can denote me truly: these indeed seem,</LINE>
658 <LINE>For they are actions that a man might play:</LINE>
659 <LINE>But I have that within which passeth show;</LINE>
660 <LINE>These but the trappings and the suits of woe.</LINE>
661 </SPEECH>
662
663 <SPEECH>
664 <SPEAKER>KING CLAUDIUS</SPEAKER>
665 <LINE>'Tis sweet and commendable in your nature, Hamlet,</LINE>
666 <LINE>To give these mourning duties to your father:</LINE>
667 <LINE>But, you must know, your father lost a father;</LINE>
668 <LINE>That father lost, lost his, and the survivor bound</LINE>
669 <LINE>In filial obligation for some term</LINE>
670 <LINE>To do obsequious sorrow: but to persever</LINE>
671 <LINE>In obstinate condolement is a course</LINE>
672 <LINE>Of impious stubbornness; 'tis unmanly grief;</LINE>
673 <LINE>It shows a will most incorrect to heaven,</LINE>
674 <LINE>A heart unfortified, a mind impatient,</LINE>
675 <LINE>An understanding simple and unschool'd:</LINE>
676 <LINE>For what we know must be and is as common</LINE>
677 <LINE>As any the most vulgar thing to sense,</LINE>
678 <LINE>Why should we in our peevish opposition</LINE>
679 <LINE>Take it to heart? Fie! 'tis a fault to heaven,</LINE>
680 <LINE>A fault against the dead, a fault to nature,</LINE>
681 <LINE>To reason most absurd: whose common theme</LINE>
682 <LINE>Is death of fathers, and who still hath cried,</LINE>
683 <LINE>From the first corse till he that died to-day,</LINE>
684 <LINE>'This must be so.' We pray you, throw to earth</LINE>
685 <LINE>This unprevailing woe, and think of us</LINE>
686 <LINE>As of a father: for let the world take note,</LINE>
687 <LINE>You are the most immediate to our throne;</LINE>
688 <LINE>And with no less nobility of love</LINE>
689 <LINE>Than that which dearest father bears his son,</LINE>
690 <LINE>Do I impart toward you. For your intent</LINE>
691 <LINE>In going back to school in Wittenberg,</LINE>
692 <LINE>It is most retrograde to our desire:</LINE>
693 <LINE>And we beseech you, bend you to remain</LINE>
694 <LINE>Here, in the cheer and comfort of our eye,</LINE>
695 <LINE>Our chiefest courtier, cousin, and our son.</LINE>
696 </SPEECH>
697
698 <SPEECH>
699 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
700 <LINE>Let not thy mother lose her prayers, Hamlet:</LINE>
701 <LINE>I pray thee, stay with us; go not to Wittenberg.</LINE>
702 </SPEECH>
703
704 <SPEECH>
705 <SPEAKER>HAMLET</SPEAKER>
706 <LINE>I shall in all my best obey you, madam.</LINE>
707 </SPEECH>
708
709 <SPEECH>
710 <SPEAKER>KING CLAUDIUS</SPEAKER>
711 <LINE>Why, 'tis a loving and a fair reply:</LINE>
712 <LINE>Be as ourself in Denmark. Madam, come;</LINE>
713 <LINE>This gentle and unforced accord of Hamlet</LINE>
714 <LINE>Sits smiling to my heart: in grace whereof,</LINE>
715 <LINE>No jocund health that Denmark drinks to-day,</LINE>
716 <LINE>But the great cannon to the clouds shall tell,</LINE>
717 <LINE>And the king's rouse the heavens all bruit again,</LINE>
718 <LINE>Re-speaking earthly thunder. Come away.</LINE>
719 </SPEECH>
720
721
722 <STAGEDIR>Exeunt all but HAMLET</STAGEDIR>
723
724 <SPEECH>
725 <SPEAKER>HAMLET</SPEAKER>
726 <LINE>O, that this too too solid flesh would melt</LINE>
727 <LINE>Thaw and resolve itself into a dew!</LINE>
728 <LINE>Or that the Everlasting had not fix'd</LINE>
729 <LINE>His canon 'gainst self-slaughter! O God! God!</LINE>
730 <LINE>How weary, stale, flat and unprofitable,</LINE>
731 <LINE>Seem to me all the uses of this world!</LINE>
732 <LINE>Fie on't! ah fie! 'tis an unweeded garden,</LINE>
733 <LINE>That grows to seed; things rank and gross in nature</LINE>
734 <LINE>Possess it merely. That it should come to this!</LINE>
735 <LINE>But two months dead: nay, not so much, not two:</LINE>
736 <LINE>So excellent a king; that was, to this,</LINE>
737 <LINE>Hyperion to a satyr; so loving to my mother</LINE>
738 <LINE>That he might not beteem the winds of heaven</LINE>
739 <LINE>Visit her face too roughly. Heaven and earth!</LINE>
740 <LINE>Must I remember? why, she would hang on him,</LINE>
741 <LINE>As if increase of appetite had grown</LINE>
742 <LINE>By what it fed on: and yet, within a month--</LINE>
743 <LINE>Let me not think on't--Frailty, thy name is woman!--</LINE>
744 <LINE>A little month, or ere those shoes were old</LINE>
745 <LINE>With which she follow'd my poor father's body,</LINE>
746 <LINE>Like Niobe, all tears:--why she, even she--</LINE>
747 <LINE>O, God! a beast, that wants discourse of reason,</LINE>
748 <LINE>Would have mourn'd longer--married with my uncle,</LINE>
749 <LINE>My father's brother, but no more like my father</LINE>
750 <LINE>Than I to Hercules: within a month:</LINE>
751 <LINE>Ere yet the salt of most unrighteous tears</LINE>
752 <LINE>Had left the flushing in her galled eyes,</LINE>
753 <LINE>She married. O, most wicked speed, to post</LINE>
754 <LINE>With such dexterity to incestuous sheets!</LINE>
755 <LINE>It is not nor it cannot come to good:</LINE>
756 <LINE>But break, my heart; for I must hold my tongue.</LINE>
757 </SPEECH>
758
759
760 <STAGEDIR>Enter HORATIO, MARCELLUS, and BERNARDO</STAGEDIR>
761
762 <SPEECH>
763 <SPEAKER>HORATIO</SPEAKER>
764 <LINE>Hail to your lordship!</LINE>
765 </SPEECH>
766
767 <SPEECH>
768 <SPEAKER>HAMLET</SPEAKER>
769 <LINE>I am glad to see you well:</LINE>
770 <LINE>Horatio,--or I do forget myself.</LINE>
771 </SPEECH>
772
773 <SPEECH>
774 <SPEAKER>HORATIO</SPEAKER>
775 <LINE>The same, my lord, and your poor servant ever.</LINE>
776 </SPEECH>
777
778 <SPEECH>
779 <SPEAKER>HAMLET</SPEAKER>
780 <LINE>Sir, my good friend; I'll change that name with you:</LINE>
781 <LINE>And what make you from Wittenberg, Horatio? Marcellus?</LINE>
782 </SPEECH>
783
784 <SPEECH>
785 <SPEAKER>MARCELLUS</SPEAKER>
786 <LINE>My good lord--</LINE>
787 </SPEECH>
788
789 <SPEECH>
790 <SPEAKER>HAMLET</SPEAKER>
791 <LINE>I am very glad to see you. Good even, sir.</LINE>
792 <LINE>But what, in faith, make you from Wittenberg?</LINE>
793 </SPEECH>
794
795 <SPEECH>
796 <SPEAKER>HORATIO</SPEAKER>
797 <LINE>A truant disposition, good my lord.</LINE>
798 </SPEECH>
799
800 <SPEECH>
801 <SPEAKER>HAMLET</SPEAKER>
802 <LINE>I would not hear your enemy say so,</LINE>
803 <LINE>Nor shall you do mine ear that violence,</LINE>
804 <LINE>To make it truster of your own report</LINE>
805 <LINE>Against yourself: I know you are no truant.</LINE>
806 <LINE>But what is your affair in Elsinore?</LINE>
807 <LINE>We'll teach you to drink deep ere you depart.</LINE>
808 </SPEECH>
809
810 <SPEECH>
811 <SPEAKER>HORATIO</SPEAKER>
812 <LINE>My lord, I came to see your father's funeral.</LINE>
813 </SPEECH>
814
815 <SPEECH>
816 <SPEAKER>HAMLET</SPEAKER>
817 <LINE>I pray thee, do not mock me, fellow-student;</LINE>
818 <LINE>I think it was to see my mother's wedding.</LINE>
819 </SPEECH>
820
821 <SPEECH>
822 <SPEAKER>HORATIO</SPEAKER>
823 <LINE>Indeed, my lord, it follow'd hard upon.</LINE>
824 </SPEECH>
825
826 <SPEECH>
827 <SPEAKER>HAMLET</SPEAKER>
828 <LINE>Thrift, thrift, Horatio! the funeral baked meats</LINE>
829 <LINE>Did coldly furnish forth the marriage tables.</LINE>
830 <LINE>Would I had met my dearest foe in heaven</LINE>
831 <LINE>Or ever I had seen that day, Horatio!</LINE>
832 <LINE>My father!--methinks I see my father.</LINE>
833 </SPEECH>
834
835 <SPEECH>
836 <SPEAKER>HORATIO</SPEAKER>
837 <LINE>Where, my lord?</LINE>
838 </SPEECH>
839
840 <SPEECH>
841 <SPEAKER>HAMLET</SPEAKER>
842 <LINE>In my mind's eye, Horatio.</LINE>
843 </SPEECH>
844
845 <SPEECH>
846 <SPEAKER>HORATIO</SPEAKER>
847 <LINE>I saw him once; he was a goodly king.</LINE>
848 </SPEECH>
849
850 <SPEECH>
851 <SPEAKER>HAMLET</SPEAKER>
852 <LINE>He was a man, take him for all in all,</LINE>
853 <LINE>I shall not look upon his like again.</LINE>
854 </SPEECH>
855
856 <SPEECH>
857 <SPEAKER>HORATIO</SPEAKER>
858 <LINE>My lord, I think I saw him yesternight.</LINE>
859 </SPEECH>
860
861 <SPEECH>
862 <SPEAKER>HAMLET</SPEAKER>
863 <LINE>Saw? who?</LINE>
864 </SPEECH>
865
866 <SPEECH>
867 <SPEAKER>HORATIO</SPEAKER>
868 <LINE>My lord, the king your father.</LINE>
869 </SPEECH>
870
871 <SPEECH>
872 <SPEAKER>HAMLET</SPEAKER>
873 <LINE>The king my father!</LINE>
874 </SPEECH>
875
876 <SPEECH>
877 <SPEAKER>HORATIO</SPEAKER>
878 <LINE>Season your admiration for awhile</LINE>
879 <LINE>With an attent ear, till I may deliver,</LINE>
880 <LINE>Upon the witness of these gentlemen,</LINE>
881 <LINE>This marvel to you.</LINE>
882 </SPEECH>
883
884 <SPEECH>
885 <SPEAKER>HAMLET</SPEAKER>
886 <LINE>For God's love, let me hear.</LINE>
887 </SPEECH>
888
889 <SPEECH>
890 <SPEAKER>HORATIO</SPEAKER>
891 <LINE>Two nights together had these gentlemen,</LINE>
892 <LINE>Marcellus and Bernardo, on their watch,</LINE>
893 <LINE>In the dead vast and middle of the night,</LINE>
894 <LINE>Been thus encounter'd. A figure like your father,</LINE>
895 <LINE>Armed at point exactly, cap-a-pe,</LINE>
896 <LINE>Appears before them, and with solemn march</LINE>
897 <LINE>Goes slow and stately by them: thrice he walk'd</LINE>
898 <LINE>By their oppress'd and fear-surprised eyes,</LINE>
899 <LINE>Within his truncheon's length; whilst they, distilled</LINE>
900 <LINE>Almost to jelly with the act of fear,</LINE>
901 <LINE>Stand dumb and speak not to him. This to me</LINE>
902 <LINE>In dreadful secrecy impart they did;</LINE>
903 <LINE>And I with them the third night kept the watch;</LINE>
904 <LINE>Where, as they had deliver'd, both in time,</LINE>
905 <LINE>Form of the thing, each word made true and good,</LINE>
906 <LINE>The apparition comes: I knew your father;</LINE>
907 <LINE>These hands are not more like.</LINE>
908 </SPEECH>
909
910 <SPEECH>
911 <SPEAKER>HAMLET</SPEAKER>
912 <LINE>But where was this?</LINE>
913 </SPEECH>
914
915 <SPEECH>
916 <SPEAKER>MARCELLUS</SPEAKER>
917 <LINE>My lord, upon the platform where we watch'd.</LINE>
918 </SPEECH>
919
920 <SPEECH>
921 <SPEAKER>HAMLET</SPEAKER>
922 <LINE>Did you not speak to it?</LINE>
923 </SPEECH>
924
925 <SPEECH>
926 <SPEAKER>HORATIO</SPEAKER>
927 <LINE>My lord, I did;</LINE>
928 <LINE>But answer made it none: yet once methought</LINE>
929 <LINE>It lifted up its head and did address</LINE>
930 <LINE>Itself to motion, like as it would speak;</LINE>
931 <LINE>But even then the morning cock crew loud,</LINE>
932 <LINE>And at the sound it shrunk in haste away,</LINE>
933 <LINE>And vanish'd from our sight.</LINE>
934 </SPEECH>
935
936 <SPEECH>
937 <SPEAKER>HAMLET</SPEAKER>
938 <LINE>'Tis very strange.</LINE>
939 </SPEECH>
940
941 <SPEECH>
942 <SPEAKER>HORATIO</SPEAKER>
943 <LINE>As I do live, my honour'd lord, 'tis true;</LINE>
944 <LINE>And we did think it writ down in our duty</LINE>
945 <LINE>To let you know of it.</LINE>
946 </SPEECH>
947
948 <SPEECH>
949 <SPEAKER>HAMLET</SPEAKER>
950 <LINE>Indeed, indeed, sirs, but this troubles me.</LINE>
951 <LINE>Hold you the watch to-night?</LINE>
952 </SPEECH>
953
954 <SPEECH>
955 <SPEAKER>MARCELLUS</SPEAKER>
956 <SPEAKER>BERNARDO</SPEAKER>
957 <LINE>We do, my lord.</LINE>
958 </SPEECH>
959
960 <SPEECH>
961 <SPEAKER>HAMLET</SPEAKER>
962 <LINE>Arm'd, say you?</LINE>
963 </SPEECH>
964
965 <SPEECH>
966 <SPEAKER>MARCELLUS</SPEAKER>
967 <SPEAKER>BERNARDO</SPEAKER>
968 <LINE>Arm'd, my lord.</LINE>
969 </SPEECH>
970
971 <SPEECH>
972 <SPEAKER>HAMLET</SPEAKER>
973 <LINE>From top to toe?</LINE>
974 </SPEECH>
975
976 <SPEECH>
977 <SPEAKER>MARCELLUS</SPEAKER>
978 <SPEAKER>BERNARDO</SPEAKER>
979 <LINE>My lord, from head to foot.</LINE>
980 </SPEECH>
981
982 <SPEECH>
983 <SPEAKER>HAMLET</SPEAKER>
984 <LINE>Then saw you not his face?</LINE>
985 </SPEECH>
986
987 <SPEECH>
988 <SPEAKER>HORATIO</SPEAKER>
989 <LINE>O, yes, my lord; he wore his beaver up.</LINE>
990 </SPEECH>
991
992 <SPEECH>
993 <SPEAKER>HAMLET</SPEAKER>
994 <LINE>What, look'd he frowningly?</LINE>
995 </SPEECH>
996
997 <SPEECH>
998 <SPEAKER>HORATIO</SPEAKER>
999 <LINE>A countenance more in sorrow than in anger.</LINE>
1000 </SPEECH>
1001
1002 <SPEECH>
1003 <SPEAKER>HAMLET</SPEAKER>
1004 <LINE>Pale or red?</LINE>
1005 </SPEECH>
1006
1007 <SPEECH>
1008 <SPEAKER>HORATIO</SPEAKER>
1009 <LINE>Nay, very pale.</LINE>
1010 </SPEECH>
1011
1012 <SPEECH>
1013 <SPEAKER>HAMLET</SPEAKER>
1014 <LINE>And fix'd his eyes upon you?</LINE>
1015 </SPEECH>
1016
1017 <SPEECH>
1018 <SPEAKER>HORATIO</SPEAKER>
1019 <LINE>Most constantly.</LINE>
1020 </SPEECH>
1021
1022 <SPEECH>
1023 <SPEAKER>HAMLET</SPEAKER>
1024 <LINE>I would I had been there.</LINE>
1025 </SPEECH>
1026
1027 <SPEECH>
1028 <SPEAKER>HORATIO</SPEAKER>
1029 <LINE>It would have much amazed you.</LINE>
1030 </SPEECH>
1031
1032 <SPEECH>
1033 <SPEAKER>HAMLET</SPEAKER>
1034 <LINE>Very like, very like. Stay'd it long?</LINE>
1035 </SPEECH>
1036
1037 <SPEECH>
1038 <SPEAKER>HORATIO</SPEAKER>
1039 <LINE>While one with moderate haste might tell a hundred.</LINE>
1040 </SPEECH>
1041
1042 <SPEECH>
1043 <SPEAKER>MARCELLUS</SPEAKER>
1044 <SPEAKER>BERNARDO</SPEAKER>
1045 <LINE>Longer, longer.</LINE>
1046 </SPEECH>
1047
1048 <SPEECH>
1049 <SPEAKER>HORATIO</SPEAKER>
1050 <LINE>Not when I saw't.</LINE>
1051 </SPEECH>
1052
1053 <SPEECH>
1054 <SPEAKER>HAMLET</SPEAKER>
1055 <LINE>His beard was grizzled--no?</LINE>
1056 </SPEECH>
1057
1058 <SPEECH>
1059 <SPEAKER>HORATIO</SPEAKER>
1060 <LINE>It was, as I have seen it in his life,</LINE>
1061 <LINE>A sable silver'd.</LINE>
1062 </SPEECH>
1063
1064 <SPEECH>
1065 <SPEAKER>HAMLET</SPEAKER>
1066 <LINE>I will watch to-night;</LINE>
1067 <LINE>Perchance 'twill walk again.</LINE>
1068 </SPEECH>
1069
1070 <SPEECH>
1071 <SPEAKER>HORATIO</SPEAKER>
1072 <LINE>I warrant it will.</LINE>
1073 </SPEECH>
1074
1075 <SPEECH>
1076 <SPEAKER>HAMLET</SPEAKER>
1077 <LINE>If it assume my noble father's person,</LINE>
1078 <LINE>I'll speak to it, though hell itself should gape</LINE>
1079 <LINE>And bid me hold my peace. I pray you all,</LINE>
1080 <LINE>If you have hitherto conceal'd this sight,</LINE>
1081 <LINE>Let it be tenable in your silence still;</LINE>
1082 <LINE>And whatsoever else shall hap to-night,</LINE>
1083 <LINE>Give it an understanding, but no tongue:</LINE>
1084 <LINE>I will requite your loves. So, fare you well:</LINE>
1085 <LINE>Upon the platform, 'twixt eleven and twelve,</LINE>
1086 <LINE>I'll visit you.</LINE>
1087 </SPEECH>
1088
1089 <SPEECH>
1090 <SPEAKER>All</SPEAKER>
1091 <LINE>Our duty to your honour.</LINE>
1092 </SPEECH>
1093
1094 <SPEECH>
1095 <SPEAKER>HAMLET</SPEAKER>
1096 <LINE>Your loves, as mine to you: farewell.</LINE>
1097 <STAGEDIR>Exeunt all but HAMLET</STAGEDIR>
1098 <LINE>My father's spirit in arms! all is not well;</LINE>
1099 <LINE>I doubt some foul play: would the night were come!</LINE>
1100 <LINE>Till then sit still, my soul: foul deeds will rise,</LINE>
1101 <LINE>Though all the earth o'erwhelm them, to men's eyes.</LINE>
1102 </SPEECH>
1103
1104
1105 <STAGEDIR>Exit</STAGEDIR>
1106 </SCENE>
1107
1108 <SCENE><TITLE>SCENE III. A room in Polonius' house.</TITLE>
1109 <STAGEDIR>Enter LAERTES and OPHELIA</STAGEDIR>
1110
1111 <SPEECH>
1112 <SPEAKER>LAERTES</SPEAKER>
1113 <LINE>My necessaries are embark'd: farewell:</LINE>
1114 <LINE>And, sister, as the winds give benefit</LINE>
1115 <LINE>And convoy is assistant, do not sleep,</LINE>
1116 <LINE>But let me hear from you.</LINE>
1117 </SPEECH>
1118
1119 <SPEECH>
1120 <SPEAKER>OPHELIA</SPEAKER>
1121 <LINE>Do you doubt that?</LINE>
1122 </SPEECH>
1123
1124 <SPEECH>
1125 <SPEAKER>LAERTES</SPEAKER>
1126 <LINE>For Hamlet and the trifling of his favour,</LINE>
1127 <LINE>Hold it a fashion and a toy in blood,</LINE>
1128 <LINE>A violet in the youth of primy nature,</LINE>
1129 <LINE>Forward, not permanent, sweet, not lasting,</LINE>
1130 <LINE>The perfume and suppliance of a minute; No more.</LINE>
1131 </SPEECH>
1132
1133 <SPEECH>
1134 <SPEAKER>OPHELIA</SPEAKER>
1135 <LINE>No more but so?</LINE>
1136 </SPEECH>
1137
1138 <SPEECH>
1139 <SPEAKER>LAERTES</SPEAKER>
1140 <LINE>Think it no more;</LINE>
1141 <LINE>For nature, crescent, does not grow alone</LINE>
1142 <LINE>In thews and bulk, but, as this temple waxes,</LINE>
1143 <LINE>The inward service of the mind and soul</LINE>
1144 <LINE>Grows wide withal. Perhaps he loves you now,</LINE>
1145 <LINE>And now no soil nor cautel doth besmirch</LINE>
1146 <LINE>The virtue of his will: but you must fear,</LINE>
1147 <LINE>His greatness weigh'd, his will is not his own;</LINE>
1148 <LINE>For he himself is subject to his birth:</LINE>
1149 <LINE>He may not, as unvalued persons do,</LINE>
1150 <LINE>Carve for himself; for on his choice depends</LINE>
1151 <LINE>The safety and health of this whole state;</LINE>
1152 <LINE>And therefore must his choice be circumscribed</LINE>
1153 <LINE>Unto the voice and yielding of that body</LINE>
1154 <LINE>Whereof he is the head. Then if he says he loves you,</LINE>
1155 <LINE>It fits your wisdom so far to believe it</LINE>
1156 <LINE>As he in his particular act and place</LINE>
1157 <LINE>May give his saying deed; which is no further</LINE>
1158 <LINE>Than the main voice of Denmark goes withal.</LINE>
1159 <LINE>Then weigh what loss your honour may sustain,</LINE>
1160 <LINE>If with too credent ear you list his songs,</LINE>
1161 <LINE>Or lose your heart, or your chaste treasure open</LINE>
1162 <LINE>To his unmaster'd importunity.</LINE>
1163 <LINE>Fear it, Ophelia, fear it, my dear sister,</LINE>
1164 <LINE>And keep you in the rear of your affection,</LINE>
1165 <LINE>Out of the shot and danger of desire.</LINE>
1166 <LINE>The chariest maid is prodigal enough,</LINE>
1167 <LINE>If she unmask her beauty to the moon:</LINE>
1168 <LINE>Virtue itself 'scapes not calumnious strokes:</LINE>
1169 <LINE>The canker galls the infants of the spring,</LINE>
1170 <LINE>Too oft before their buttons be disclosed,</LINE>
1171 <LINE>And in the morn and liquid dew of youth</LINE>
1172 <LINE>Contagious blastments are most imminent.</LINE>
1173 <LINE>Be wary then; best safety lies in fear:</LINE>
1174 <LINE>Youth to itself rebels, though none else near.</LINE>
1175 </SPEECH>
1176
1177 <SPEECH>
1178 <SPEAKER>OPHELIA</SPEAKER>
1179 <LINE>I shall the effect of this good lesson keep,</LINE>
1180 <LINE>As watchman to my heart. But, good my brother,</LINE>
1181 <LINE>Do not, as some ungracious pastors do,</LINE>
1182 <LINE>Show me the steep and thorny way to heaven;</LINE>
1183 <LINE>Whiles, like a puff'd and reckless libertine,</LINE>
1184 <LINE>Himself the primrose path of dalliance treads,</LINE>
1185 <LINE>And recks not his own rede.</LINE>
1186 </SPEECH>
1187
1188 <SPEECH>
1189 <SPEAKER>LAERTES</SPEAKER>
1190 <LINE>O, fear me not.</LINE>
1191 <LINE>I stay too long: but here my father comes.</LINE>
1192 <STAGEDIR>Enter POLONIUS</STAGEDIR>
1193 <LINE>A double blessing is a double grace,</LINE>
1194 <LINE>Occasion smiles upon a second leave.</LINE>
1195 </SPEECH>
1196
1197 <SPEECH>
1198 <SPEAKER>LORD POLONIUS</SPEAKER>
1199 <LINE>Yet here, Laertes! aboard, aboard, for shame!</LINE>
1200 <LINE>The wind sits in the shoulder of your sail,</LINE>
1201 <LINE>And you are stay'd for. There; my blessing with thee!</LINE>
1202 <LINE>And these few precepts in thy memory</LINE>
1203 <LINE>See thou character. Give thy thoughts no tongue,</LINE>
1204 <LINE>Nor any unproportioned thought his act.</LINE>
1205 <LINE>Be thou familiar, but by no means vulgar.</LINE>
1206 <LINE>Those friends thou hast, and their adoption tried,</LINE>
1207 <LINE>Grapple them to thy soul with hoops of steel;</LINE>
1208 <LINE>But do not dull thy palm with entertainment</LINE>
1209 <LINE>Of each new-hatch'd, unfledged comrade. Beware</LINE>
1210 <LINE>Of entrance to a quarrel, but being in,</LINE>
1211 <LINE>Bear't that the opposed may beware of thee.</LINE>
1212 <LINE>Give every man thy ear, but few thy voice;</LINE>
1213 <LINE>Take each man's censure, but reserve thy judgment.</LINE>
1214 <LINE>Costly thy habit as thy purse can buy,</LINE>
1215 <LINE>But not express'd in fancy; rich, not gaudy;</LINE>
1216 <LINE>For the apparel oft proclaims the man,</LINE>
1217 <LINE>And they in France of the best rank and station</LINE>
1218 <LINE>Are of a most select and generous chief in that.</LINE>
1219 <LINE>Neither a borrower nor a lender be;</LINE>
1220 <LINE>For loan oft loses both itself and friend,</LINE>
1221 <LINE>And borrowing dulls the edge of husbandry.</LINE>
1222 <LINE>This above all: to thine ownself be true,</LINE>
1223 <LINE>And it must follow, as the night the day,</LINE>
1224 <LINE>Thou canst not then be false to any man.</LINE>
1225 <LINE>Farewell: my blessing season this in thee!</LINE>
1226 </SPEECH>
1227
1228 <SPEECH>
1229 <SPEAKER>LAERTES</SPEAKER>
1230 <LINE>Most humbly do I take my leave, my lord.</LINE>
1231 </SPEECH>
1232
1233 <SPEECH>
1234 <SPEAKER>LORD POLONIUS</SPEAKER>
1235 <LINE>The time invites you; go; your servants tend.</LINE>
1236 </SPEECH>
1237
1238 <SPEECH>
1239 <SPEAKER>LAERTES</SPEAKER>
1240 <LINE>Farewell, Ophelia; and remember well</LINE>
1241 <LINE>What I have said to you.</LINE>
1242 </SPEECH>
1243
1244 <SPEECH>
1245 <SPEAKER>OPHELIA</SPEAKER>
1246 <LINE>'Tis in my memory lock'd,</LINE>
1247 <LINE>And you yourself shall keep the key of it.</LINE>
1248 </SPEECH>
1249
1250 <SPEECH>
1251 <SPEAKER>LAERTES</SPEAKER>
1252 <LINE>Farewell.</LINE>
1253 </SPEECH>
1254
1255
1256 <STAGEDIR>Exit</STAGEDIR>
1257
1258 <SPEECH>
1259 <SPEAKER>LORD POLONIUS</SPEAKER>
1260 <LINE>What is't, Ophelia, be hath said to you?</LINE>
1261 </SPEECH>
1262
1263 <SPEECH>
1264 <SPEAKER>OPHELIA</SPEAKER>
1265 <LINE>So please you, something touching the Lord Hamlet.</LINE>
1266 </SPEECH>
1267
1268 <SPEECH>
1269 <SPEAKER>LORD POLONIUS</SPEAKER>
1270 <LINE>Marry, well bethought:</LINE>
1271 <LINE>'Tis told me, he hath very oft of late</LINE>
1272 <LINE>Given private time to you; and you yourself</LINE>
1273 <LINE>Have of your audience been most free and bounteous:</LINE>
1274 <LINE>If it be so, as so 'tis put on me,</LINE>
1275 <LINE>And that in way of caution, I must tell you,</LINE>
1276 <LINE>You do not understand yourself so clearly</LINE>
1277 <LINE>As it behoves my daughter and your honour.</LINE>
1278 <LINE>What is between you? give me up the truth.</LINE>
1279 </SPEECH>
1280
1281 <SPEECH>
1282 <SPEAKER>OPHELIA</SPEAKER>
1283 <LINE>He hath, my lord, of late made many tenders</LINE>
1284 <LINE>Of his affection to me.</LINE>
1285 </SPEECH>
1286
1287 <SPEECH>
1288 <SPEAKER>LORD POLONIUS</SPEAKER>
1289 <LINE>Affection! pooh! you speak like a green girl,</LINE>
1290 <LINE>Unsifted in such perilous circumstance.</LINE>
1291 <LINE>Do you believe his tenders, as you call them?</LINE>
1292 </SPEECH>
1293
1294 <SPEECH>
1295 <SPEAKER>OPHELIA</SPEAKER>
1296 <LINE>I do not know, my lord, what I should think.</LINE>
1297 </SPEECH>
1298
1299 <SPEECH>
1300 <SPEAKER>LORD POLONIUS</SPEAKER>
1301 <LINE>Marry, I'll teach you: think yourself a baby;</LINE>
1302 <LINE>That you have ta'en these tenders for true pay,</LINE>
1303 <LINE>Which are not sterling. Tender yourself more dearly;</LINE>
1304 <LINE>Or--not to crack the wind of the poor phrase,</LINE>
1305 <LINE>Running it thus--you'll tender me a fool.</LINE>
1306 </SPEECH>
1307
1308 <SPEECH>
1309 <SPEAKER>OPHELIA</SPEAKER>
1310 <LINE>My lord, he hath importuned me with love</LINE>
1311 <LINE>In honourable fashion.</LINE>
1312 </SPEECH>
1313
1314 <SPEECH>
1315 <SPEAKER>LORD POLONIUS</SPEAKER>
1316 <LINE>Ay, fashion you may call it; go to, go to.</LINE>
1317 </SPEECH>
1318
1319 <SPEECH>
1320 <SPEAKER>OPHELIA</SPEAKER>
1321 <LINE>And hath given countenance to his speech, my lord,</LINE>
1322 <LINE>With almost all the holy vows of heaven.</LINE>
1323 </SPEECH>
1324
1325 <SPEECH>
1326 <SPEAKER>LORD POLONIUS</SPEAKER>
1327 <LINE>Ay, springes to catch woodcocks. I do know,</LINE>
1328 <LINE>When the blood burns, how prodigal the soul</LINE>
1329 <LINE>Lends the tongue vows: these blazes, daughter,</LINE>
1330 <LINE>Giving more light than heat, extinct in both,</LINE>
1331 <LINE>Even in their promise, as it is a-making,</LINE>
1332 <LINE>You must not take for fire. From this time</LINE>
1333 <LINE>Be somewhat scanter of your maiden presence;</LINE>
1334 <LINE>Set your entreatments at a higher rate</LINE>
1335 <LINE>Than a command to parley. For Lord Hamlet,</LINE>
1336 <LINE>Believe so much in him, that he is young</LINE>
1337 <LINE>And with a larger tether may he walk</LINE>
1338 <LINE>Than may be given you: in few, Ophelia,</LINE>
1339 <LINE>Do not believe his vows; for they are brokers,</LINE>
1340 <LINE>Not of that dye which their investments show,</LINE>
1341 <LINE>But mere implorators of unholy suits,</LINE>
1342 <LINE>Breathing like sanctified and pious bawds,</LINE>
1343 <LINE>The better to beguile. This is for all:</LINE>
1344 <LINE>I would not, in plain terms, from this time forth,</LINE>
1345 <LINE>Have you so slander any moment leisure,</LINE>
1346 <LINE>As to give words or talk with the Lord Hamlet.</LINE>
1347 <LINE>Look to't, I charge you: come your ways.</LINE>
1348 </SPEECH>
1349
1350 <SPEECH>
1351 <SPEAKER>OPHELIA</SPEAKER>
1352 <LINE>I shall obey, my lord.</LINE>
1353 </SPEECH>
1354
1355
1356 <STAGEDIR>Exeunt</STAGEDIR>
1357 </SCENE>
1358
1359 <SCENE><TITLE>SCENE IV. The platform.</TITLE>
1360 <STAGEDIR>Enter HAMLET, HORATIO, and MARCELLUS</STAGEDIR>
1361
1362 <SPEECH>
1363 <SPEAKER>HAMLET</SPEAKER>
1364 <LINE>The air bites shrewdly; it is very cold.</LINE>
1365 </SPEECH>
1366
1367 <SPEECH>
1368 <SPEAKER>HORATIO</SPEAKER>
1369 <LINE>It is a nipping and an eager air.</LINE>
1370 </SPEECH>
1371
1372 <SPEECH>
1373 <SPEAKER>HAMLET</SPEAKER>
1374 <LINE>What hour now?</LINE>
1375 </SPEECH>
1376
1377 <SPEECH>
1378 <SPEAKER>HORATIO</SPEAKER>
1379 <LINE>I think it lacks of twelve.</LINE>
1380 </SPEECH>
1381
1382 <SPEECH>
1383 <SPEAKER>HAMLET</SPEAKER>
1384 <LINE>No, it is struck.</LINE>
1385 </SPEECH>
1386
1387 <SPEECH>
1388 <SPEAKER>HORATIO</SPEAKER>
1389 <LINE>Indeed? I heard it not: then it draws near the season</LINE>
1390 <LINE>Wherein the spirit held his wont to walk.</LINE>
1391 <STAGEDIR>A flourish of trumpets, and ordnance shot off, within</STAGEDIR>
1392 <LINE>What does this mean, my lord?</LINE>
1393 </SPEECH>
1394
1395 <SPEECH>
1396 <SPEAKER>HAMLET</SPEAKER>
1397 <LINE>The king doth wake to-night and takes his rouse,</LINE>
1398 <LINE>Keeps wassail, and the swaggering up-spring reels;</LINE>
1399 <LINE>And, as he drains his draughts of Rhenish down,</LINE>
1400 <LINE>The kettle-drum and trumpet thus bray out</LINE>
1401 <LINE>The triumph of his pledge.</LINE>
1402 </SPEECH>
1403
1404 <SPEECH>
1405 <SPEAKER>HORATIO</SPEAKER>
1406 <LINE>Is it a custom?</LINE>
1407 </SPEECH>
1408
1409 <SPEECH>
1410 <SPEAKER>HAMLET</SPEAKER>
1411 <LINE>Ay, marry, is't:</LINE>
1412 <LINE>But to my mind, though I am native here</LINE>
1413 <LINE>And to the manner born, it is a custom</LINE>
1414 <LINE>More honour'd in the breach than the observance.</LINE>
1415 <LINE>This heavy-headed revel east and west</LINE>
1416 <LINE>Makes us traduced and tax'd of other nations:</LINE>
1417 <LINE>They clepe us drunkards, and with swinish phrase</LINE>
1418 <LINE>Soil our addition; and indeed it takes</LINE>
1419 <LINE>From our achievements, though perform'd at height,</LINE>
1420 <LINE>The pith and marrow of our attribute.</LINE>
1421 <LINE>So, oft it chances in particular men,</LINE>
1422 <LINE>That for some vicious mole of nature in them,</LINE>
1423 <LINE>As, in their birth--wherein they are not guilty,</LINE>
1424 <LINE>Since nature cannot choose his origin--</LINE>
1425 <LINE>By the o'ergrowth of some complexion,</LINE>
1426 <LINE>Oft breaking down the pales and forts of reason,</LINE>
1427 <LINE>Or by some habit that too much o'er-leavens</LINE>
1428 <LINE>The form of plausive manners, that these men,</LINE>
1429 <LINE>Carrying, I say, the stamp of one defect,</LINE>
1430 <LINE>Being nature's livery, or fortune's star,--</LINE>
1431 <LINE>Their virtues else--be they as pure as grace,</LINE>
1432 <LINE>As infinite as man may undergo--</LINE>
1433 <LINE>Shall in the general censure take corruption</LINE>
1434 <LINE>From that particular fault: the dram of eale</LINE>
1435 <LINE>Doth all the noble substance of a doubt</LINE>
1436 <LINE>To his own scandal.</LINE>
1437 </SPEECH>
1438
1439 <SPEECH>
1440 <SPEAKER>HORATIO</SPEAKER>
1441 <LINE>Look, my lord, it comes!</LINE>
1442 </SPEECH>
1443
1444
1445 <STAGEDIR>Enter Ghost</STAGEDIR>
1446
1447 <SPEECH>
1448 <SPEAKER>HAMLET</SPEAKER>
1449 <LINE>Angels and ministers of grace defend us!</LINE>
1450 <LINE>Be thou a spirit of health or goblin damn'd,</LINE>
1451 <LINE>Bring with thee airs from heaven or blasts from hell,</LINE>
1452 <LINE>Be thy intents wicked or charitable,</LINE>
1453 <LINE>Thou comest in such a questionable shape</LINE>
1454 <LINE>That I will speak to thee: I'll call thee Hamlet,</LINE>
1455 <LINE>King, father, royal Dane: O, answer me!</LINE>
1456 <LINE>Let me not burst in ignorance; but tell</LINE>
1457 <LINE>Why thy canonized bones, hearsed in death,</LINE>
1458 <LINE>Have burst their cerements; why the sepulchre,</LINE>
1459 <LINE>Wherein we saw thee quietly inurn'd,</LINE>
1460 <LINE>Hath oped his ponderous and marble jaws,</LINE>
1461 <LINE>To cast thee up again. What may this mean,</LINE>
1462 <LINE>That thou, dead corse, again in complete steel</LINE>
1463 <LINE>Revisit'st thus the glimpses of the moon,</LINE>
1464 <LINE>Making night hideous; and we fools of nature</LINE>
1465 <LINE>So horridly to shake our disposition</LINE>
1466 <LINE>With thoughts beyond the reaches of our souls?</LINE>
1467 <LINE>Say, why is this? wherefore? what should we do?</LINE>
1468 </SPEECH>
1469
1470
1471 <STAGEDIR>Ghost beckons HAMLET</STAGEDIR>
1472
1473 <SPEECH>
1474 <SPEAKER>HORATIO</SPEAKER>
1475 <LINE>It beckons you to go away with it,</LINE>
1476 <LINE>As if it some impartment did desire</LINE>
1477 <LINE>To you alone.</LINE>
1478 </SPEECH>
1479
1480 <SPEECH>
1481 <SPEAKER>MARCELLUS</SPEAKER>
1482 <LINE>Look, with what courteous action</LINE>
1483 <LINE>It waves you to a more removed ground:</LINE>
1484 <LINE>But do not go with it.</LINE>
1485 </SPEECH>
1486
1487 <SPEECH>
1488 <SPEAKER>HORATIO</SPEAKER>
1489 <LINE>No, by no means.</LINE>
1490 </SPEECH>
1491
1492 <SPEECH>
1493 <SPEAKER>HAMLET</SPEAKER>
1494 <LINE>It will not speak; then I will follow it.</LINE>
1495 </SPEECH>
1496
1497 <SPEECH>
1498 <SPEAKER>HORATIO</SPEAKER>
1499 <LINE>Do not, my lord.</LINE>
1500 </SPEECH>
1501
1502 <SPEECH>
1503 <SPEAKER>HAMLET</SPEAKER>
1504 <LINE>Why, what should be the fear?</LINE>
1505 <LINE>I do not set my life in a pin's fee;</LINE>
1506 <LINE>And for my soul, what can it do to that,</LINE>
1507 <LINE>Being a thing immortal as itself?</LINE>
1508 <LINE>It waves me forth again: I'll follow it.</LINE>
1509 </SPEECH>
1510
1511 <SPEECH>
1512 <SPEAKER>HORATIO</SPEAKER>
1513 <LINE>What if it tempt you toward the flood, my lord,</LINE>
1514 <LINE>Or to the dreadful summit of the cliff</LINE>
1515 <LINE>That beetles o'er his base into the sea,</LINE>
1516 <LINE>And there assume some other horrible form,</LINE>
1517 <LINE>Which might deprive your sovereignty of reason</LINE>
1518 <LINE>And draw you into madness? think of it:</LINE>
1519 <LINE>The very place puts toys of desperation,</LINE>
1520 <LINE>Without more motive, into every brain</LINE>
1521 <LINE>That looks so many fathoms to the sea</LINE>
1522 <LINE>And hears it roar beneath.</LINE>
1523 </SPEECH>
1524
1525 <SPEECH>
1526 <SPEAKER>HAMLET</SPEAKER>
1527 <LINE>It waves me still.</LINE>
1528 <LINE>Go on; I'll follow thee.</LINE>
1529 </SPEECH>
1530
1531 <SPEECH>
1532 <SPEAKER>MARCELLUS</SPEAKER>
1533 <LINE>You shall not go, my lord.</LINE>
1534 </SPEECH>
1535
1536 <SPEECH>
1537 <SPEAKER>HAMLET</SPEAKER>
1538 <LINE>Hold off your hands.</LINE>
1539 </SPEECH>
1540
1541 <SPEECH>
1542 <SPEAKER>HORATIO</SPEAKER>
1543 <LINE>Be ruled; you shall not go.</LINE>
1544 </SPEECH>
1545
1546 <SPEECH>
1547 <SPEAKER>HAMLET</SPEAKER>
1548 <LINE>My fate cries out,</LINE>
1549 <LINE>And makes each petty artery in this body</LINE>
1550 <LINE>As hardy as the Nemean lion's nerve.</LINE>
1551 <LINE>Still am I call'd. Unhand me, gentlemen.</LINE>
1552 <LINE>By heaven, I'll make a ghost of him that lets me!</LINE>
1553 <LINE>I say, away! Go on; I'll follow thee.</LINE>
1554 </SPEECH>
1555
1556
1557 <STAGEDIR>Exeunt Ghost and HAMLET</STAGEDIR>
1558
1559 <SPEECH>
1560 <SPEAKER>HORATIO</SPEAKER>
1561 <LINE>He waxes desperate with imagination.</LINE>
1562 </SPEECH>
1563
1564 <SPEECH>
1565 <SPEAKER>MARCELLUS</SPEAKER>
1566 <LINE>Let's follow; 'tis not fit thus to obey him.</LINE>
1567 </SPEECH>
1568
1569 <SPEECH>
1570 <SPEAKER>HORATIO</SPEAKER>
1571 <LINE>Have after. To what issue will this come?</LINE>
1572 </SPEECH>
1573
1574 <SPEECH>
1575 <SPEAKER>MARCELLUS</SPEAKER>
1576 <LINE>Something is rotten in the state of Denmark.</LINE>
1577 </SPEECH>
1578
1579 <SPEECH>
1580 <SPEAKER>HORATIO</SPEAKER>
1581 <LINE>Heaven will direct it.</LINE>
1582 </SPEECH>
1583
1584 <SPEECH>
1585 <SPEAKER>MARCELLUS</SPEAKER>
1586 <LINE>Nay, let's follow him.</LINE>
1587 </SPEECH>
1588
1589
1590 <STAGEDIR>Exeunt</STAGEDIR>
1591 </SCENE>
1592
1593 <SCENE><TITLE>SCENE V. Another part of the platform.</TITLE>
1594 <STAGEDIR>Enter GHOST and HAMLET</STAGEDIR>
1595
1596 <SPEECH>
1597 <SPEAKER>HAMLET</SPEAKER>
1598 <LINE>Where wilt thou lead me? speak; I'll go no further.</LINE>
1599 </SPEECH>
1600
1601 <SPEECH>
1602 <SPEAKER>Ghost</SPEAKER>
1603 <LINE>Mark me.</LINE>
1604 </SPEECH>
1605
1606 <SPEECH>
1607 <SPEAKER>HAMLET</SPEAKER>
1608 <LINE>I will.</LINE>
1609 </SPEECH>
1610
1611 <SPEECH>
1612 <SPEAKER>Ghost</SPEAKER>
1613 <LINE>My hour is almost come,</LINE>
1614 <LINE>When I to sulphurous and tormenting flames</LINE>
1615 <LINE>Must render up myself.</LINE>
1616 </SPEECH>
1617
1618 <SPEECH>
1619 <SPEAKER>HAMLET</SPEAKER>
1620 <LINE>Alas, poor ghost!</LINE>
1621 </SPEECH>
1622
1623 <SPEECH>
1624 <SPEAKER>Ghost</SPEAKER>
1625 <LINE>Pity me not, but lend thy serious hearing</LINE>
1626 <LINE>To what I shall unfold.</LINE>
1627 </SPEECH>
1628
1629 <SPEECH>
1630 <SPEAKER>HAMLET</SPEAKER>
1631 <LINE>Speak; I am bound to hear.</LINE>
1632 </SPEECH>
1633
1634 <SPEECH>
1635 <SPEAKER>Ghost</SPEAKER>
1636 <LINE>So art thou to revenge, when thou shalt hear.</LINE>
1637 </SPEECH>
1638
1639 <SPEECH>
1640 <SPEAKER>HAMLET</SPEAKER>
1641 <LINE>What?</LINE>
1642 </SPEECH>
1643
1644 <SPEECH>
1645 <SPEAKER>Ghost</SPEAKER>
1646 <LINE>I am thy father's spirit,</LINE>
1647 <LINE>Doom'd for a certain term to walk the night,</LINE>
1648 <LINE>And for the day confined to fast in fires,</LINE>
1649 <LINE>Till the foul crimes done in my days of nature</LINE>
1650 <LINE>Are burnt and purged away. But that I am forbid</LINE>
1651 <LINE>To tell the secrets of my prison-house,</LINE>
1652 <LINE>I could a tale unfold whose lightest word</LINE>
1653 <LINE>Would harrow up thy soul, freeze thy young blood,</LINE>
1654 <LINE>Make thy two eyes, like stars, start from their spheres,</LINE>
1655 <LINE>Thy knotted and combined locks to part</LINE>
1656 <LINE>And each particular hair to stand on end,</LINE>
1657 <LINE>Like quills upon the fretful porpentine:</LINE>
1658 <LINE>But this eternal blazon must not be</LINE>
1659 <LINE>To ears of flesh and blood. List, list, O, list!</LINE>
1660 <LINE>If thou didst ever thy dear father love--</LINE>
1661 </SPEECH>
1662
1663 <SPEECH>
1664 <SPEAKER>HAMLET</SPEAKER>
1665 <LINE>O God!</LINE>
1666 </SPEECH>
1667
1668 <SPEECH>
1669 <SPEAKER>Ghost</SPEAKER>
1670 <LINE>Revenge his foul and most unnatural murder.</LINE>
1671 </SPEECH>
1672
1673 <SPEECH>
1674 <SPEAKER>HAMLET</SPEAKER>
1675 <LINE>Murder!</LINE>
1676 </SPEECH>
1677
1678 <SPEECH>
1679 <SPEAKER>Ghost</SPEAKER>
1680 <LINE>Murder most foul, as in the best it is;</LINE>
1681 <LINE>But this most foul, strange and unnatural.</LINE>
1682 </SPEECH>
1683
1684 <SPEECH>
1685 <SPEAKER>HAMLET</SPEAKER>
1686 <LINE>Haste me to know't, that I, with wings as swift</LINE>
1687 <LINE>As meditation or the thoughts of love,</LINE>
1688 <LINE>May sweep to my revenge.</LINE>
1689 </SPEECH>
1690
1691 <SPEECH>
1692 <SPEAKER>Ghost</SPEAKER>
1693 <LINE>I find thee apt;</LINE>
1694 <LINE>And duller shouldst thou be than the fat weed</LINE>
1695 <LINE>That roots itself in ease on Lethe wharf,</LINE>
1696 <LINE>Wouldst thou not stir in this. Now, Hamlet, hear:</LINE>
1697 <LINE>'Tis given out that, sleeping in my orchard,</LINE>
1698 <LINE>A serpent stung me; so the whole ear of Denmark</LINE>
1699 <LINE>Is by a forged process of my death</LINE>
1700 <LINE>Rankly abused: but know, thou noble youth,</LINE>
1701 <LINE>The serpent that did sting thy father's life</LINE>
1702 <LINE>Now wears his crown.</LINE>
1703 </SPEECH>
1704
1705 <SPEECH>
1706 <SPEAKER>HAMLET</SPEAKER>
1707 <LINE>O my prophetic soul! My uncle!</LINE>
1708 </SPEECH>
1709
1710 <SPEECH>
1711 <SPEAKER>Ghost</SPEAKER>
1712 <LINE>Ay, that incestuous, that adulterate beast,</LINE>
1713 <LINE>With witchcraft of his wit, with traitorous gifts,--</LINE>
1714 <LINE>O wicked wit and gifts, that have the power</LINE>
1715 <LINE>So to seduce!--won to his shameful lust</LINE>
1716 <LINE>The will of my most seeming-virtuous queen:</LINE>
1717 <LINE>O Hamlet, what a falling-off was there!</LINE>
1718 <LINE>From me, whose love was of that dignity</LINE>
1719 <LINE>That it went hand in hand even with the vow</LINE>
1720 <LINE>I made to her in marriage, and to decline</LINE>
1721 <LINE>Upon a wretch whose natural gifts were poor</LINE>
1722 <LINE>To those of mine!</LINE>
1723 <LINE>But virtue, as it never will be moved,</LINE>
1724 <LINE>Though lewdness court it in a shape of heaven,</LINE>
1725 <LINE>So lust, though to a radiant angel link'd,</LINE>
1726 <LINE>Will sate itself in a celestial bed,</LINE>
1727 <LINE>And prey on garbage.</LINE>
1728 <LINE>But, soft! methinks I scent the morning air;</LINE>
1729 <LINE>Brief let me be. Sleeping within my orchard,</LINE>
1730 <LINE>My custom always of the afternoon,</LINE>
1731 <LINE>Upon my secure hour thy uncle stole,</LINE>
1732 <LINE>With juice of cursed hebenon in a vial,</LINE>
1733 <LINE>And in the porches of my ears did pour</LINE>
1734 <LINE>The leperous distilment; whose effect</LINE>
1735 <LINE>Holds such an enmity with blood of man</LINE>
1736 <LINE>That swift as quicksilver it courses through</LINE>
1737 <LINE>The natural gates and alleys of the body,</LINE>
1738 <LINE>And with a sudden vigour doth posset</LINE>
1739 <LINE>And curd, like eager droppings into milk,</LINE>
1740 <LINE>The thin and wholesome blood: so did it mine;</LINE>
1741 <LINE>And a most instant tetter bark'd about,</LINE>
1742 <LINE>Most lazar-like, with vile and loathsome crust,</LINE>
1743 <LINE>All my smooth body.</LINE>
1744 <LINE>Thus was I, sleeping, by a brother's hand</LINE>
1745 <LINE>Of life, of crown, of queen, at once dispatch'd:</LINE>
1746 <LINE>Cut off even in the blossoms of my sin,</LINE>
1747 <LINE>Unhousel'd, disappointed, unanel'd,</LINE>
1748 <LINE>No reckoning made, but sent to my account</LINE>
1749 <LINE>With all my imperfections on my head:</LINE>
1750 <LINE>O, horrible! O, horrible! most horrible!</LINE>
1751 <LINE>If thou hast nature in thee, bear it not;</LINE>
1752 <LINE>Let not the royal bed of Denmark be</LINE>
1753 <LINE>A couch for luxury and damned incest.</LINE>
1754 <LINE>But, howsoever thou pursuest this act,</LINE>
1755 <LINE>Taint not thy mind, nor let thy soul contrive</LINE>
1756 <LINE>Against thy mother aught: leave her to heaven</LINE>
1757 <LINE>And to those thorns that in her bosom lodge,</LINE>
1758 <LINE>To prick and sting her. Fare thee well at once!</LINE>
1759 <LINE>The glow-worm shows the matin to be near,</LINE>
1760 <LINE>And 'gins to pale his uneffectual fire:</LINE>
1761 <LINE>Adieu, adieu! Hamlet, remember me.</LINE>
1762 </SPEECH>
1763
1764
1765 <STAGEDIR>Exit</STAGEDIR>
1766
1767 <SPEECH>
1768 <SPEAKER>HAMLET</SPEAKER>
1769 <LINE>O all you host of heaven! O earth! what else?</LINE>
1770 <LINE>And shall I couple hell? O, fie! Hold, hold, my heart;</LINE>
1771 <LINE>And you, my sinews, grow not instant old,</LINE>
1772 <LINE>But bear me stiffly up. Remember thee!</LINE>
1773 <LINE>Ay, thou poor ghost, while memory holds a seat</LINE>
1774 <LINE>In this distracted globe. Remember thee!</LINE>
1775 <LINE>Yea, from the table of my memory</LINE>
1776 <LINE>I'll wipe away all trivial fond records,</LINE>
1777 <LINE>All saws of books, all forms, all pressures past,</LINE>
1778 <LINE>That youth and observation copied there;</LINE>
1779 <LINE>And thy commandment all alone shall live</LINE>
1780 <LINE>Within the book and volume of my brain,</LINE>
1781 <LINE>Unmix'd with baser matter: yes, by heaven!</LINE>
1782 <LINE>O most pernicious woman!</LINE>
1783 <LINE>O villain, villain, smiling, damned villain!</LINE>
1784 <LINE>My tables,--meet it is I set it down,</LINE>
1785 <LINE>That one may smile, and smile, and be a villain;</LINE>
1786 <LINE>At least I'm sure it may be so in Denmark:</LINE>
1787 <STAGEDIR>Writing</STAGEDIR>
1788 <LINE>So, uncle, there you are. Now to my word;</LINE>
1789 <LINE>It is 'Adieu, adieu! remember me.'</LINE>
1790 <LINE>I have sworn 't.</LINE>
1791 </SPEECH>
1792
1793 <SPEECH>
1794 <SPEAKER>MARCELLUS</SPEAKER>
1795 <SPEAKER>HORATIO</SPEAKER>
1796 <LINE><STAGEDIR>Within</STAGEDIR> My lord, my lord,--</LINE>
1797 </SPEECH>
1798
1799 <SPEECH>
1800 <SPEAKER>MARCELLUS</SPEAKER>
1801 <LINE><STAGEDIR>Within</STAGEDIR> Lord Hamlet,--</LINE>
1802 </SPEECH>
1803
1804 <SPEECH>
1805 <SPEAKER>HORATIO</SPEAKER>
1806 <LINE><STAGEDIR>Within</STAGEDIR> Heaven secure him!</LINE>
1807 </SPEECH>
1808
1809 <SPEECH>
1810 <SPEAKER>HAMLET</SPEAKER>
1811 <LINE>So be it!</LINE>
1812 </SPEECH>
1813
1814 <SPEECH>
1815 <SPEAKER>HORATIO</SPEAKER>
1816 <LINE><STAGEDIR>Within</STAGEDIR> Hillo, ho, ho, my lord!</LINE>
1817 </SPEECH>
1818
1819 <SPEECH>
1820 <SPEAKER>HAMLET</SPEAKER>
1821 <LINE>Hillo, ho, ho, boy! come, bird, come.</LINE>
1822 </SPEECH>
1823
1824
1825 <STAGEDIR>Enter HORATIO and MARCELLUS</STAGEDIR>
1826
1827 <SPEECH>
1828 <SPEAKER>MARCELLUS</SPEAKER>
1829 <LINE>How is't, my noble lord?</LINE>
1830 </SPEECH>
1831
1832 <SPEECH>
1833 <SPEAKER>HORATIO</SPEAKER>
1834 <LINE>What news, my lord?</LINE>
1835 </SPEECH>
1836
1837 <SPEECH>
1838 <SPEAKER>HAMLET</SPEAKER>
1839 <LINE>O, wonderful!</LINE>
1840 </SPEECH>
1841
1842 <SPEECH>
1843 <SPEAKER>HORATIO</SPEAKER>
1844 <LINE>Good my lord, tell it.</LINE>
1845 </SPEECH>
1846
1847 <SPEECH>
1848 <SPEAKER>HAMLET</SPEAKER>
1849 <LINE>No; you'll reveal it.</LINE>
1850 </SPEECH>
1851
1852 <SPEECH>
1853 <SPEAKER>HORATIO</SPEAKER>
1854 <LINE>Not I, my lord, by heaven.</LINE>
1855 </SPEECH>
1856
1857 <SPEECH>
1858 <SPEAKER>MARCELLUS</SPEAKER>
1859 <LINE>Nor I, my lord.</LINE>
1860 </SPEECH>
1861
1862 <SPEECH>
1863 <SPEAKER>HAMLET</SPEAKER>
1864 <LINE>How say you, then; would heart of man once think it?</LINE>
1865 <LINE>But you'll be secret?</LINE>
1866 </SPEECH>
1867
1868 <SPEECH>
1869 <SPEAKER>HORATIO</SPEAKER>
1870 <SPEAKER>MARCELLUS</SPEAKER>
1871 <LINE>Ay, by heaven, my lord.</LINE>
1872 </SPEECH>
1873
1874 <SPEECH>
1875 <SPEAKER>HAMLET</SPEAKER>
1876 <LINE>There's ne'er a villain dwelling in all Denmark</LINE>
1877 <LINE>But he's an arrant knave.</LINE>
1878 </SPEECH>
1879
1880 <SPEECH>
1881 <SPEAKER>HORATIO</SPEAKER>
1882 <LINE>There needs no ghost, my lord, come from the grave</LINE>
1883 <LINE>To tell us this.</LINE>
1884 </SPEECH>
1885
1886 <SPEECH>
1887 <SPEAKER>HAMLET</SPEAKER>
1888 <LINE>Why, right; you are i' the right;</LINE>
1889 <LINE>And so, without more circumstance at all,</LINE>
1890 <LINE>I hold it fit that we shake hands and part:</LINE>
1891 <LINE>You, as your business and desire shall point you;</LINE>
1892 <LINE>For every man has business and desire,</LINE>
1893 <LINE>Such as it is; and for mine own poor part,</LINE>
1894 <LINE>Look you, I'll go pray.</LINE>
1895 </SPEECH>
1896
1897 <SPEECH>
1898 <SPEAKER>HORATIO</SPEAKER>
1899 <LINE>These are but wild and whirling words, my lord.</LINE>
1900 </SPEECH>
1901
1902 <SPEECH>
1903 <SPEAKER>HAMLET</SPEAKER>
1904 <LINE>I'm sorry they offend you, heartily;</LINE>
1905 <LINE>Yes, 'faith heartily.</LINE>
1906 </SPEECH>
1907
1908 <SPEECH>
1909 <SPEAKER>HORATIO</SPEAKER>
1910 <LINE>There's no offence, my lord.</LINE>
1911 </SPEECH>
1912
1913 <SPEECH>
1914 <SPEAKER>HAMLET</SPEAKER>
1915 <LINE>Yes, by Saint Patrick, but there is, Horatio,</LINE>
1916 <LINE>And much offence too. Touching this vision here,</LINE>
1917 <LINE>It is an honest ghost, that let me tell you:</LINE>
1918 <LINE>For your desire to know what is between us,</LINE>
1919 <LINE>O'ermaster 't as you may. And now, good friends,</LINE>
1920 <LINE>As you are friends, scholars and soldiers,</LINE>
1921 <LINE>Give me one poor request.</LINE>
1922 </SPEECH>
1923
1924 <SPEECH>
1925 <SPEAKER>HORATIO</SPEAKER>
1926 <LINE>What is't, my lord? we will.</LINE>
1927 </SPEECH>
1928
1929 <SPEECH>
1930 <SPEAKER>HAMLET</SPEAKER>
1931 <LINE>Never make known what you have seen to-night.</LINE>
1932 </SPEECH>
1933
1934 <SPEECH>
1935 <SPEAKER>HORATIO</SPEAKER>
1936 <SPEAKER>MARCELLUS</SPEAKER>
1937 <LINE>My lord, we will not.</LINE>
1938 </SPEECH>
1939
1940 <SPEECH>
1941 <SPEAKER>HAMLET</SPEAKER>
1942 <LINE>Nay, but swear't.</LINE>
1943 </SPEECH>
1944
1945 <SPEECH>
1946 <SPEAKER>HORATIO</SPEAKER>
1947 <LINE>In faith,</LINE>
1948 <LINE>My lord, not I.</LINE>
1949 </SPEECH>
1950
1951 <SPEECH>
1952 <SPEAKER>MARCELLUS</SPEAKER>
1953 <LINE>Nor I, my lord, in faith.</LINE>
1954 </SPEECH>
1955
1956 <SPEECH>
1957 <SPEAKER>HAMLET</SPEAKER>
1958 <LINE>Upon my sword.</LINE>
1959 </SPEECH>
1960
1961 <SPEECH>
1962 <SPEAKER>MARCELLUS</SPEAKER>
1963 <LINE>We have sworn, my lord, already.</LINE>
1964 </SPEECH>
1965
1966 <SPEECH>
1967 <SPEAKER>HAMLET</SPEAKER>
1968 <LINE>Indeed, upon my sword, indeed.</LINE>
1969 </SPEECH>
1970
1971 <SPEECH>
1972 <SPEAKER>Ghost</SPEAKER>
1973 <LINE><STAGEDIR>Beneath</STAGEDIR> Swear.</LINE>
1974 </SPEECH>
1975
1976 <SPEECH>
1977 <SPEAKER>HAMLET</SPEAKER>
1978 <LINE>Ah, ha, boy! say'st thou so? art thou there,</LINE>
1979 <LINE>truepenny?</LINE>
1980 <LINE>Come on--you hear this fellow in the cellarage--</LINE>
1981 <LINE>Consent to swear.</LINE>
1982 </SPEECH>
1983
1984 <SPEECH>
1985 <SPEAKER>HORATIO</SPEAKER>
1986 <LINE>Propose the oath, my lord.</LINE>
1987 </SPEECH>
1988
1989 <SPEECH>
1990 <SPEAKER>HAMLET</SPEAKER>
1991 <LINE>Never to speak of this that you have seen,</LINE>
1992 <LINE>Swear by my sword.</LINE>
1993 </SPEECH>
1994
1995 <SPEECH>
1996 <SPEAKER>Ghost</SPEAKER>
1997 <LINE><STAGEDIR>Beneath</STAGEDIR> Swear.</LINE>
1998 </SPEECH>
1999
2000 <SPEECH>
2001 <SPEAKER>HAMLET</SPEAKER>
2002 <LINE>Hic et ubique? then we'll shift our ground.</LINE>
2003 <LINE>Come hither, gentlemen,</LINE>
2004 <LINE>And lay your hands again upon my sword:</LINE>
2005 <LINE>Never to speak of this that you have heard,</LINE>
2006 <LINE>Swear by my sword.</LINE>
2007 </SPEECH>
2008
2009 <SPEECH>
2010 <SPEAKER>Ghost</SPEAKER>
2011 <LINE><STAGEDIR>Beneath</STAGEDIR> Swear.</LINE>
2012 </SPEECH>
2013
2014 <SPEECH>
2015 <SPEAKER>HAMLET</SPEAKER>
2016 <LINE>Well said, old mole! canst work i' the earth so fast?</LINE>
2017 <LINE>A worthy pioner! Once more remove, good friends.</LINE>
2018 </SPEECH>
2019
2020 <SPEECH>
2021 <SPEAKER>HORATIO</SPEAKER>
2022 <LINE>O day and night, but this is wondrous strange!</LINE>
2023 </SPEECH>
2024
2025 <SPEECH>
2026 <SPEAKER>HAMLET</SPEAKER>
2027 <LINE>And therefore as a stranger give it welcome.</LINE>
2028 <LINE>There are more things in heaven and earth, Horatio,</LINE>
2029 <LINE>Than are dreamt of in your philosophy. But come;</LINE>
2030 <LINE>Here, as before, never, so help you mercy,</LINE>
2031 <LINE>How strange or odd soe'er I bear myself,</LINE>
2032 <LINE>As I perchance hereafter shall think meet</LINE>
2033 <LINE>To put an antic disposition on,</LINE>
2034 <LINE>That you, at such times seeing me, never shall,</LINE>
2035 <LINE>With arms encumber'd thus, or this headshake,</LINE>
2036 <LINE>Or by pronouncing of some doubtful phrase,</LINE>
2037 <LINE>As 'Well, well, we know,' or 'We could, an if we would,'</LINE>
2038 <LINE>Or 'If we list to speak,' or 'There be, an if they might,'</LINE>
2039 <LINE>Or such ambiguous giving out, to note</LINE>
2040 <LINE>That you know aught of me: this not to do,</LINE>
2041 <LINE>So grace and mercy at your most need help you, Swear.</LINE>
2042 </SPEECH>
2043
2044 <SPEECH>
2045 <SPEAKER>Ghost</SPEAKER>
2046 <LINE><STAGEDIR>Beneath</STAGEDIR> Swear.</LINE>
2047 </SPEECH>
2048
2049 <SPEECH>
2050 <SPEAKER>HAMLET</SPEAKER>
2051 <LINE>Rest, rest, perturbed spirit!</LINE>
2052 <STAGEDIR>They swear</STAGEDIR>
2053 <LINE>So, gentlemen,</LINE>
2054 <LINE>With all my love I do commend me to you:</LINE>
2055 <LINE>And what so poor a man as Hamlet is</LINE>
2056 <LINE>May do, to express his love and friending to you,</LINE>
2057 <LINE>God willing, shall not lack. Let us go in together;</LINE>
2058 <LINE>And still your fingers on your lips, I pray.</LINE>
2059 <LINE>The time is out of joint: O cursed spite,</LINE>
2060 <LINE>That ever I was born to set it right!</LINE>
2061 <LINE>Nay, come, let's go together.</LINE>
2062 </SPEECH>
2063
2064
2065 <STAGEDIR>Exeunt</STAGEDIR>
2066 </SCENE>
2067
2068 </ACT>
2069
2070 <ACT><TITLE>ACT II</TITLE>
2071
2072 <SCENE><TITLE>SCENE I. A room in POLONIUS' house.</TITLE>
2073 <STAGEDIR>Enter POLONIUS and REYNALDO</STAGEDIR>
2074
2075 <SPEECH>
2076 <SPEAKER>LORD POLONIUS</SPEAKER>
2077 <LINE>Give him this money and these notes, Reynaldo.</LINE>
2078 </SPEECH>
2079
2080 <SPEECH>
2081 <SPEAKER>REYNALDO</SPEAKER>
2082 <LINE>I will, my lord.</LINE>
2083 </SPEECH>
2084
2085 <SPEECH>
2086 <SPEAKER>LORD POLONIUS</SPEAKER>
2087 <LINE>You shall do marvellous wisely, good Reynaldo,</LINE>
2088 <LINE>Before you visit him, to make inquire</LINE>
2089 <LINE>Of his behavior.</LINE>
2090 </SPEECH>
2091
2092 <SPEECH>
2093 <SPEAKER>REYNALDO</SPEAKER>
2094 <LINE>My lord, I did intend it.</LINE>
2095 </SPEECH>
2096
2097 <SPEECH>
2098 <SPEAKER>LORD POLONIUS</SPEAKER>
2099 <LINE>Marry, well said; very well said. Look you, sir,</LINE>
2100 <LINE>Inquire me first what Danskers are in Paris;</LINE>
2101 <LINE>And how, and who, what means, and where they keep,</LINE>
2102 <LINE>What company, at what expense; and finding</LINE>
2103 <LINE>By this encompassment and drift of question</LINE>
2104 <LINE>That they do know my son, come you more nearer</LINE>
2105 <LINE>Than your particular demands will touch it:</LINE>
2106 <LINE>Take you, as 'twere, some distant knowledge of him;</LINE>
2107 <LINE>As thus, 'I know his father and his friends,</LINE>
2108 <LINE>And in part him: ' do you mark this, Reynaldo?</LINE>
2109 </SPEECH>
2110
2111 <SPEECH>
2112 <SPEAKER>REYNALDO</SPEAKER>
2113 <LINE>Ay, very well, my lord.</LINE>
2114 </SPEECH>
2115
2116 <SPEECH>
2117 <SPEAKER>LORD POLONIUS</SPEAKER>
2118 <LINE>'And in part him; but' you may say 'not well:</LINE>
2119 <LINE>But, if't be he I mean, he's very wild;</LINE>
2120 <LINE>Addicted so and so:' and there put on him</LINE>
2121 <LINE>What forgeries you please; marry, none so rank</LINE>
2122 <LINE>As may dishonour him; take heed of that;</LINE>
2123 <LINE>But, sir, such wanton, wild and usual slips</LINE>
2124 <LINE>As are companions noted and most known</LINE>
2125 <LINE>To youth and liberty.</LINE>
2126 </SPEECH>
2127
2128 <SPEECH>
2129 <SPEAKER>REYNALDO</SPEAKER>
2130 <LINE>As gaming, my lord.</LINE>
2131 </SPEECH>
2132
2133 <SPEECH>
2134 <SPEAKER>LORD POLONIUS</SPEAKER>
2135 <LINE>Ay, or drinking, fencing, swearing, quarrelling,</LINE>
2136 <LINE>Drabbing: you may go so far.</LINE>
2137 </SPEECH>
2138
2139 <SPEECH>
2140 <SPEAKER>REYNALDO</SPEAKER>
2141 <LINE>My lord, that would dishonour him.</LINE>
2142 </SPEECH>
2143
2144 <SPEECH>
2145 <SPEAKER>LORD POLONIUS</SPEAKER>
2146 <LINE>'Faith, no; as you may season it in the charge</LINE>
2147 <LINE>You must not put another scandal on him,</LINE>
2148 <LINE>That he is open to incontinency;</LINE>
2149 <LINE>That's not my meaning: but breathe his faults so quaintly</LINE>
2150 <LINE>That they may seem the taints of liberty,</LINE>
2151 <LINE>The flash and outbreak of a fiery mind,</LINE>
2152 <LINE>A savageness in unreclaimed blood,</LINE>
2153 <LINE>Of general assault.</LINE>
2154 </SPEECH>
2155
2156 <SPEECH>
2157 <SPEAKER>REYNALDO</SPEAKER>
2158 <LINE>But, my good lord,--</LINE>
2159 </SPEECH>
2160
2161 <SPEECH>
2162 <SPEAKER>LORD POLONIUS</SPEAKER>
2163 <LINE>Wherefore should you do this?</LINE>
2164 </SPEECH>
2165
2166 <SPEECH>
2167 <SPEAKER>REYNALDO</SPEAKER>
2168 <LINE>Ay, my lord,</LINE>
2169 <LINE>I would know that.</LINE>
2170 </SPEECH>
2171
2172 <SPEECH>
2173 <SPEAKER>LORD POLONIUS</SPEAKER>
2174 <LINE>Marry, sir, here's my drift;</LINE>
2175 <LINE>And I believe, it is a fetch of wit:</LINE>
2176 <LINE>You laying these slight sullies on my son,</LINE>
2177 <LINE>As 'twere a thing a little soil'd i' the working, Mark you,</LINE>
2178 <LINE>Your party in converse, him you would sound,</LINE>
2179 <LINE>Having ever seen in the prenominate crimes</LINE>
2180 <LINE>The youth you breathe of guilty, be assured</LINE>
2181 <LINE>He closes with you in this consequence;</LINE>
2182 <LINE>'Good sir,' or so, or 'friend,' or 'gentleman,'</LINE>
2183 <LINE>According to the phrase or the addition</LINE>
2184 <LINE>Of man and country.</LINE>
2185 </SPEECH>
2186
2187 <SPEECH>
2188 <SPEAKER>REYNALDO</SPEAKER>
2189 <LINE>Very good, my lord.</LINE>
2190 </SPEECH>
2191
2192 <SPEECH>
2193 <SPEAKER>LORD POLONIUS</SPEAKER>
2194 <LINE>And then, sir, does he this--he does--what was I</LINE>
2195 <LINE>about to say? By the mass, I was about to say</LINE>
2196 <LINE>something: where did I leave?</LINE>
2197 </SPEECH>
2198
2199 <SPEECH>
2200 <SPEAKER>REYNALDO</SPEAKER>
2201 <LINE>At 'closes in the consequence,' at 'friend or so,'</LINE>
2202 <LINE>and 'gentleman.'</LINE>
2203 </SPEECH>
2204
2205 <SPEECH>
2206 <SPEAKER>LORD POLONIUS</SPEAKER>
2207 <LINE>At 'closes in the consequence,' ay, marry;</LINE>
2208 <LINE>He closes thus: 'I know the gentleman;</LINE>
2209 <LINE>I saw him yesterday, or t' other day,</LINE>
2210 <LINE>Or then, or then; with such, or such; and, as you say,</LINE>
2211 <LINE>There was a' gaming; there o'ertook in's rouse;</LINE>
2212 <LINE>There falling out at tennis:' or perchance,</LINE>
2213 <LINE>'I saw him enter such a house of sale,'</LINE>
2214 <LINE>Videlicet, a brothel, or so forth.</LINE>
2215 <LINE>See you now;</LINE>
2216 <LINE>Your bait of falsehood takes this carp of truth:</LINE>
2217 <LINE>And thus do we of wisdom and of reach,</LINE>
2218 <LINE>With windlasses and with assays of bias,</LINE>
2219 <LINE>By indirections find directions out:</LINE>
2220 <LINE>So by my former lecture and advice,</LINE>
2221 <LINE>Shall you my son. You have me, have you not?</LINE>
2222 </SPEECH>
2223
2224 <SPEECH>
2225 <SPEAKER>REYNALDO</SPEAKER>
2226 <LINE>My lord, I have.</LINE>
2227 </SPEECH>
2228
2229 <SPEECH>
2230 <SPEAKER>LORD POLONIUS</SPEAKER>
2231 <LINE>God be wi' you; fare you well.</LINE>
2232 </SPEECH>
2233
2234 <SPEECH>
2235 <SPEAKER>REYNALDO</SPEAKER>
2236 <LINE>Good my lord!</LINE>
2237 </SPEECH>
2238
2239 <SPEECH>
2240 <SPEAKER>LORD POLONIUS</SPEAKER>
2241 <LINE>Observe his inclination in yourself.</LINE>
2242 </SPEECH>
2243
2244 <SPEECH>
2245 <SPEAKER>REYNALDO</SPEAKER>
2246 <LINE>I shall, my lord.</LINE>
2247 </SPEECH>
2248
2249 <SPEECH>
2250 <SPEAKER>LORD POLONIUS</SPEAKER>
2251 <LINE>And let him ply his music.</LINE>
2252 </SPEECH>
2253
2254 <SPEECH>
2255 <SPEAKER>REYNALDO</SPEAKER>
2256 <LINE>Well, my lord.</LINE>
2257 </SPEECH>
2258
2259 <SPEECH>
2260 <SPEAKER>LORD POLONIUS</SPEAKER>
2261 <LINE>Farewell!</LINE>
2262 <STAGEDIR>Exit REYNALDO</STAGEDIR>
2263 <STAGEDIR>Enter OPHELIA</STAGEDIR>
2264 <LINE>How now, Ophelia! what's the matter?</LINE>
2265 </SPEECH>
2266
2267 <SPEECH>
2268 <SPEAKER>OPHELIA</SPEAKER>
2269 <LINE>O, my lord, my lord, I have been so affrighted!</LINE>
2270 </SPEECH>
2271
2272 <SPEECH>
2273 <SPEAKER>LORD POLONIUS</SPEAKER>
2274 <LINE>With what, i' the name of God?</LINE>
2275 </SPEECH>
2276
2277 <SPEECH>
2278 <SPEAKER>OPHELIA</SPEAKER>
2279 <LINE>My lord, as I was sewing in my closet,</LINE>
2280 <LINE>Lord Hamlet, with his doublet all unbraced;</LINE>
2281 <LINE>No hat upon his head; his stockings foul'd,</LINE>
2282 <LINE>Ungarter'd, and down-gyved to his ancle;</LINE>
2283 <LINE>Pale as his shirt; his knees knocking each other;</LINE>
2284 <LINE>And with a look so piteous in purport</LINE>
2285 <LINE>As if he had been loosed out of hell</LINE>
2286 <LINE>To speak of horrors,--he comes before me.</LINE>
2287 </SPEECH>
2288
2289 <SPEECH>
2290 <SPEAKER>LORD POLONIUS</SPEAKER>
2291 <LINE>Mad for thy love?</LINE>
2292 </SPEECH>
2293
2294 <SPEECH>
2295 <SPEAKER>OPHELIA</SPEAKER>
2296 <LINE>My lord, I do not know;</LINE>
2297 <LINE>But truly, I do fear it.</LINE>
2298 </SPEECH>
2299
2300 <SPEECH>
2301 <SPEAKER>LORD POLONIUS</SPEAKER>
2302 <LINE>What said he?</LINE>
2303 </SPEECH>
2304
2305 <SPEECH>
2306 <SPEAKER>OPHELIA</SPEAKER>
2307 <LINE>He took me by the wrist and held me hard;</LINE>
2308 <LINE>Then goes he to the length of all his arm;</LINE>
2309 <LINE>And, with his other hand thus o'er his brow,</LINE>
2310 <LINE>He falls to such perusal of my face</LINE>
2311 <LINE>As he would draw it. Long stay'd he so;</LINE>
2312 <LINE>At last, a little shaking of mine arm</LINE>
2313 <LINE>And thrice his head thus waving up and down,</LINE>
2314 <LINE>He raised a sigh so piteous and profound</LINE>
2315 <LINE>As it did seem to shatter all his bulk</LINE>
2316 <LINE>And end his being: that done, he lets me go:</LINE>
2317 <LINE>And, with his head over his shoulder turn'd,</LINE>
2318 <LINE>He seem'd to find his way without his eyes;</LINE>
2319 <LINE>For out o' doors he went without their helps,</LINE>
2320 <LINE>And, to the last, bended their light on me.</LINE>
2321 </SPEECH>
2322
2323 <SPEECH>
2324 <SPEAKER>LORD POLONIUS</SPEAKER>
2325 <LINE>Come, go with me: I will go seek the king.</LINE>
2326 <LINE>This is the very ecstasy of love,</LINE>
2327 <LINE>Whose violent property fordoes itself</LINE>
2328 <LINE>And leads the will to desperate undertakings</LINE>
2329 <LINE>As oft as any passion under heaven</LINE>
2330 <LINE>That does afflict our natures. I am sorry.</LINE>
2331 <LINE>What, have you given him any hard words of late?</LINE>
2332 </SPEECH>
2333
2334 <SPEECH>
2335 <SPEAKER>OPHELIA</SPEAKER>
2336 <LINE>No, my good lord, but, as you did command,</LINE>
2337 <LINE>I did repel his fetters and denied</LINE>
2338 <LINE>His access to me.</LINE>
2339 </SPEECH>
2340
2341 <SPEECH>
2342 <SPEAKER>LORD POLONIUS</SPEAKER>
2343 <LINE>That hath made him mad.</LINE>
2344 <LINE>I am sorry that with better heed and judgment</LINE>
2345 <LINE>I had not quoted him: I fear'd he did but trifle,</LINE>
2346 <LINE>And meant to wreck thee; but, beshrew my jealousy!</LINE>
2347 <LINE>By heaven, it is as proper to our age</LINE>
2348 <LINE>To cast beyond ourselves in our opinions</LINE>
2349 <LINE>As it is common for the younger sort</LINE>
2350 <LINE>To lack discretion. Come, go we to the king:</LINE>
2351 <LINE>This must be known; which, being kept close, might</LINE>
2352 <LINE>move</LINE>
2353 <LINE>More grief to hide than hate to utter love.</LINE>
2354 </SPEECH>
2355
2356
2357 <STAGEDIR>Exeunt</STAGEDIR>
2358 </SCENE>
2359
2360 <SCENE><TITLE>SCENE II. A room in the castle.</TITLE>
2361 <STAGEDIR>Enter KING CLAUDIUS, QUEEN GERTRUDE, ROSENCRANTZ,
2362 GUILDENSTERN, and Attendants</STAGEDIR>
2363
2364 <SPEECH>
2365 <SPEAKER>KING CLAUDIUS</SPEAKER>
2366 <LINE>Welcome, dear Rosencrantz and Guildenstern!</LINE>
2367 <LINE>Moreover that we much did long to see you,</LINE>
2368 <LINE>The need we have to use you did provoke</LINE>
2369 <LINE>Our hasty sending. Something have you heard</LINE>
2370 <LINE>Of Hamlet's transformation; so call it,</LINE>
2371 <LINE>Sith nor the exterior nor the inward man</LINE>
2372 <LINE>Resembles that it was. What it should be,</LINE>
2373 <LINE>More than his father's death, that thus hath put him</LINE>
2374 <LINE>So much from the understanding of himself,</LINE>
2375 <LINE>I cannot dream of: I entreat you both,</LINE>
2376 <LINE>That, being of so young days brought up with him,</LINE>
2377 <LINE>And sith so neighbour'd to his youth and havior,</LINE>
2378 <LINE>That you vouchsafe your rest here in our court</LINE>
2379 <LINE>Some little time: so by your companies</LINE>
2380 <LINE>To draw him on to pleasures, and to gather,</LINE>
2381 <LINE>So much as from occasion you may glean,</LINE>
2382 <LINE>Whether aught, to us unknown, afflicts him thus,</LINE>
2383 <LINE>That, open'd, lies within our remedy.</LINE>
2384 </SPEECH>
2385
2386 <SPEECH>
2387 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
2388 <LINE>Good gentlemen, he hath much talk'd of you;</LINE>
2389 <LINE>And sure I am two men there are not living</LINE>
2390 <LINE>To whom he more adheres. If it will please you</LINE>
2391 <LINE>To show us so much gentry and good will</LINE>
2392 <LINE>As to expend your time with us awhile,</LINE>
2393 <LINE>For the supply and profit of our hope,</LINE>
2394 <LINE>Your visitation shall receive such thanks</LINE>
2395 <LINE>As fits a king's remembrance.</LINE>
2396 </SPEECH>
2397
2398 <SPEECH>
2399 <SPEAKER>ROSENCRANTZ</SPEAKER>
2400 <LINE>Both your majesties</LINE>
2401 <LINE>Might, by the sovereign power you have of us,</LINE>
2402 <LINE>Put your dread pleasures more into command</LINE>
2403 <LINE>Than to entreaty.</LINE>
2404 </SPEECH>
2405
2406 <SPEECH>
2407 <SPEAKER>GUILDENSTERN</SPEAKER>
2408 <LINE>But we both obey,</LINE>
2409 <LINE>And here give up ourselves, in the full bent</LINE>
2410 <LINE>To lay our service freely at your feet,</LINE>
2411 <LINE>To be commanded.</LINE>
2412 </SPEECH>
2413
2414 <SPEECH>
2415 <SPEAKER>KING CLAUDIUS</SPEAKER>
2416 <LINE>Thanks, Rosencrantz and gentle Guildenstern.</LINE>
2417 </SPEECH>
2418
2419 <SPEECH>
2420 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
2421 <LINE>Thanks, Guildenstern and gentle Rosencrantz:</LINE>
2422 <LINE>And I beseech you instantly to visit</LINE>
2423 <LINE>My too much changed son. Go, some of you,</LINE>
2424 <LINE>And bring these gentlemen where Hamlet is.</LINE>
2425 </SPEECH>
2426
2427 <SPEECH>
2428 <SPEAKER>GUILDENSTERN</SPEAKER>
2429 <LINE>Heavens make our presence and our practises</LINE>
2430 <LINE>Pleasant and helpful to him!</LINE>
2431 </SPEECH>
2432
2433 <SPEECH>
2434 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
2435 <LINE>Ay, amen!</LINE>
2436 </SPEECH>
2437
2438 <STAGEDIR>Exeunt ROSENCRANTZ, GUILDENSTERN, and some
2439 Attendants</STAGEDIR>
2440 <STAGEDIR>Enter POLONIUS</STAGEDIR>
2441
2442 <SPEECH>
2443 <SPEAKER>LORD POLONIUS</SPEAKER>
2444 <LINE>The ambassadors from Norway, my good lord,</LINE>
2445 <LINE>Are joyfully return'd.</LINE>
2446 </SPEECH>
2447
2448 <SPEECH>
2449 <SPEAKER>KING CLAUDIUS</SPEAKER>
2450 <LINE>Thou still hast been the father of good news.</LINE>
2451 </SPEECH>
2452
2453 <SPEECH>
2454 <SPEAKER>LORD POLONIUS</SPEAKER>
2455 <LINE>Have I, my lord? I assure my good liege,</LINE>
2456 <LINE>I hold my duty, as I hold my soul,</LINE>
2457 <LINE>Both to my God and to my gracious king:</LINE>
2458 <LINE>And I do think, or else this brain of mine</LINE>
2459 <LINE>Hunts not the trail of policy so sure</LINE>
2460 <LINE>As it hath used to do, that I have found</LINE>
2461 <LINE>The very cause of Hamlet's lunacy.</LINE>
2462 </SPEECH>
2463
2464 <SPEECH>
2465 <SPEAKER>KING CLAUDIUS</SPEAKER>
2466 <LINE>O, speak of that; that do I long to hear.</LINE>
2467 </SPEECH>
2468
2469 <SPEECH>
2470 <SPEAKER>LORD POLONIUS</SPEAKER>
2471 <LINE>Give first admittance to the ambassadors;</LINE>
2472 <LINE>My news shall be the fruit to that great feast.</LINE>
2473 </SPEECH>
2474
2475 <SPEECH>
2476 <SPEAKER>KING CLAUDIUS</SPEAKER>
2477 <LINE>Thyself do grace to them, and bring them in.</LINE>
2478 <STAGEDIR>Exit POLONIUS</STAGEDIR>
2479 <LINE>He tells me, my dear Gertrude, he hath found</LINE>
2480 <LINE>The head and source of all your son's distemper.</LINE>
2481 </SPEECH>
2482
2483 <SPEECH>
2484 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
2485 <LINE>I doubt it is no other but the main;</LINE>
2486 <LINE>His father's death, and our o'erhasty marriage.</LINE>
2487 </SPEECH>
2488
2489 <SPEECH>
2490 <SPEAKER>KING CLAUDIUS</SPEAKER>
2491 <LINE>Well, we shall sift him.</LINE>
2492 <STAGEDIR>Re-enter POLONIUS, with VOLTIMAND and CORNELIUS</STAGEDIR>
2493 <LINE>Welcome, my good friends!</LINE>
2494 <LINE>Say, Voltimand, what from our brother Norway?</LINE>
2495 </SPEECH>
2496
2497 <SPEECH>
2498 <SPEAKER>VOLTIMAND</SPEAKER>
2499 <LINE>Most fair return of greetings and desires.</LINE>
2500 <LINE>Upon our first, he sent out to suppress</LINE>
2501 <LINE>His nephew's levies; which to him appear'd</LINE>
2502 <LINE>To be a preparation 'gainst the Polack;</LINE>
2503 <LINE>But, better look'd into, he truly found</LINE>
2504 <LINE>It was against your highness: whereat grieved,</LINE>
2505 <LINE>That so his sickness, age and impotence</LINE>
2506 <LINE>Was falsely borne in hand, sends out arrests</LINE>
2507 <LINE>On Fortinbras; which he, in brief, obeys;</LINE>
2508 <LINE>Receives rebuke from Norway, and in fine</LINE>
2509 <LINE>Makes vow before his uncle never more</LINE>
2510 <LINE>To give the assay of arms against your majesty.</LINE>
2511 <LINE>Whereon old Norway, overcome with joy,</LINE>
2512 <LINE>Gives him three thousand crowns in annual fee,</LINE>
2513 <LINE>And his commission to employ those soldiers,</LINE>
2514 <LINE>So levied as before, against the Polack:</LINE>
2515 <LINE>With an entreaty, herein further shown,</LINE>
2516 <STAGEDIR>Giving a paper</STAGEDIR>
2517 <LINE>That it might please you to give quiet pass</LINE>
2518 <LINE>Through your dominions for this enterprise,</LINE>
2519 <LINE>On such regards of safety and allowance</LINE>
2520 <LINE>As therein are set down.</LINE>
2521 </SPEECH>
2522
2523 <SPEECH>
2524 <SPEAKER>KING CLAUDIUS</SPEAKER>
2525 <LINE>It likes us well;</LINE>
2526 <LINE>And at our more consider'd time well read,</LINE>
2527 <LINE>Answer, and think upon this business.</LINE>
2528 <LINE>Meantime we thank you for your well-took labour:</LINE>
2529 <LINE>Go to your rest; at night we'll feast together:</LINE>
2530 <LINE>Most welcome home!</LINE>
2531 </SPEECH>
2532
2533
2534 <STAGEDIR>Exeunt VOLTIMAND and CORNELIUS</STAGEDIR>
2535
2536 <SPEECH>
2537 <SPEAKER>LORD POLONIUS</SPEAKER>
2538 <LINE>This business is well ended.</LINE>
2539 <LINE>My liege, and madam, to expostulate</LINE>
2540 <LINE>What majesty should be, what duty is,</LINE>
2541 <LINE>Why day is day, night night, and time is time,</LINE>
2542 <LINE>Were nothing but to waste night, day and time.</LINE>
2543 <LINE>Therefore, since brevity is the soul of wit,</LINE>
2544 <LINE>And tediousness the limbs and outward flourishes,</LINE>
2545 <LINE>I will be brief: your noble son is mad:</LINE>
2546 <LINE>Mad call I it; for, to define true madness,</LINE>
2547 <LINE>What is't but to be nothing else but mad?</LINE>
2548 <LINE>But let that go.</LINE>
2549 </SPEECH>
2550
2551 <SPEECH>
2552 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
2553 <LINE>More matter, with less art.</LINE>
2554 </SPEECH>
2555
2556 <SPEECH>
2557 <SPEAKER>LORD POLONIUS</SPEAKER>
2558 <LINE>Madam, I swear I use no art at all.</LINE>
2559 <LINE>That he is mad, 'tis true: 'tis true 'tis pity;</LINE>
2560 <LINE>And pity 'tis 'tis true: a foolish figure;</LINE>
2561 <LINE>But farewell it, for I will use no art.</LINE>
2562 <LINE>Mad let us grant him, then: and now remains</LINE>
2563 <LINE>That we find out the cause of this effect,</LINE>
2564 <LINE>Or rather say, the cause of this defect,</LINE>
2565 <LINE>For this effect defective comes by cause:</LINE>
2566 <LINE>Thus it remains, and the remainder thus. Perpend.</LINE>
2567 <LINE>I have a daughter--have while she is mine--</LINE>
2568 <LINE>Who, in her duty and obedience, mark,</LINE>
2569 <LINE>Hath given me this: now gather, and surmise.</LINE>
2570 <STAGEDIR>Reads</STAGEDIR>
2571 <LINE>'To the celestial and my soul's idol, the most</LINE>
2572 <LINE>beautified Ophelia,'--</LINE>
2573 <LINE>That's an ill phrase, a vile phrase; 'beautified' is</LINE>
2574 <LINE>a vile phrase: but you shall hear. Thus:</LINE>
2575 <STAGEDIR>Reads</STAGEDIR>
2576 <LINE>'In her excellent white bosom, these, &amp;c.'</LINE>
2577 </SPEECH>
2578
2579 <SPEECH>
2580 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
2581 <LINE>Came this from Hamlet to her?</LINE>
2582 </SPEECH>
2583
2584 <SPEECH>
2585 <SPEAKER>LORD POLONIUS</SPEAKER>
2586 <LINE>Good madam, stay awhile; I will be faithful.</LINE>
2587 <STAGEDIR>Reads</STAGEDIR>
2588 <LINE>'Doubt thou the stars are fire;</LINE>
2589 <LINE>Doubt that the sun doth move;</LINE>
2590 <LINE>Doubt truth to be a liar;</LINE>
2591 <LINE>But never doubt I love.</LINE>
2592 <LINE>'O dear Ophelia, I am ill at these numbers;</LINE>
2593 <LINE>I have not art to reckon my groans: but that</LINE>
2594 <LINE>I love thee best, O most best, believe it. Adieu.</LINE>
2595 <LINE>'Thine evermore most dear lady, whilst</LINE>
2596 <LINE>this machine is to him, HAMLET.'</LINE>
2597 <LINE>This, in obedience, hath my daughter shown me,</LINE>
2598 <LINE>And more above, hath his solicitings,</LINE>
2599 <LINE>As they fell out by time, by means and place,</LINE>
2600 <LINE>All given to mine ear.</LINE>
2601 </SPEECH>
2602
2603 <SPEECH>
2604 <SPEAKER>KING CLAUDIUS</SPEAKER>
2605 <LINE>But how hath she</LINE>
2606 <LINE>Received his love?</LINE>
2607 </SPEECH>
2608
2609 <SPEECH>
2610 <SPEAKER>LORD POLONIUS</SPEAKER>
2611 <LINE>What do you think of me?</LINE>
2612 </SPEECH>
2613
2614 <SPEECH>
2615 <SPEAKER>KING CLAUDIUS</SPEAKER>
2616 <LINE>As of a man faithful and honourable.</LINE>
2617 </SPEECH>
2618
2619 <SPEECH>
2620 <SPEAKER>LORD POLONIUS</SPEAKER>
2621 <LINE>I would fain prove so. But what might you think,</LINE>
2622 <LINE>When I had seen this hot love on the wing--</LINE>
2623 <LINE>As I perceived it, I must tell you that,</LINE>
2624 <LINE>Before my daughter told me--what might you,</LINE>
2625 <LINE>Or my dear majesty your queen here, think,</LINE>
2626 <LINE>If I had play'd the desk or table-book,</LINE>
2627 <LINE>Or given my heart a winking, mute and dumb,</LINE>
2628 <LINE>Or look'd upon this love with idle sight;</LINE>
2629 <LINE>What might you think? No, I went round to work,</LINE>
2630 <LINE>And my young mistress thus I did bespeak:</LINE>
2631 <LINE>'Lord Hamlet is a prince, out of thy star;</LINE>
2632 <LINE>This must not be:' and then I precepts gave her,</LINE>
2633 <LINE>That she should lock herself from his resort,</LINE>
2634 <LINE>Admit no messengers, receive no tokens.</LINE>
2635 <LINE>Which done, she took the fruits of my advice;</LINE>
2636 <LINE>And he, repulsed--a short tale to make--</LINE>
2637 <LINE>Fell into a sadness, then into a fast,</LINE>
2638 <LINE>Thence to a watch, thence into a weakness,</LINE>
2639 <LINE>Thence to a lightness, and, by this declension,</LINE>
2640 <LINE>Into the madness wherein now he raves,</LINE>
2641 <LINE>And all we mourn for.</LINE>
2642 </SPEECH>
2643
2644 <SPEECH>
2645 <SPEAKER>KING CLAUDIUS</SPEAKER>
2646 <LINE>Do you think 'tis this?</LINE>
2647 </SPEECH>
2648
2649 <SPEECH>
2650 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
2651 <LINE>It may be, very likely.</LINE>
2652 </SPEECH>
2653
2654 <SPEECH>
2655 <SPEAKER>LORD POLONIUS</SPEAKER>
2656 <LINE>Hath there been such a time--I'd fain know that--</LINE>
2657 <LINE>That I have positively said 'Tis so,'</LINE>
2658 <LINE>When it proved otherwise?</LINE>
2659 </SPEECH>
2660
2661 <SPEECH>
2662 <SPEAKER>KING CLAUDIUS</SPEAKER>
2663 <LINE>Not that I know.</LINE>
2664 </SPEECH>
2665
2666 <SPEECH>
2667 <SPEAKER>LORD POLONIUS</SPEAKER>
2668 <LINE><STAGEDIR>Pointing to his head and shoulder</STAGEDIR></LINE>
2669 <LINE>Take this from this, if this be otherwise:</LINE>
2670 <LINE>If circumstances lead me, I will find</LINE>
2671 <LINE>Where truth is hid, though it were hid indeed</LINE>
2672 <LINE>Within the centre.</LINE>
2673 </SPEECH>
2674
2675 <SPEECH>
2676 <SPEAKER>KING CLAUDIUS</SPEAKER>
2677 <LINE>How may we try it further?</LINE>
2678 </SPEECH>
2679
2680 <SPEECH>
2681 <SPEAKER>LORD POLONIUS</SPEAKER>
2682 <LINE>You know, sometimes he walks four hours together</LINE>
2683 <LINE>Here in the lobby.</LINE>
2684 </SPEECH>
2685
2686 <SPEECH>
2687 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
2688 <LINE>So he does indeed.</LINE>
2689 </SPEECH>
2690
2691 <SPEECH>
2692 <SPEAKER>LORD POLONIUS</SPEAKER>
2693 <LINE>At such a time I'll loose my daughter to him:</LINE>
2694 <LINE>Be you and I behind an arras then;</LINE>
2695 <LINE>Mark the encounter: if he love her not</LINE>
2696 <LINE>And be not from his reason fall'n thereon,</LINE>
2697 <LINE>Let me be no assistant for a state,</LINE>
2698 <LINE>But keep a farm and carters.</LINE>
2699 </SPEECH>
2700
2701 <SPEECH>
2702 <SPEAKER>KING CLAUDIUS</SPEAKER>
2703 <LINE>We will try it.</LINE>
2704 </SPEECH>
2705
2706 <SPEECH>
2707 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
2708 <LINE>But, look, where sadly the poor wretch comes reading.</LINE>
2709 </SPEECH>
2710
2711 <SPEECH>
2712 <SPEAKER>LORD POLONIUS</SPEAKER>
2713 <LINE>Away, I do beseech you, both away:</LINE>
2714 <LINE>I'll board him presently.</LINE>
2715 <STAGEDIR>Exeunt KING CLAUDIUS, QUEEN GERTRUDE, and
2716 Attendants</STAGEDIR>
2717 <STAGEDIR>Enter HAMLET, reading</STAGEDIR>
2718 <LINE>O, give me leave:</LINE>
2719 <LINE>How does my good Lord Hamlet?</LINE>
2720 </SPEECH>
2721
2722 <SPEECH>
2723 <SPEAKER>HAMLET</SPEAKER>
2724 <LINE>Well, God-a-mercy.</LINE>
2725 </SPEECH>
2726
2727 <SPEECH>
2728 <SPEAKER>LORD POLONIUS</SPEAKER>
2729 <LINE>Do you know me, my lord?</LINE>
2730 </SPEECH>
2731
2732 <SPEECH>
2733 <SPEAKER>HAMLET</SPEAKER>
2734 <LINE>Excellent well; you are a fishmonger.</LINE>
2735 </SPEECH>
2736
2737 <SPEECH>
2738 <SPEAKER>LORD POLONIUS</SPEAKER>
2739 <LINE>Not I, my lord.</LINE>
2740 </SPEECH>
2741
2742 <SPEECH>
2743 <SPEAKER>HAMLET</SPEAKER>
2744 <LINE>Then I would you were so honest a man.</LINE>
2745 </SPEECH>
2746
2747 <SPEECH>
2748 <SPEAKER>LORD POLONIUS</SPEAKER>
2749 <LINE>Honest, my lord!</LINE>
2750 </SPEECH>
2751
2752 <SPEECH>
2753 <SPEAKER>HAMLET</SPEAKER>
2754 <LINE>Ay, sir; to be honest, as this world goes, is to be</LINE>
2755 <LINE>one man picked out of ten thousand.</LINE>
2756 </SPEECH>
2757
2758 <SPEECH>
2759 <SPEAKER>LORD POLONIUS</SPEAKER>
2760 <LINE>That's very true, my lord.</LINE>
2761 </SPEECH>
2762
2763 <SPEECH>
2764 <SPEAKER>HAMLET</SPEAKER>
2765 <LINE>For if the sun breed maggots in a dead dog, being a</LINE>
2766 <LINE>god kissing carrion,--Have you a daughter?</LINE>
2767 </SPEECH>
2768
2769 <SPEECH>
2770 <SPEAKER>LORD POLONIUS</SPEAKER>
2771 <LINE>I have, my lord.</LINE>
2772 </SPEECH>
2773
2774 <SPEECH>
2775 <SPEAKER>HAMLET</SPEAKER>
2776 <LINE>Let her not walk i' the sun: conception is a</LINE>
2777 <LINE>blessing: but not as your daughter may conceive.</LINE>
2778 <LINE>Friend, look to 't.</LINE>
2779 </SPEECH>
2780
2781 <SPEECH>
2782 <SPEAKER>LORD POLONIUS</SPEAKER>
2783 <LINE><STAGEDIR>Aside</STAGEDIR> How say you by that? Still harping on my</LINE>
2784 <LINE>daughter: yet he knew me not at first; he said I</LINE>
2785 <LINE>was a fishmonger: he is far gone, far gone: and</LINE>
2786 <LINE>truly in my youth I suffered much extremity for</LINE>
2787 <LINE>love; very near this. I'll speak to him again.</LINE>
2788 <LINE>What do you read, my lord?</LINE>
2789 </SPEECH>
2790
2791 <SPEECH>
2792 <SPEAKER>HAMLET</SPEAKER>
2793 <LINE>Words, words, words.</LINE>
2794 </SPEECH>
2795
2796 <SPEECH>
2797 <SPEAKER>LORD POLONIUS</SPEAKER>
2798 <LINE>What is the matter, my lord?</LINE>
2799 </SPEECH>
2800
2801 <SPEECH>
2802 <SPEAKER>HAMLET</SPEAKER>
2803 <LINE>Between who?</LINE>
2804 </SPEECH>
2805
2806 <SPEECH>
2807 <SPEAKER>LORD POLONIUS</SPEAKER>
2808 <LINE>I mean, the matter that you read, my lord.</LINE>
2809 </SPEECH>
2810
2811 <SPEECH>
2812 <SPEAKER>HAMLET</SPEAKER>
2813 <LINE>Slanders, sir: for the satirical rogue says here</LINE>
2814 <LINE>that old men have grey beards, that their faces are</LINE>
2815 <LINE>wrinkled, their eyes purging thick amber and</LINE>
2816 <LINE>plum-tree gum and that they have a plentiful lack of</LINE>
2817 <LINE>wit, together with most weak hams: all which, sir,</LINE>
2818 <LINE>though I most powerfully and potently believe, yet</LINE>
2819 <LINE>I hold it not honesty to have it thus set down, for</LINE>
2820 <LINE>yourself, sir, should be old as I am, if like a crab</LINE>
2821 <LINE>you could go backward.</LINE>
2822 </SPEECH>
2823
2824 <SPEECH>
2825 <SPEAKER>LORD POLONIUS</SPEAKER>
2826 <LINE><STAGEDIR>Aside</STAGEDIR> Though this be madness, yet there is method</LINE>
2827 <LINE>in 't. Will you walk out of the air, my lord?</LINE>
2828 </SPEECH>
2829
2830 <SPEECH>
2831 <SPEAKER>HAMLET</SPEAKER>
2832 <LINE>Into my grave.</LINE>
2833 </SPEECH>
2834
2835 <SPEECH>
2836 <SPEAKER>LORD POLONIUS</SPEAKER>
2837 <LINE>Indeed, that is out o' the air.</LINE>
2838 <STAGEDIR>Aside</STAGEDIR>
2839 <LINE>How pregnant sometimes his replies are! a happiness</LINE>
2840 <LINE>that often madness hits on, which reason and sanity</LINE>
2841 <LINE>could not so prosperously be delivered of. I will</LINE>
2842 <LINE>leave him, and suddenly contrive the means of</LINE>
2843 <LINE>meeting between him and my daughter.--My honourable</LINE>
2844 <LINE>lord, I will most humbly take my leave of you.</LINE>
2845 </SPEECH>
2846
2847 <SPEECH>
2848 <SPEAKER>HAMLET</SPEAKER>
2849 <LINE>You cannot, sir, take from me any thing that I will</LINE>
2850 <LINE>more willingly part withal: except my life, except</LINE>
2851 <LINE>my life, except my life.</LINE>
2852 </SPEECH>
2853
2854 <SPEECH>
2855 <SPEAKER>LORD POLONIUS</SPEAKER>
2856 <LINE>Fare you well, my lord.</LINE>
2857 </SPEECH>
2858
2859 <SPEECH>
2860 <SPEAKER>HAMLET</SPEAKER>
2861 <LINE>These tedious old fools!</LINE>
2862 </SPEECH>
2863
2864
2865 <STAGEDIR>Enter ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
2866
2867 <SPEECH>
2868 <SPEAKER>LORD POLONIUS</SPEAKER>
2869 <LINE>You go to seek the Lord Hamlet; there he is.</LINE>
2870 </SPEECH>
2871
2872 <SPEECH>
2873 <SPEAKER>ROSENCRANTZ</SPEAKER>
2874 <LINE><STAGEDIR>To POLONIUS</STAGEDIR> God save you, sir!</LINE>
2875 </SPEECH>
2876
2877
2878 <STAGEDIR>Exit POLONIUS</STAGEDIR>
2879
2880 <SPEECH>
2881 <SPEAKER>GUILDENSTERN</SPEAKER>
2882 <LINE>My honoured lord!</LINE>
2883 </SPEECH>
2884
2885 <SPEECH>
2886 <SPEAKER>ROSENCRANTZ</SPEAKER>
2887 <LINE>My most dear lord!</LINE>
2888 </SPEECH>
2889
2890 <SPEECH>
2891 <SPEAKER>HAMLET</SPEAKER>
2892 <LINE>My excellent good friends! How dost thou,</LINE>
2893 <LINE>Guildenstern? Ah, Rosencrantz! Good lads, how do ye both?</LINE>
2894 </SPEECH>
2895
2896 <SPEECH>
2897 <SPEAKER>ROSENCRANTZ</SPEAKER>
2898 <LINE>As the indifferent children of the earth.</LINE>
2899 </SPEECH>
2900
2901 <SPEECH>
2902 <SPEAKER>GUILDENSTERN</SPEAKER>
2903 <LINE>Happy, in that we are not over-happy;</LINE>
2904 <LINE>On fortune's cap we are not the very button.</LINE>
2905 </SPEECH>
2906
2907 <SPEECH>
2908 <SPEAKER>HAMLET</SPEAKER>
2909 <LINE>Nor the soles of her shoe?</LINE>
2910 </SPEECH>
2911
2912 <SPEECH>
2913 <SPEAKER>ROSENCRANTZ</SPEAKER>
2914 <LINE>Neither, my lord.</LINE>
2915 </SPEECH>
2916
2917 <SPEECH>
2918 <SPEAKER>HAMLET</SPEAKER>
2919 <LINE>Then you live about her waist, or in the middle of</LINE>
2920 <LINE>her favours?</LINE>
2921 </SPEECH>
2922
2923 <SPEECH>
2924 <SPEAKER>GUILDENSTERN</SPEAKER>
2925 <LINE>'Faith, her privates we.</LINE>
2926 </SPEECH>
2927
2928 <SPEECH>
2929 <SPEAKER>HAMLET</SPEAKER>
2930 <LINE>In the secret parts of fortune? O, most true; she</LINE>
2931 <LINE>is a strumpet. What's the news?</LINE>
2932 </SPEECH>
2933
2934 <SPEECH>
2935 <SPEAKER>ROSENCRANTZ</SPEAKER>
2936 <LINE>None, my lord, but that the world's grown honest.</LINE>
2937 </SPEECH>
2938
2939 <SPEECH>
2940 <SPEAKER>HAMLET</SPEAKER>
2941 <LINE>Then is doomsday near: but your news is not true.</LINE>
2942 <LINE>Let me question more in particular: what have you,</LINE>
2943 <LINE>my good friends, deserved at the hands of fortune,</LINE>
2944 <LINE>that she sends you to prison hither?</LINE>
2945 </SPEECH>
2946
2947 <SPEECH>
2948 <SPEAKER>GUILDENSTERN</SPEAKER>
2949 <LINE>Prison, my lord!</LINE>
2950 </SPEECH>
2951
2952 <SPEECH>
2953 <SPEAKER>HAMLET</SPEAKER>
2954 <LINE>Denmark's a prison.</LINE>
2955 </SPEECH>
2956
2957 <SPEECH>
2958 <SPEAKER>ROSENCRANTZ</SPEAKER>
2959 <LINE>Then is the world one.</LINE>
2960 </SPEECH>
2961
2962 <SPEECH>
2963 <SPEAKER>HAMLET</SPEAKER>
2964 <LINE>A goodly one; in which there are many confines,</LINE>
2965 <LINE>wards and dungeons, Denmark being one o' the worst.</LINE>
2966 </SPEECH>
2967
2968 <SPEECH>
2969 <SPEAKER>ROSENCRANTZ</SPEAKER>
2970 <LINE>We think not so, my lord.</LINE>
2971 </SPEECH>
2972
2973 <SPEECH>
2974 <SPEAKER>HAMLET</SPEAKER>
2975 <LINE>Why, then, 'tis none to you; for there is nothing</LINE>
2976 <LINE>either good or bad, but thinking makes it so: to me</LINE>
2977 <LINE>it is a prison.</LINE>
2978 </SPEECH>
2979
2980 <SPEECH>
2981 <SPEAKER>ROSENCRANTZ</SPEAKER>
2982 <LINE>Why then, your ambition makes it one; 'tis too</LINE>
2983 <LINE>narrow for your mind.</LINE>
2984 </SPEECH>
2985
2986 <SPEECH>
2987 <SPEAKER>HAMLET</SPEAKER>
2988 <LINE>O God, I could be bounded in a nut shell and count</LINE>
2989 <LINE>myself a king of infinite space, were it not that I</LINE>
2990 <LINE>have bad dreams.</LINE>
2991 </SPEECH>
2992
2993 <SPEECH>
2994 <SPEAKER>GUILDENSTERN</SPEAKER>
2995 <LINE>Which dreams indeed are ambition, for the very</LINE>
2996 <LINE>substance of the ambitious is merely the shadow of a dream.</LINE>
2997 </SPEECH>
2998
2999 <SPEECH>
3000 <SPEAKER>HAMLET</SPEAKER>
3001 <LINE>A dream itself is but a shadow.</LINE>
3002 </SPEECH>
3003
3004 <SPEECH>
3005 <SPEAKER>ROSENCRANTZ</SPEAKER>
3006 <LINE>Truly, and I hold ambition of so airy and light a</LINE>
3007 <LINE>quality that it is but a shadow's shadow.</LINE>
3008 </SPEECH>
3009
3010 <SPEECH>
3011 <SPEAKER>HAMLET</SPEAKER>
3012 <LINE>Then are our beggars bodies, and our monarchs and</LINE>
3013 <LINE>outstretched heroes the beggars' shadows. Shall we</LINE>
3014 <LINE>to the court? for, by my fay, I cannot reason.</LINE>
3015 </SPEECH>
3016
3017 <SPEECH>
3018 <SPEAKER>ROSENCRANTZ</SPEAKER>
3019 <SPEAKER>GUILDENSTERN</SPEAKER>
3020 <LINE>We'll wait upon you.</LINE>
3021 </SPEECH>
3022
3023 <SPEECH>
3024 <SPEAKER>HAMLET</SPEAKER>
3025 <LINE>No such matter: I will not sort you with the rest</LINE>
3026 <LINE>of my servants, for, to speak to you like an honest</LINE>
3027 <LINE>man, I am most dreadfully attended. But, in the</LINE>
3028 <LINE>beaten way of friendship, what make you at Elsinore?</LINE>
3029 </SPEECH>
3030
3031 <SPEECH>
3032 <SPEAKER>ROSENCRANTZ</SPEAKER>
3033 <LINE>To visit you, my lord; no other occasion.</LINE>
3034 </SPEECH>
3035
3036 <SPEECH>
3037 <SPEAKER>HAMLET</SPEAKER>
3038 <LINE>Beggar that I am, I am even poor in thanks; but I</LINE>
3039 <LINE>thank you: and sure, dear friends, my thanks are</LINE>
3040 <LINE>too dear a halfpenny. Were you not sent for? Is it</LINE>
3041 <LINE>your own inclining? Is it a free visitation? Come,</LINE>
3042 <LINE>deal justly with me: come, come; nay, speak.</LINE>
3043 </SPEECH>
3044
3045 <SPEECH>
3046 <SPEAKER>GUILDENSTERN</SPEAKER>
3047 <LINE>What should we say, my lord?</LINE>
3048 </SPEECH>
3049
3050 <SPEECH>
3051 <SPEAKER>HAMLET</SPEAKER>
3052 <LINE>Why, any thing, but to the purpose. You were sent</LINE>
3053 <LINE>for; and there is a kind of confession in your looks</LINE>
3054 <LINE>which your modesties have not craft enough to colour:</LINE>
3055 <LINE>I know the good king and queen have sent for you.</LINE>
3056 </SPEECH>
3057
3058 <SPEECH>
3059 <SPEAKER>ROSENCRANTZ</SPEAKER>
3060 <LINE>To what end, my lord?</LINE>
3061 </SPEECH>
3062
3063 <SPEECH>
3064 <SPEAKER>HAMLET</SPEAKER>
3065 <LINE>That you must teach me. But let me conjure you, by</LINE>
3066 <LINE>the rights of our fellowship, by the consonancy of</LINE>
3067 <LINE>our youth, by the obligation of our ever-preserved</LINE>
3068 <LINE>love, and by what more dear a better proposer could</LINE>
3069 <LINE>charge you withal, be even and direct with me,</LINE>
3070 <LINE>whether you were sent for, or no?</LINE>
3071 </SPEECH>
3072
3073 <SPEECH>
3074 <SPEAKER>ROSENCRANTZ</SPEAKER>
3075 <LINE><STAGEDIR>Aside to GUILDENSTERN</STAGEDIR> What say you?</LINE>
3076 </SPEECH>
3077
3078 <SPEECH>
3079 <SPEAKER>HAMLET</SPEAKER>
3080 <LINE><STAGEDIR>Aside</STAGEDIR> Nay, then, I have an eye of you.--If you</LINE>
3081 <LINE>love me, hold not off.</LINE>
3082 </SPEECH>
3083
3084 <SPEECH>
3085 <SPEAKER>GUILDENSTERN</SPEAKER>
3086 <LINE>My lord, we were sent for.</LINE>
3087 </SPEECH>
3088
3089 <SPEECH>
3090 <SPEAKER>HAMLET</SPEAKER>
3091 <LINE>I will tell you why; so shall my anticipation</LINE>
3092 <LINE>prevent your discovery, and your secrecy to the king</LINE>
3093 <LINE>and queen moult no feather. I have of late--but</LINE>
3094 <LINE>wherefore I know not--lost all my mirth, forgone all</LINE>
3095 <LINE>custom of exercises; and indeed it goes so heavily</LINE>
3096 <LINE>with my disposition that this goodly frame, the</LINE>
3097 <LINE>earth, seems to me a sterile promontory, this most</LINE>
3098 <LINE>excellent canopy, the air, look you, this brave</LINE>
3099 <LINE>o'erhanging firmament, this majestical roof fretted</LINE>
3100 <LINE>with golden fire, why, it appears no other thing to</LINE>
3101 <LINE>me than a foul and pestilent congregation of vapours.</LINE>
3102 <LINE>What a piece of work is a man! how noble in reason!</LINE>
3103 <LINE>how infinite in faculty! in form and moving how</LINE>
3104 <LINE>express and admirable! in action how like an angel!</LINE>
3105 <LINE>in apprehension how like a god! the beauty of the</LINE>
3106 <LINE>world! the paragon of animals! And yet, to me,</LINE>
3107 <LINE>what is this quintessence of dust? man delights not</LINE>
3108 <LINE>me: no, nor woman neither, though by your smiling</LINE>
3109 <LINE>you seem to say so.</LINE>
3110 </SPEECH>
3111
3112 <SPEECH>
3113 <SPEAKER>ROSENCRANTZ</SPEAKER>
3114 <LINE>My lord, there was no such stuff in my thoughts.</LINE>
3115 </SPEECH>
3116
3117 <SPEECH>
3118 <SPEAKER>HAMLET</SPEAKER>
3119 <LINE>Why did you laugh then, when I said 'man delights not me'?</LINE>
3120 </SPEECH>
3121
3122 <SPEECH>
3123 <SPEAKER>ROSENCRANTZ</SPEAKER>
3124 <LINE>To think, my lord, if you delight not in man, what</LINE>
3125 <LINE>lenten entertainment the players shall receive from</LINE>
3126 <LINE>you: we coted them on the way; and hither are they</LINE>
3127 <LINE>coming, to offer you service.</LINE>
3128 </SPEECH>
3129
3130 <SPEECH>
3131 <SPEAKER>HAMLET</SPEAKER>
3132 <LINE>He that plays the king shall be welcome; his majesty</LINE>
3133 <LINE>shall have tribute of me; the adventurous knight</LINE>
3134 <LINE>shall use his foil and target; the lover shall not</LINE>
3135 <LINE>sigh gratis; the humourous man shall end his part</LINE>
3136 <LINE>in peace; the clown shall make those laugh whose</LINE>
3137 <LINE>lungs are tickled o' the sere; and the lady shall</LINE>
3138 <LINE>say her mind freely, or the blank verse shall halt</LINE>
3139 <LINE>for't. What players are they?</LINE>
3140 </SPEECH>
3141
3142 <SPEECH>
3143 <SPEAKER>ROSENCRANTZ</SPEAKER>
3144 <LINE>Even those you were wont to take delight in, the</LINE>
3145 <LINE>tragedians of the city.</LINE>
3146 </SPEECH>
3147
3148 <SPEECH>
3149 <SPEAKER>HAMLET</SPEAKER>
3150 <LINE>How chances it they travel? their residence, both</LINE>
3151 <LINE>in reputation and profit, was better both ways.</LINE>
3152 </SPEECH>
3153
3154 <SPEECH>
3155 <SPEAKER>ROSENCRANTZ</SPEAKER>
3156 <LINE>I think their inhibition comes by the means of the</LINE>
3157 <LINE>late innovation.</LINE>
3158 </SPEECH>
3159
3160 <SPEECH>
3161 <SPEAKER>HAMLET</SPEAKER>
3162 <LINE>Do they hold the same estimation they did when I was</LINE>
3163 <LINE>in the city? are they so followed?</LINE>
3164 </SPEECH>
3165
3166 <SPEECH>
3167 <SPEAKER>ROSENCRANTZ</SPEAKER>
3168 <LINE>No, indeed, are they not.</LINE>
3169 </SPEECH>
3170
3171 <SPEECH>
3172 <SPEAKER>HAMLET</SPEAKER>
3173 <LINE>How comes it? do they grow rusty?</LINE>
3174 </SPEECH>
3175
3176 <SPEECH>
3177 <SPEAKER>ROSENCRANTZ</SPEAKER>
3178 <LINE>Nay, their endeavour keeps in the wonted pace: but</LINE>
3179 <LINE>there is, sir, an aery of children, little eyases,</LINE>
3180 <LINE>that cry out on the top of question, and are most</LINE>
3181 <LINE>tyrannically clapped for't: these are now the</LINE>
3182 <LINE>fashion, and so berattle the common stages--so they</LINE>
3183 <LINE>call them--that many wearing rapiers are afraid of</LINE>
3184 <LINE>goose-quills and dare scarce come thither.</LINE>
3185 </SPEECH>
3186
3187 <SPEECH>
3188 <SPEAKER>HAMLET</SPEAKER>
3189 <LINE>What, are they children? who maintains 'em? how are</LINE>
3190 <LINE>they escoted? Will they pursue the quality no</LINE>
3191 <LINE>longer than they can sing? will they not say</LINE>
3192 <LINE>afterwards, if they should grow themselves to common</LINE>
3193 <LINE>players--as it is most like, if their means are no</LINE>
3194 <LINE>better--their writers do them wrong, to make them</LINE>
3195 <LINE>exclaim against their own succession?</LINE>
3196 </SPEECH>
3197
3198 <SPEECH>
3199 <SPEAKER>ROSENCRANTZ</SPEAKER>
3200 <LINE>'Faith, there has been much to do on both sides; and</LINE>
3201 <LINE>the nation holds it no sin to tarre them to</LINE>
3202 <LINE>controversy: there was, for a while, no money bid</LINE>
3203 <LINE>for argument, unless the poet and the player went to</LINE>
3204 <LINE>cuffs in the question.</LINE>
3205 </SPEECH>
3206
3207 <SPEECH>
3208 <SPEAKER>HAMLET</SPEAKER>
3209 <LINE>Is't possible?</LINE>
3210 </SPEECH>
3211
3212 <SPEECH>
3213 <SPEAKER>GUILDENSTERN</SPEAKER>
3214 <LINE>O, there has been much throwing about of brains.</LINE>
3215 </SPEECH>
3216
3217 <SPEECH>
3218 <SPEAKER>HAMLET</SPEAKER>
3219 <LINE>Do the boys carry it away?</LINE>
3220 </SPEECH>
3221
3222 <SPEECH>
3223 <SPEAKER>ROSENCRANTZ</SPEAKER>
3224 <LINE>Ay, that they do, my lord; Hercules and his load too.</LINE>
3225 </SPEECH>
3226
3227 <SPEECH>
3228 <SPEAKER>HAMLET</SPEAKER>
3229 <LINE>It is not very strange; for mine uncle is king of</LINE>
3230 <LINE>Denmark, and those that would make mows at him while</LINE>
3231 <LINE>my father lived, give twenty, forty, fifty, an</LINE>
3232 <LINE>hundred ducats a-piece for his picture in little.</LINE>
3233 <LINE>'Sblood, there is something in this more than</LINE>
3234 <LINE>natural, if philosophy could find it out.</LINE>
3235 </SPEECH>
3236
3237
3238 <STAGEDIR>Flourish of trumpets within</STAGEDIR>
3239
3240 <SPEECH>
3241 <SPEAKER>GUILDENSTERN</SPEAKER>
3242 <LINE>There are the players.</LINE>
3243 </SPEECH>
3244
3245 <SPEECH>
3246 <SPEAKER>HAMLET</SPEAKER>
3247 <LINE>Gentlemen, you are welcome to Elsinore. Your hands,</LINE>
3248 <LINE>come then: the appurtenance of welcome is fashion</LINE>
3249 <LINE>and ceremony: let me comply with you in this garb,</LINE>
3250 <LINE>lest my extent to the players, which, I tell you,</LINE>
3251 <LINE>must show fairly outward, should more appear like</LINE>
3252 <LINE>entertainment than yours. You are welcome: but my</LINE>
3253 <LINE>uncle-father and aunt-mother are deceived.</LINE>
3254 </SPEECH>
3255
3256 <SPEECH>
3257 <SPEAKER>GUILDENSTERN</SPEAKER>
3258 <LINE>In what, my dear lord?</LINE>
3259 </SPEECH>
3260
3261 <SPEECH>
3262 <SPEAKER>HAMLET</SPEAKER>
3263 <LINE>I am but mad north-north-west: when the wind is</LINE>
3264 <LINE>southerly I know a hawk from a handsaw.</LINE>
3265 </SPEECH>
3266
3267
3268 <STAGEDIR>Enter POLONIUS</STAGEDIR>
3269
3270 <SPEECH>
3271 <SPEAKER>LORD POLONIUS</SPEAKER>
3272 <LINE>Well be with you, gentlemen!</LINE>
3273 </SPEECH>
3274
3275 <SPEECH>
3276 <SPEAKER>HAMLET</SPEAKER>
3277 <LINE>Hark you, Guildenstern; and you too: at each ear a</LINE>
3278 <LINE>hearer: that great baby you see there is not yet</LINE>
3279 <LINE>out of his swaddling-clouts.</LINE>
3280 </SPEECH>
3281
3282 <SPEECH>
3283 <SPEAKER>ROSENCRANTZ</SPEAKER>
3284 <LINE>Happily he's the second time come to them; for they</LINE>
3285 <LINE>say an old man is twice a child.</LINE>
3286 </SPEECH>
3287
3288 <SPEECH>
3289 <SPEAKER>HAMLET</SPEAKER>
3290 <LINE>I will prophesy he comes to tell me of the players;</LINE>
3291 <LINE>mark it. You say right, sir: o' Monday morning;</LINE>
3292 <LINE>'twas so indeed.</LINE>
3293 </SPEECH>
3294
3295 <SPEECH>
3296 <SPEAKER>LORD POLONIUS</SPEAKER>
3297 <LINE>My lord, I have news to tell you.</LINE>
3298 </SPEECH>
3299
3300 <SPEECH>
3301 <SPEAKER>HAMLET</SPEAKER>
3302 <LINE>My lord, I have news to tell you.</LINE>
3303 <LINE>When Roscius was an actor in Rome,--</LINE>
3304 </SPEECH>
3305
3306 <SPEECH>
3307 <SPEAKER>LORD POLONIUS</SPEAKER>
3308 <LINE>The actors are come hither, my lord.</LINE>
3309 </SPEECH>
3310
3311 <SPEECH>
3312 <SPEAKER>HAMLET</SPEAKER>
3313 <LINE>Buz, buz!</LINE>
3314 </SPEECH>
3315
3316 <SPEECH>
3317 <SPEAKER>LORD POLONIUS</SPEAKER>
3318 <LINE>Upon mine honour,--</LINE>
3319 </SPEECH>
3320
3321 <SPEECH>
3322 <SPEAKER>HAMLET</SPEAKER>
3323 <LINE>Then came each actor on his ass,--</LINE>
3324 </SPEECH>
3325
3326 <SPEECH>
3327 <SPEAKER>LORD POLONIUS</SPEAKER>
3328 <LINE>The best actors in the world, either for tragedy,</LINE>
3329 <LINE>comedy, history, pastoral, pastoral-comical,</LINE>
3330 <LINE>historical-pastoral, tragical-historical, tragical-</LINE>
3331 <LINE>comical-historical-pastoral, scene individable, or</LINE>
3332 <LINE>poem unlimited: Seneca cannot be too heavy, nor</LINE>
3333 <LINE>Plautus too light. For the law of writ and the</LINE>
3334 <LINE>liberty, these are the only men.</LINE>
3335 </SPEECH>
3336
3337 <SPEECH>
3338 <SPEAKER>HAMLET</SPEAKER>
3339 <LINE>O Jephthah, judge of Israel, what a treasure hadst thou!</LINE>
3340 </SPEECH>
3341
3342 <SPEECH>
3343 <SPEAKER>LORD POLONIUS</SPEAKER>
3344 <LINE>What a treasure had he, my lord?</LINE>
3345 </SPEECH>
3346
3347 <SPEECH>
3348 <SPEAKER>HAMLET</SPEAKER>
3349 <LINE>Why,</LINE>
3350 <LINE>'One fair daughter and no more,</LINE>
3351 <LINE>The which he loved passing well.'</LINE>
3352 </SPEECH>
3353
3354 <SPEECH>
3355 <SPEAKER>LORD POLONIUS</SPEAKER>
3356 <LINE><STAGEDIR>Aside</STAGEDIR> Still on my daughter.</LINE>
3357 </SPEECH>
3358
3359 <SPEECH>
3360 <SPEAKER>HAMLET</SPEAKER>
3361 <LINE>Am I not i' the right, old Jephthah?</LINE>
3362 </SPEECH>
3363
3364 <SPEECH>
3365 <SPEAKER>LORD POLONIUS</SPEAKER>
3366 <LINE>If you call me Jephthah, my lord, I have a daughter</LINE>
3367 <LINE>that I love passing well.</LINE>
3368 </SPEECH>
3369
3370 <SPEECH>
3371 <SPEAKER>HAMLET</SPEAKER>
3372 <LINE>Nay, that follows not.</LINE>
3373 </SPEECH>
3374
3375 <SPEECH>
3376 <SPEAKER>LORD POLONIUS</SPEAKER>
3377 <LINE>What follows, then, my lord?</LINE>
3378 </SPEECH>
3379
3380 <SPEECH>
3381 <SPEAKER>HAMLET</SPEAKER>
3382 <LINE>Why,</LINE>
3383 <LINE>'As by lot, God wot,'</LINE>
3384 <LINE>and then, you know,</LINE>
3385 <LINE>'It came to pass, as most like it was,'--</LINE>
3386 <LINE>the first row of the pious chanson will show you</LINE>
3387 <LINE>more; for look, where my abridgement comes.</LINE>
3388 <STAGEDIR>Enter four or five Players</STAGEDIR>
3389 <LINE>You are welcome, masters; welcome, all. I am glad</LINE>
3390 <LINE>to see thee well. Welcome, good friends. O, my old</LINE>
3391 <LINE>friend! thy face is valenced since I saw thee last:</LINE>
3392 <LINE>comest thou to beard me in Denmark? What, my young</LINE>
3393 <LINE>lady and mistress! By'r lady, your ladyship is</LINE>
3394 <LINE>nearer to heaven than when I saw you last, by the</LINE>
3395 <LINE>altitude of a chopine. Pray God, your voice, like</LINE>
3396 <LINE>apiece of uncurrent gold, be not cracked within the</LINE>
3397 <LINE>ring. Masters, you are all welcome. We'll e'en</LINE>
3398 <LINE>to't like French falconers, fly at any thing we see:</LINE>
3399 <LINE>we'll have a speech straight: come, give us a taste</LINE>
3400 <LINE>of your quality; come, a passionate speech.</LINE>
3401 </SPEECH>
3402
3403 <SPEECH>
3404 <SPEAKER>First Player</SPEAKER>
3405 <LINE>What speech, my lord?</LINE>
3406 </SPEECH>
3407
3408 <SPEECH>
3409 <SPEAKER>HAMLET</SPEAKER>
3410 <LINE>I heard thee speak me a speech once, but it was</LINE>
3411 <LINE>never acted; or, if it was, not above once; for the</LINE>
3412 <LINE>play, I remember, pleased not the million; 'twas</LINE>
3413 <LINE>caviare to the general: but it was--as I received</LINE>
3414 <LINE>it, and others, whose judgments in such matters</LINE>
3415 <LINE>cried in the top of mine--an excellent play, well</LINE>
3416 <LINE>digested in the scenes, set down with as much</LINE>
3417 <LINE>modesty as cunning. I remember, one said there</LINE>
3418 <LINE>were no sallets in the lines to make the matter</LINE>
3419 <LINE>savoury, nor no matter in the phrase that might</LINE>
3420 <LINE>indict the author of affectation; but called it an</LINE>
3421 <LINE>honest method, as wholesome as sweet, and by very</LINE>
3422 <LINE>much more handsome than fine. One speech in it I</LINE>
3423 <LINE>chiefly loved: 'twas Aeneas' tale to Dido; and</LINE>
3424 <LINE>thereabout of it especially, where he speaks of</LINE>
3425 <LINE>Priam's slaughter: if it live in your memory, begin</LINE>
3426 <LINE>at this line: let me see, let me see--</LINE>
3427 <LINE>'The rugged Pyrrhus, like the Hyrcanian beast,'--</LINE>
3428 <LINE>it is not so:--it begins with Pyrrhus:--</LINE>
3429 <LINE>'The rugged Pyrrhus, he whose sable arms,</LINE>
3430 <LINE>Black as his purpose, did the night resemble</LINE>
3431 <LINE>When he lay couched in the ominous horse,</LINE>
3432 <LINE>Hath now this dread and black complexion smear'd</LINE>
3433 <LINE>With heraldry more dismal; head to foot</LINE>
3434 <LINE>Now is he total gules; horridly trick'd</LINE>
3435 <LINE>With blood of fathers, mothers, daughters, sons,</LINE>
3436 <LINE>Baked and impasted with the parching streets,</LINE>
3437 <LINE>That lend a tyrannous and damned light</LINE>
3438 <LINE>To their lord's murder: roasted in wrath and fire,</LINE>
3439 <LINE>And thus o'er-sized with coagulate gore,</LINE>
3440 <LINE>With eyes like carbuncles, the hellish Pyrrhus</LINE>
3441 <LINE>Old grandsire Priam seeks.'</LINE>
3442 <LINE>So, proceed you.</LINE>
3443 </SPEECH>
3444
3445 <SPEECH>
3446 <SPEAKER>LORD POLONIUS</SPEAKER>
3447 <LINE>'Fore God, my lord, well spoken, with good accent and</LINE>
3448 <LINE>good discretion.</LINE>
3449 </SPEECH>
3450
3451 <SPEECH>
3452 <SPEAKER>First Player</SPEAKER>
3453 <LINE>'Anon he finds him</LINE>
3454 <LINE>Striking too short at Greeks; his antique sword,</LINE>
3455 <LINE>Rebellious to his arm, lies where it falls,</LINE>
3456 <LINE>Repugnant to command: unequal match'd,</LINE>
3457 <LINE>Pyrrhus at Priam drives; in rage strikes wide;</LINE>
3458 <LINE>But with the whiff and wind of his fell sword</LINE>
3459 <LINE>The unnerved father falls. Then senseless Ilium,</LINE>
3460 <LINE>Seeming to feel this blow, with flaming top</LINE>
3461 <LINE>Stoops to his base, and with a hideous crash</LINE>
3462 <LINE>Takes prisoner Pyrrhus' ear: for, lo! his sword,</LINE>
3463 <LINE>Which was declining on the milky head</LINE>
3464 <LINE>Of reverend Priam, seem'd i' the air to stick:</LINE>
3465 <LINE>So, as a painted tyrant, Pyrrhus stood,</LINE>
3466 <LINE>And like a neutral to his will and matter,</LINE>
3467 <LINE>Did nothing.</LINE>
3468 <LINE>But, as we often see, against some storm,</LINE>
3469 <LINE>A silence in the heavens, the rack stand still,</LINE>
3470 <LINE>The bold winds speechless and the orb below</LINE>
3471 <LINE>As hush as death, anon the dreadful thunder</LINE>
3472 <LINE>Doth rend the region, so, after Pyrrhus' pause,</LINE>
3473 <LINE>Aroused vengeance sets him new a-work;</LINE>
3474 <LINE>And never did the Cyclops' hammers fall</LINE>
3475 <LINE>On Mars's armour forged for proof eterne</LINE>
3476 <LINE>With less remorse than Pyrrhus' bleeding sword</LINE>
3477 <LINE>Now falls on Priam.</LINE>
3478 <LINE>Out, out, thou strumpet, Fortune! All you gods,</LINE>
3479 <LINE>In general synod 'take away her power;</LINE>
3480 <LINE>Break all the spokes and fellies from her wheel,</LINE>
3481 <LINE>And bowl the round nave down the hill of heaven,</LINE>
3482 <LINE>As low as to the fiends!'</LINE>
3483 </SPEECH>
3484
3485 <SPEECH>
3486 <SPEAKER>LORD POLONIUS</SPEAKER>
3487 <LINE>This is too long.</LINE>
3488 </SPEECH>
3489
3490 <SPEECH>
3491 <SPEAKER>HAMLET</SPEAKER>
3492 <LINE>It shall to the barber's, with your beard. Prithee,</LINE>
3493 <LINE>say on: he's for a jig or a tale of bawdry, or he</LINE>
3494 <LINE>sleeps: say on: come to Hecuba.</LINE>
3495 </SPEECH>
3496
3497 <SPEECH>
3498 <SPEAKER>First Player</SPEAKER>
3499 <LINE>'But who, O, who had seen the mobled queen--'</LINE>
3500 </SPEECH>
3501
3502 <SPEECH>
3503 <SPEAKER>HAMLET</SPEAKER>
3504 <LINE>'The mobled queen?'</LINE>
3505 </SPEECH>
3506
3507 <SPEECH>
3508 <SPEAKER>LORD POLONIUS</SPEAKER>
3509 <LINE>That's good; 'mobled queen' is good.</LINE>
3510 </SPEECH>
3511
3512 <SPEECH>
3513 <SPEAKER>First Player</SPEAKER>
3514 <LINE>'Run barefoot up and down, threatening the flames</LINE>
3515 <LINE>With bisson rheum; a clout upon that head</LINE>
3516 <LINE>Where late the diadem stood, and for a robe,</LINE>
3517 <LINE>About her lank and all o'er-teemed loins,</LINE>
3518 <LINE>A blanket, in the alarm of fear caught up;</LINE>
3519 <LINE>Who this had seen, with tongue in venom steep'd,</LINE>
3520 <LINE>'Gainst Fortune's state would treason have</LINE>
3521 <LINE>pronounced:</LINE>
3522 <LINE>But if the gods themselves did see her then</LINE>
3523 <LINE>When she saw Pyrrhus make malicious sport</LINE>
3524 <LINE>In mincing with his sword her husband's limbs,</LINE>
3525 <LINE>The instant burst of clamour that she made,</LINE>
3526 <LINE>Unless things mortal move them not at all,</LINE>
3527 <LINE>Would have made milch the burning eyes of heaven,</LINE>
3528 <LINE>And passion in the gods.'</LINE>
3529 </SPEECH>
3530
3531 <SPEECH>
3532 <SPEAKER>LORD POLONIUS</SPEAKER>
3533 <LINE>Look, whether he has not turned his colour and has</LINE>
3534 <LINE>tears in's eyes. Pray you, no more.</LINE>
3535 </SPEECH>
3536
3537 <SPEECH>
3538 <SPEAKER>HAMLET</SPEAKER>
3539 <LINE>'Tis well: I'll have thee speak out the rest soon.</LINE>
3540 <LINE>Good my lord, will you see the players well</LINE>
3541 <LINE>bestowed? Do you hear, let them be well used; for</LINE>
3542 <LINE>they are the abstract and brief chronicles of the</LINE>
3543 <LINE>time: after your death you were better have a bad</LINE>
3544 <LINE>epitaph than their ill report while you live.</LINE>
3545 </SPEECH>
3546
3547 <SPEECH>
3548 <SPEAKER>LORD POLONIUS</SPEAKER>
3549 <LINE>My lord, I will use them according to their desert.</LINE>
3550 </SPEECH>
3551
3552 <SPEECH>
3553 <SPEAKER>HAMLET</SPEAKER>
3554 <LINE>God's bodykins, man, much better: use every man</LINE>
3555 <LINE>after his desert, and who should 'scape whipping?</LINE>
3556 <LINE>Use them after your own honour and dignity: the less</LINE>
3557 <LINE>they deserve, the more merit is in your bounty.</LINE>
3558 <LINE>Take them in.</LINE>
3559 </SPEECH>
3560
3561 <SPEECH>
3562 <SPEAKER>LORD POLONIUS</SPEAKER>
3563 <LINE>Come, sirs.</LINE>
3564 </SPEECH>
3565
3566 <SPEECH>
3567 <SPEAKER>HAMLET</SPEAKER>
3568 <LINE>Follow him, friends: we'll hear a play to-morrow.</LINE>
3569 <STAGEDIR>Exit POLONIUS with all the Players but the First</STAGEDIR>
3570 <LINE>Dost thou hear me, old friend; can you play the</LINE>
3571 <LINE>Murder of Gonzago?</LINE>
3572 </SPEECH>
3573
3574 <SPEECH>
3575 <SPEAKER>First Player</SPEAKER>
3576 <LINE>Ay, my lord.</LINE>
3577 </SPEECH>
3578
3579 <SPEECH>
3580 <SPEAKER>HAMLET</SPEAKER>
3581 <LINE>We'll ha't to-morrow night. You could, for a need,</LINE>
3582 <LINE>study a speech of some dozen or sixteen lines, which</LINE>
3583 <LINE>I would set down and insert in't, could you not?</LINE>
3584 </SPEECH>
3585
3586 <SPEECH>
3587 <SPEAKER>First Player</SPEAKER>
3588 <LINE>Ay, my lord.</LINE>
3589 </SPEECH>
3590
3591 <SPEECH>
3592 <SPEAKER>HAMLET</SPEAKER>
3593 <LINE>Very well. Follow that lord; and look you mock him</LINE>
3594 <LINE>not.</LINE>
3595 <STAGEDIR>Exit First Player</STAGEDIR>
3596 <LINE>My good friends, I'll leave you till night: you are</LINE>
3597 <LINE>welcome to Elsinore.</LINE>
3598 </SPEECH>
3599
3600 <SPEECH>
3601 <SPEAKER>ROSENCRANTZ</SPEAKER>
3602 <LINE>Good my lord!</LINE>
3603 </SPEECH>
3604
3605 <SPEECH>
3606 <SPEAKER>HAMLET</SPEAKER>
3607 <LINE>Ay, so, God be wi' ye;</LINE>
3608 <STAGEDIR>Exeunt ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
3609 <LINE>Now I am alone.</LINE>
3610 <LINE>O, what a rogue and peasant slave am I!</LINE>
3611 <LINE>Is it not monstrous that this player here,</LINE>
3612 <LINE>But in a fiction, in a dream of passion,</LINE>
3613 <LINE>Could force his soul so to his own conceit</LINE>
3614 <LINE>That from her working all his visage wann'd,</LINE>
3615 <LINE>Tears in his eyes, distraction in's aspect,</LINE>
3616 <LINE>A broken voice, and his whole function suiting</LINE>
3617 <LINE>With forms to his conceit? and all for nothing!</LINE>
3618 <LINE>For Hecuba!</LINE>
3619 <LINE>What's Hecuba to him, or he to Hecuba,</LINE>
3620 <LINE>That he should weep for her? What would he do,</LINE>
3621 <LINE>Had he the motive and the cue for passion</LINE>
3622 <LINE>That I have? He would drown the stage with tears</LINE>
3623 <LINE>And cleave the general ear with horrid speech,</LINE>
3624 <LINE>Make mad the guilty and appal the free,</LINE>
3625 <LINE>Confound the ignorant, and amaze indeed</LINE>
3626 <LINE>The very faculties of eyes and ears. Yet I,</LINE>
3627 <LINE>A dull and muddy-mettled rascal, peak,</LINE>
3628 <LINE>Like John-a-dreams, unpregnant of my cause,</LINE>
3629 <LINE>And can say nothing; no, not for a king,</LINE>
3630 <LINE>Upon whose property and most dear life</LINE>
3631 <LINE>A damn'd defeat was made. Am I a coward?</LINE>
3632 <LINE>Who calls me villain? breaks my pate across?</LINE>
3633 <LINE>Plucks off my beard, and blows it in my face?</LINE>
3634 <LINE>Tweaks me by the nose? gives me the lie i' the throat,</LINE>
3635 <LINE>As deep as to the lungs? who does me this?</LINE>
3636 <LINE>Ha!</LINE>
3637 <LINE>'Swounds, I should take it: for it cannot be</LINE>
3638 <LINE>But I am pigeon-liver'd and lack gall</LINE>
3639 <LINE>To make oppression bitter, or ere this</LINE>
3640 <LINE>I should have fatted all the region kites</LINE>
3641 <LINE>With this slave's offal: bloody, bawdy villain!</LINE>
3642 <LINE>Remorseless, treacherous, lecherous, kindless villain!</LINE>
3643 <LINE>O, vengeance!</LINE>
3644 <LINE>Why, what an ass am I! This is most brave,</LINE>
3645 <LINE>That I, the son of a dear father murder'd,</LINE>
3646 <LINE>Prompted to my revenge by heaven and hell,</LINE>
3647 <LINE>Must, like a whore, unpack my heart with words,</LINE>
3648 <LINE>And fall a-cursing, like a very drab,</LINE>
3649 <LINE>A scullion!</LINE>
3650 <LINE>Fie upon't! foh! About, my brain! I have heard</LINE>
3651 <LINE>That guilty creatures sitting at a play</LINE>
3652 <LINE>Have by the very cunning of the scene</LINE>
3653 <LINE>Been struck so to the soul that presently</LINE>
3654 <LINE>They have proclaim'd their malefactions;</LINE>
3655 <LINE>For murder, though it have no tongue, will speak</LINE>
3656 <LINE>With most miraculous organ. I'll have these players</LINE>
3657 <LINE>Play something like the murder of my father</LINE>
3658 <LINE>Before mine uncle: I'll observe his looks;</LINE>
3659 <LINE>I'll tent him to the quick: if he but blench,</LINE>
3660 <LINE>I know my course. The spirit that I have seen</LINE>
3661 <LINE>May be the devil: and the devil hath power</LINE>
3662 <LINE>To assume a pleasing shape; yea, and perhaps</LINE>
3663 <LINE>Out of my weakness and my melancholy,</LINE>
3664 <LINE>As he is very potent with such spirits,</LINE>
3665 <LINE>Abuses me to damn me: I'll have grounds</LINE>
3666 <LINE>More relative than this: the play 's the thing</LINE>
3667 <LINE>Wherein I'll catch the conscience of the king.</LINE>
3668 </SPEECH>
3669
3670
3671 <STAGEDIR>Exit</STAGEDIR>
3672 </SCENE>
3673
3674 </ACT>
3675
3676 <ACT><TITLE>ACT III</TITLE>
3677
3678 <SCENE><TITLE>SCENE I. A room in the castle.</TITLE>
3679 <STAGEDIR>Enter KING CLAUDIUS, QUEEN GERTRUDE, POLONIUS,
3680 OPHELIA, ROSENCRANTZ, and GUILDENSTERN</STAGEDIR>
3681
3682 <SPEECH>
3683 <SPEAKER>KING CLAUDIUS</SPEAKER>
3684 <LINE>And can you, by no drift of circumstance,</LINE>
3685 <LINE>Get from him why he puts on this confusion,</LINE>
3686 <LINE>Grating so harshly all his days of quiet</LINE>
3687 <LINE>With turbulent and dangerous lunacy?</LINE>
3688 </SPEECH>
3689
3690 <SPEECH>
3691 <SPEAKER>ROSENCRANTZ</SPEAKER>
3692 <LINE>He does confess he feels himself distracted;</LINE>
3693 <LINE>But from what cause he will by no means speak.</LINE>
3694 </SPEECH>
3695
3696 <SPEECH>
3697 <SPEAKER>GUILDENSTERN</SPEAKER>
3698 <LINE>Nor do we find him forward to be sounded,</LINE>
3699 <LINE>But, with a crafty madness, keeps aloof,</LINE>
3700 <LINE>When we would bring him on to some confession</LINE>
3701 <LINE>Of his true state.</LINE>
3702 </SPEECH>
3703
3704 <SPEECH>
3705 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
3706 <LINE>Did he receive you well?</LINE>
3707 </SPEECH>
3708
3709 <SPEECH>
3710 <SPEAKER>ROSENCRANTZ</SPEAKER>
3711 <LINE>Most like a gentleman.</LINE>
3712 </SPEECH>
3713
3714 <SPEECH>
3715 <SPEAKER>GUILDENSTERN</SPEAKER>
3716 <LINE>But with much forcing of his disposition.</LINE>
3717 </SPEECH>
3718
3719 <SPEECH>
3720 <SPEAKER>ROSENCRANTZ</SPEAKER>
3721 <LINE>Niggard of question; but, of our demands,</LINE>
3722 <LINE>Most free in his reply.</LINE>
3723 </SPEECH>
3724
3725 <SPEECH>
3726 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
3727 <LINE>Did you assay him?</LINE>
3728 <LINE>To any pastime?</LINE>
3729 </SPEECH>
3730
3731 <SPEECH>
3732 <SPEAKER>ROSENCRANTZ</SPEAKER>
3733 <LINE>Madam, it so fell out, that certain players</LINE>
3734 <LINE>We o'er-raught on the way: of these we told him;</LINE>
3735 <LINE>And there did seem in him a kind of joy</LINE>
3736 <LINE>To hear of it: they are about the court,</LINE>
3737 <LINE>And, as I think, they have already order</LINE>
3738 <LINE>This night to play before him.</LINE>
3739 </SPEECH>
3740
3741 <SPEECH>
3742 <SPEAKER>LORD POLONIUS</SPEAKER>
3743 <LINE>'Tis most true:</LINE>
3744 <LINE>And he beseech'd me to entreat your majesties</LINE>
3745 <LINE>To hear and see the matter.</LINE>
3746 </SPEECH>
3747
3748 <SPEECH>
3749 <SPEAKER>KING CLAUDIUS</SPEAKER>
3750 <LINE>With all my heart; and it doth much content me</LINE>
3751 <LINE>To hear him so inclined.</LINE>
3752 <LINE>Good gentlemen, give him a further edge,</LINE>
3753 <LINE>And drive his purpose on to these delights.</LINE>
3754 </SPEECH>
3755
3756 <SPEECH>
3757 <SPEAKER>ROSENCRANTZ</SPEAKER>
3758 <LINE>We shall, my lord.</LINE>
3759 </SPEECH>
3760
3761
3762 <STAGEDIR>Exeunt ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
3763
3764 <SPEECH>
3765 <SPEAKER>KING CLAUDIUS</SPEAKER>
3766 <LINE>Sweet Gertrude, leave us too;</LINE>
3767 <LINE>For we have closely sent for Hamlet hither,</LINE>
3768 <LINE>That he, as 'twere by accident, may here</LINE>
3769 <LINE>Affront Ophelia:</LINE>
3770 <LINE>Her father and myself, lawful espials,</LINE>
3771 <LINE>Will so bestow ourselves that, seeing, unseen,</LINE>
3772 <LINE>We may of their encounter frankly judge,</LINE>
3773 <LINE>And gather by him, as he is behaved,</LINE>
3774 <LINE>If 't be the affliction of his love or no</LINE>
3775 <LINE>That thus he suffers for.</LINE>
3776 </SPEECH>
3777
3778 <SPEECH>
3779 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
3780 <LINE>I shall obey you.</LINE>
3781 <LINE>And for your part, Ophelia, I do wish</LINE>
3782 <LINE>That your good beauties be the happy cause</LINE>
3783 <LINE>Of Hamlet's wildness: so shall I hope your virtues</LINE>
3784 <LINE>Will bring him to his wonted way again,</LINE>
3785 <LINE>To both your honours.</LINE>
3786 </SPEECH>
3787
3788 <SPEECH>
3789 <SPEAKER>OPHELIA</SPEAKER>
3790 <LINE>Madam, I wish it may.</LINE>
3791 </SPEECH>
3792
3793
3794 <STAGEDIR>Exit QUEEN GERTRUDE</STAGEDIR>
3795
3796 <SPEECH>
3797 <SPEAKER>LORD POLONIUS</SPEAKER>
3798 <LINE>Ophelia, walk you here. Gracious, so please you,</LINE>
3799 <LINE>We will bestow ourselves.</LINE>
3800 <STAGEDIR>To OPHELIA</STAGEDIR>
3801 <LINE>Read on this book;</LINE>
3802 <LINE>That show of such an exercise may colour</LINE>
3803 <LINE>Your loneliness. We are oft to blame in this,--</LINE>
3804 <LINE>'Tis too much proved--that with devotion's visage</LINE>
3805 <LINE>And pious action we do sugar o'er</LINE>
3806 <LINE>The devil himself.</LINE>
3807 </SPEECH>
3808
3809 <SPEECH>
3810 <SPEAKER>KING CLAUDIUS</SPEAKER>
3811 <LINE><STAGEDIR>Aside</STAGEDIR> O, 'tis too true!</LINE>
3812 <LINE>How smart a lash that speech doth give my conscience!</LINE>
3813 <LINE>The harlot's cheek, beautied with plastering art,</LINE>
3814 <LINE>Is not more ugly to the thing that helps it</LINE>
3815 <LINE>Than is my deed to my most painted word:</LINE>
3816 <LINE>O heavy burthen!</LINE>
3817 </SPEECH>
3818
3819 <SPEECH>
3820 <SPEAKER>LORD POLONIUS</SPEAKER>
3821 <LINE>I hear him coming: let's withdraw, my lord.</LINE>
3822 </SPEECH>
3823
3824 <STAGEDIR>Exeunt KING CLAUDIUS and POLONIUS</STAGEDIR>
3825 <STAGEDIR>Enter HAMLET</STAGEDIR>
3826
3827 <SPEECH>
3828 <SPEAKER>HAMLET</SPEAKER>
3829 <LINE>To be, or not to be: that is the question:</LINE>
3830 <LINE>Whether 'tis nobler in the mind to suffer</LINE>
3831 <LINE>The slings and arrows of outrageous fortune,</LINE>
3832 <LINE>Or to take arms against a sea of troubles,</LINE>
3833 <LINE>And by opposing end them? To die: to sleep;</LINE>
3834 <LINE>No more; and by a sleep to say we end</LINE>
3835 <LINE>The heart-ache and the thousand natural shocks</LINE>
3836 <LINE>That flesh is heir to, 'tis a consummation</LINE>
3837 <LINE>Devoutly to be wish'd. To die, to sleep;</LINE>
3838 <LINE>To sleep: perchance to dream: ay, there's the rub;</LINE>
3839 <LINE>For in that sleep of death what dreams may come</LINE>
3840 <LINE>When we have shuffled off this mortal coil,</LINE>
3841 <LINE>Must give us pause: there's the respect</LINE>
3842 <LINE>That makes calamity of so long life;</LINE>
3843 <LINE>For who would bear the whips and scorns of time,</LINE>
3844 <LINE>The oppressor's wrong, the proud man's contumely,</LINE>
3845 <LINE>The pangs of despised love, the law's delay,</LINE>
3846 <LINE>The insolence of office and the spurns</LINE>
3847 <LINE>That patient merit of the unworthy takes,</LINE>
3848 <LINE>When he himself might his quietus make</LINE>
3849 <LINE>With a bare bodkin? who would fardels bear,</LINE>
3850 <LINE>To grunt and sweat under a weary life,</LINE>
3851 <LINE>But that the dread of something after death,</LINE>
3852 <LINE>The undiscover'd country from whose bourn</LINE>
3853 <LINE>No traveller returns, puzzles the will</LINE>
3854 <LINE>And makes us rather bear those ills we have</LINE>
3855 <LINE>Than fly to others that we know not of?</LINE>
3856 <LINE>Thus conscience does make cowards of us all;</LINE>
3857 <LINE>And thus the native hue of resolution</LINE>
3858 <LINE>Is sicklied o'er with the pale cast of thought,</LINE>
3859 <LINE>And enterprises of great pith and moment</LINE>
3860 <LINE>With this regard their currents turn awry,</LINE>
3861 <LINE>And lose the name of action.--Soft you now!</LINE>
3862 <LINE>The fair Ophelia! Nymph, in thy orisons</LINE>
3863 <LINE>Be all my sins remember'd.</LINE>
3864 </SPEECH>
3865
3866 <SPEECH>
3867 <SPEAKER>OPHELIA</SPEAKER>
3868 <LINE>Good my lord,</LINE>
3869 <LINE>How does your honour for this many a day?</LINE>
3870 </SPEECH>
3871
3872 <SPEECH>
3873 <SPEAKER>HAMLET</SPEAKER>
3874 <LINE>I humbly thank you; well, well, well.</LINE>
3875 </SPEECH>
3876
3877 <SPEECH>
3878 <SPEAKER>OPHELIA</SPEAKER>
3879 <LINE>My lord, I have remembrances of yours,</LINE>
3880 <LINE>That I have longed long to re-deliver;</LINE>
3881 <LINE>I pray you, now receive them.</LINE>
3882 </SPEECH>
3883
3884 <SPEECH>
3885 <SPEAKER>HAMLET</SPEAKER>
3886 <LINE>No, not I;</LINE>
3887 <LINE>I never gave you aught.</LINE>
3888 </SPEECH>
3889
3890 <SPEECH>
3891 <SPEAKER>OPHELIA</SPEAKER>
3892 <LINE>My honour'd lord, you know right well you did;</LINE>
3893 <LINE>And, with them, words of so sweet breath composed</LINE>
3894 <LINE>As made the things more rich: their perfume lost,</LINE>
3895 <LINE>Take these again; for to the noble mind</LINE>
3896 <LINE>Rich gifts wax poor when givers prove unkind.</LINE>
3897 <LINE>There, my lord.</LINE>
3898 </SPEECH>
3899
3900 <SPEECH>
3901 <SPEAKER>HAMLET</SPEAKER>
3902 <LINE>Ha, ha! are you honest?</LINE>
3903 </SPEECH>
3904
3905 <SPEECH>
3906 <SPEAKER>OPHELIA</SPEAKER>
3907 <LINE>My lord?</LINE>
3908 </SPEECH>
3909
3910 <SPEECH>
3911 <SPEAKER>HAMLET</SPEAKER>
3912 <LINE>Are you fair?</LINE>
3913 </SPEECH>
3914
3915 <SPEECH>
3916 <SPEAKER>OPHELIA</SPEAKER>
3917 <LINE>What means your lordship?</LINE>
3918 </SPEECH>
3919
3920 <SPEECH>
3921 <SPEAKER>HAMLET</SPEAKER>
3922 <LINE>That if you be honest and fair, your honesty should</LINE>
3923 <LINE>admit no discourse to your beauty.</LINE>
3924 </SPEECH>
3925
3926 <SPEECH>
3927 <SPEAKER>OPHELIA</SPEAKER>
3928 <LINE>Could beauty, my lord, have better commerce than</LINE>
3929 <LINE>with honesty?</LINE>
3930 </SPEECH>
3931
3932 <SPEECH>
3933 <SPEAKER>HAMLET</SPEAKER>
3934 <LINE>Ay, truly; for the power of beauty will sooner</LINE>
3935 <LINE>transform honesty from what it is to a bawd than the</LINE>
3936 <LINE>force of honesty can translate beauty into his</LINE>
3937 <LINE>likeness: this was sometime a paradox, but now the</LINE>
3938 <LINE>time gives it proof. I did love you once.</LINE>
3939 </SPEECH>
3940
3941 <SPEECH>
3942 <SPEAKER>OPHELIA</SPEAKER>
3943 <LINE>Indeed, my lord, you made me believe so.</LINE>
3944 </SPEECH>
3945
3946 <SPEECH>
3947 <SPEAKER>HAMLET</SPEAKER>
3948 <LINE>You should not have believed me; for virtue cannot</LINE>
3949 <LINE>so inoculate our old stock but we shall relish of</LINE>
3950 <LINE>it: I loved you not.</LINE>
3951 </SPEECH>
3952
3953 <SPEECH>
3954 <SPEAKER>OPHELIA</SPEAKER>
3955 <LINE>I was the more deceived.</LINE>
3956 </SPEECH>
3957
3958 <SPEECH>
3959 <SPEAKER>HAMLET</SPEAKER>
3960 <LINE>Get thee to a nunnery: why wouldst thou be a</LINE>
3961 <LINE>breeder of sinners? I am myself indifferent honest;</LINE>
3962 <LINE>but yet I could accuse me of such things that it</LINE>
3963 <LINE>were better my mother had not borne me: I am very</LINE>
3964 <LINE>proud, revengeful, ambitious, with more offences at</LINE>
3965 <LINE>my beck than I have thoughts to put them in,</LINE>
3966 <LINE>imagination to give them shape, or time to act them</LINE>
3967 <LINE>in. What should such fellows as I do crawling</LINE>
3968 <LINE>between earth and heaven? We are arrant knaves,</LINE>
3969 <LINE>all; believe none of us. Go thy ways to a nunnery.</LINE>
3970 <LINE>Where's your father?</LINE>
3971 </SPEECH>
3972
3973 <SPEECH>
3974 <SPEAKER>OPHELIA</SPEAKER>
3975 <LINE>At home, my lord.</LINE>
3976 </SPEECH>
3977
3978 <SPEECH>
3979 <SPEAKER>HAMLET</SPEAKER>
3980 <LINE>Let the doors be shut upon him, that he may play the</LINE>
3981 <LINE>fool no where but in's own house. Farewell.</LINE>
3982 </SPEECH>
3983
3984 <SPEECH>
3985 <SPEAKER>OPHELIA</SPEAKER>
3986 <LINE>O, help him, you sweet heavens!</LINE>
3987 </SPEECH>
3988
3989 <SPEECH>
3990 <SPEAKER>HAMLET</SPEAKER>
3991 <LINE>If thou dost marry, I'll give thee this plague for</LINE>
3992 <LINE>thy dowry: be thou as chaste as ice, as pure as</LINE>
3993 <LINE>snow, thou shalt not escape calumny. Get thee to a</LINE>
3994 <LINE>nunnery, go: farewell. Or, if thou wilt needs</LINE>
3995 <LINE>marry, marry a fool; for wise men know well enough</LINE>
3996 <LINE>what monsters you make of them. To a nunnery, go,</LINE>
3997 <LINE>and quickly too. Farewell.</LINE>
3998 </SPEECH>
3999
4000 <SPEECH>
4001 <SPEAKER>OPHELIA</SPEAKER>
4002 <LINE>O heavenly powers, restore him!</LINE>
4003 </SPEECH>
4004
4005 <SPEECH>
4006 <SPEAKER>HAMLET</SPEAKER>
4007 <LINE>I have heard of your paintings too, well enough; God</LINE>
4008 <LINE>has given you one face, and you make yourselves</LINE>
4009 <LINE>another: you jig, you amble, and you lisp, and</LINE>
4010 <LINE>nick-name God's creatures, and make your wantonness</LINE>
4011 <LINE>your ignorance. Go to, I'll no more on't; it hath</LINE>
4012 <LINE>made me mad. I say, we will have no more marriages:</LINE>
4013 <LINE>those that are married already, all but one, shall</LINE>
4014 <LINE>live; the rest shall keep as they are. To a</LINE>
4015 <LINE>nunnery, go.</LINE>
4016 </SPEECH>
4017
4018
4019 <STAGEDIR>Exit</STAGEDIR>
4020
4021 <SPEECH>
4022 <SPEAKER>OPHELIA</SPEAKER>
4023 <LINE>O, what a noble mind is here o'erthrown!</LINE>
4024 <LINE>The courtier's, soldier's, scholar's, eye, tongue, sword;</LINE>
4025 <LINE>The expectancy and rose of the fair state,</LINE>
4026 <LINE>The glass of fashion and the mould of form,</LINE>
4027 <LINE>The observed of all observers, quite, quite down!</LINE>
4028 <LINE>And I, of ladies most deject and wretched,</LINE>
4029 <LINE>That suck'd the honey of his music vows,</LINE>
4030 <LINE>Now see that noble and most sovereign reason,</LINE>
4031 <LINE>Like sweet bells jangled, out of tune and harsh;</LINE>
4032 <LINE>That unmatch'd form and feature of blown youth</LINE>
4033 <LINE>Blasted with ecstasy: O, woe is me,</LINE>
4034 <LINE>To have seen what I have seen, see what I see!</LINE>
4035 </SPEECH>
4036
4037
4038 <STAGEDIR>Re-enter KING CLAUDIUS and POLONIUS</STAGEDIR>
4039
4040 <SPEECH>
4041 <SPEAKER>KING CLAUDIUS</SPEAKER>
4042 <LINE>Love! his affections do not that way tend;</LINE>
4043 <LINE>Nor what he spake, though it lack'd form a little,</LINE>
4044 <LINE>Was not like madness. There's something in his soul,</LINE>
4045 <LINE>O'er which his melancholy sits on brood;</LINE>
4046 <LINE>And I do doubt the hatch and the disclose</LINE>
4047 <LINE>Will be some danger: which for to prevent,</LINE>
4048 <LINE>I have in quick determination</LINE>
4049 <LINE>Thus set it down: he shall with speed to England,</LINE>
4050 <LINE>For the demand of our neglected tribute</LINE>
4051 <LINE>Haply the seas and countries different</LINE>
4052 <LINE>With variable objects shall expel</LINE>
4053 <LINE>This something-settled matter in his heart,</LINE>
4054 <LINE>Whereon his brains still beating puts him thus</LINE>
4055 <LINE>From fashion of himself. What think you on't?</LINE>
4056 </SPEECH>
4057
4058 <SPEECH>
4059 <SPEAKER>LORD POLONIUS</SPEAKER>
4060 <LINE>It shall do well: but yet do I believe</LINE>
4061 <LINE>The origin and commencement of his grief</LINE>
4062 <LINE>Sprung from neglected love. How now, Ophelia!</LINE>
4063 <LINE>You need not tell us what Lord Hamlet said;</LINE>
4064 <LINE>We heard it all. My lord, do as you please;</LINE>
4065 <LINE>But, if you hold it fit, after the play</LINE>
4066 <LINE>Let his queen mother all alone entreat him</LINE>
4067 <LINE>To show his grief: let her be round with him;</LINE>
4068 <LINE>And I'll be placed, so please you, in the ear</LINE>
4069 <LINE>Of all their conference. If she find him not,</LINE>
4070 <LINE>To England send him, or confine him where</LINE>
4071 <LINE>Your wisdom best shall think.</LINE>
4072 </SPEECH>
4073
4074 <SPEECH>
4075 <SPEAKER>KING CLAUDIUS</SPEAKER>
4076 <LINE>It shall be so:</LINE>
4077 <LINE>Madness in great ones must not unwatch'd go.</LINE>
4078 </SPEECH>
4079
4080
4081 <STAGEDIR>Exeunt</STAGEDIR>
4082 </SCENE>
4083
4084 <SCENE><TITLE>SCENE II. A hall in the castle.</TITLE>
4085 <STAGEDIR>Enter HAMLET and Players</STAGEDIR>
4086
4087 <SPEECH>
4088 <SPEAKER>HAMLET</SPEAKER>
4089 <LINE>Speak the speech, I pray you, as I pronounced it to</LINE>
4090 <LINE>you, trippingly on the tongue: but if you mouth it,</LINE>
4091 <LINE>as many of your players do, I had as lief the</LINE>
4092 <LINE>town-crier spoke my lines. Nor do not saw the air</LINE>
4093 <LINE>too much with your hand, thus, but use all gently;</LINE>
4094 <LINE>for in the very torrent, tempest, and, as I may say,</LINE>
4095 <LINE>the whirlwind of passion, you must acquire and beget</LINE>
4096 <LINE>a temperance that may give it smoothness. O, it</LINE>
4097 <LINE>offends me to the soul to hear a robustious</LINE>
4098 <LINE>periwig-pated fellow tear a passion to tatters, to</LINE>
4099 <LINE>very rags, to split the ears of the groundlings, who</LINE>
4100 <LINE>for the most part are capable of nothing but</LINE>
4101 <LINE>inexplicable dumbshows and noise: I would have such</LINE>
4102 <LINE>a fellow whipped for o'erdoing Termagant; it</LINE>
4103 <LINE>out-herods Herod: pray you, avoid it.</LINE>
4104 </SPEECH>
4105
4106 <SPEECH>
4107 <SPEAKER>First Player</SPEAKER>
4108 <LINE>I warrant your honour.</LINE>
4109 </SPEECH>
4110
4111 <SPEECH>
4112 <SPEAKER>HAMLET</SPEAKER>
4113 <LINE>Be not too tame neither, but let your own discretion</LINE>
4114 <LINE>be your tutor: suit the action to the word, the</LINE>
4115 <LINE>word to the action; with this special o'erstep not</LINE>
4116 <LINE>the modesty of nature: for any thing so overdone is</LINE>
4117 <LINE>from the purpose of playing, whose end, both at the</LINE>
4118 <LINE>first and now, was and is, to hold, as 'twere, the</LINE>
4119 <LINE>mirror up to nature; to show virtue her own feature,</LINE>
4120 <LINE>scorn her own image, and the very age and body of</LINE>
4121 <LINE>the time his form and pressure. Now this overdone,</LINE>
4122 <LINE>or come tardy off, though it make the unskilful</LINE>
4123 <LINE>laugh, cannot but make the judicious grieve; the</LINE>
4124 <LINE>censure of the which one must in your allowance</LINE>
4125 <LINE>o'erweigh a whole theatre of others. O, there be</LINE>
4126 <LINE>players that I have seen play, and heard others</LINE>
4127 <LINE>praise, and that highly, not to speak it profanely,</LINE>
4128 <LINE>that, neither having the accent of Christians nor</LINE>
4129 <LINE>the gait of Christian, pagan, nor man, have so</LINE>
4130 <LINE>strutted and bellowed that I have thought some of</LINE>
4131 <LINE>nature's journeymen had made men and not made them</LINE>
4132 <LINE>well, they imitated humanity so abominably.</LINE>
4133 </SPEECH>
4134
4135 <SPEECH>
4136 <SPEAKER>First Player</SPEAKER>
4137 <LINE>I hope we have reformed that indifferently with us,</LINE>
4138 <LINE>sir.</LINE>
4139 </SPEECH>
4140
4141 <SPEECH>
4142 <SPEAKER>HAMLET</SPEAKER>
4143 <LINE>O, reform it altogether. And let those that play</LINE>
4144 <LINE>your clowns speak no more than is set down for them;</LINE>
4145 <LINE>for there be of them that will themselves laugh, to</LINE>
4146 <LINE>set on some quantity of barren spectators to laugh</LINE>
4147 <LINE>too; though, in the mean time, some necessary</LINE>
4148 <LINE>question of the play be then to be considered:</LINE>
4149 <LINE>that's villanous, and shows a most pitiful ambition</LINE>
4150 <LINE>in the fool that uses it. Go, make you ready.</LINE>
4151 <STAGEDIR>Exeunt Players</STAGEDIR>
4152 <STAGEDIR>Enter POLONIUS, ROSENCRANTZ, and GUILDENSTERN</STAGEDIR>
4153 <LINE>How now, my lord! I will the king hear this piece of work?</LINE>
4154 </SPEECH>
4155
4156 <SPEECH>
4157 <SPEAKER>LORD POLONIUS</SPEAKER>
4158 <LINE>And the queen too, and that presently.</LINE>
4159 </SPEECH>
4160
4161 <SPEECH>
4162 <SPEAKER>HAMLET</SPEAKER>
4163 <LINE>Bid the players make haste.</LINE>
4164 <STAGEDIR>Exit POLONIUS</STAGEDIR>
4165 <LINE>Will you two help to hasten them?</LINE>
4166 </SPEECH>
4167
4168 <SPEECH>
4169 <SPEAKER>ROSENCRANTZ</SPEAKER>
4170 <SPEAKER>GUILDENSTERN</SPEAKER>
4171 <LINE>We will, my lord.</LINE>
4172 </SPEECH>
4173
4174 <STAGEDIR>Exeunt ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
4175
4176 <SPEECH>
4177 <SPEAKER>HAMLET</SPEAKER>
4178 <LINE>What ho! Horatio!</LINE>
4179 </SPEECH>
4180
4181
4182 <STAGEDIR>Enter HORATIO</STAGEDIR>
4183
4184 <SPEECH>
4185 <SPEAKER>HORATIO</SPEAKER>
4186 <LINE>Here, sweet lord, at your service.</LINE>
4187 </SPEECH>
4188
4189 <SPEECH>
4190 <SPEAKER>HAMLET</SPEAKER>
4191 <LINE>Horatio, thou art e'en as just a man</LINE>
4192 <LINE>As e'er my conversation coped withal.</LINE>
4193 </SPEECH>
4194
4195 <SPEECH>
4196 <SPEAKER>HORATIO</SPEAKER>
4197 <LINE>O, my dear lord,--</LINE>
4198 </SPEECH>
4199
4200 <SPEECH>
4201 <SPEAKER>HAMLET</SPEAKER>
4202 <LINE>Nay, do not think I flatter;</LINE>
4203 <LINE>For what advancement may I hope from thee</LINE>
4204 <LINE>That no revenue hast but thy good spirits,</LINE>
4205 <LINE>To feed and clothe thee? Why should the poor be flatter'd?</LINE>
4206 <LINE>No, let the candied tongue lick absurd pomp,</LINE>
4207 <LINE>And crook the pregnant hinges of the knee</LINE>
4208 <LINE>Where thrift may follow fawning. Dost thou hear?</LINE>
4209 <LINE>Since my dear soul was mistress of her choice</LINE>
4210 <LINE>And could of men distinguish, her election</LINE>
4211 <LINE>Hath seal'd thee for herself; for thou hast been</LINE>
4212 <LINE>As one, in suffering all, that suffers nothing,</LINE>
4213 <LINE>A man that fortune's buffets and rewards</LINE>
4214 <LINE>Hast ta'en with equal thanks: and blest are those</LINE>
4215 <LINE>Whose blood and judgment are so well commingled,</LINE>
4216 <LINE>That they are not a pipe for fortune's finger</LINE>
4217 <LINE>To sound what stop she please. Give me that man</LINE>
4218 <LINE>That is not passion's slave, and I will wear him</LINE>
4219 <LINE>In my heart's core, ay, in my heart of heart,</LINE>
4220 <LINE>As I do thee.--Something too much of this.--</LINE>
4221 <LINE>There is a play to-night before the king;</LINE>
4222 <LINE>One scene of it comes near the circumstance</LINE>
4223 <LINE>Which I have told thee of my father's death:</LINE>
4224 <LINE>I prithee, when thou seest that act afoot,</LINE>
4225 <LINE>Even with the very comment of thy soul</LINE>
4226 <LINE>Observe mine uncle: if his occulted guilt</LINE>
4227 <LINE>Do not itself unkennel in one speech,</LINE>
4228 <LINE>It is a damned ghost that we have seen,</LINE>
4229 <LINE>And my imaginations are as foul</LINE>
4230 <LINE>As Vulcan's stithy. Give him heedful note;</LINE>
4231 <LINE>For I mine eyes will rivet to his face,</LINE>
4232 <LINE>And after we will both our judgments join</LINE>
4233 <LINE>In censure of his seeming.</LINE>
4234 </SPEECH>
4235
4236 <SPEECH>
4237 <SPEAKER>HORATIO</SPEAKER>
4238 <LINE>Well, my lord:</LINE>
4239 <LINE>If he steal aught the whilst this play is playing,</LINE>
4240 <LINE>And 'scape detecting, I will pay the theft.</LINE>
4241 </SPEECH>
4242
4243 <SPEECH>
4244 <SPEAKER>HAMLET</SPEAKER>
4245 <LINE>They are coming to the play; I must be idle:</LINE>
4246 <LINE>Get you a place.</LINE>
4247 </SPEECH>
4248
4249
4250 <STAGEDIR>Danish march. A flourish. Enter KING CLAUDIUS,
4251 QUEEN GERTRUDE, POLONIUS, OPHELIA, ROSENCRANTZ,
4252 GUILDENSTERN, and others</STAGEDIR>
4253
4254 <SPEECH>
4255 <SPEAKER>KING CLAUDIUS</SPEAKER>
4256 <LINE>How fares our cousin Hamlet?</LINE>
4257 </SPEECH>
4258
4259 <SPEECH>
4260 <SPEAKER>HAMLET</SPEAKER>
4261 <LINE>Excellent, i' faith; of the chameleon's dish: I eat</LINE>
4262 <LINE>the air, promise-crammed: you cannot feed capons so.</LINE>
4263 </SPEECH>
4264
4265 <SPEECH>
4266 <SPEAKER>KING CLAUDIUS</SPEAKER>
4267 <LINE>I have nothing with this answer, Hamlet; these words</LINE>
4268 <LINE>are not mine.</LINE>
4269 </SPEECH>
4270
4271 <SPEECH>
4272 <SPEAKER>HAMLET</SPEAKER>
4273 <LINE>No, nor mine now.</LINE>
4274 <STAGEDIR>To POLONIUS</STAGEDIR>
4275 <LINE>My lord, you played once i' the university, you say?</LINE>
4276 </SPEECH>
4277
4278 <SPEECH>
4279 <SPEAKER>LORD POLONIUS</SPEAKER>
4280 <LINE>That did I, my lord; and was accounted a good actor.</LINE>
4281 </SPEECH>
4282
4283 <SPEECH>
4284 <SPEAKER>HAMLET</SPEAKER>
4285 <LINE>What did you enact?</LINE>
4286 </SPEECH>
4287
4288 <SPEECH>
4289 <SPEAKER>LORD POLONIUS</SPEAKER>
4290 <LINE>I did enact Julius Caesar: I was killed i' the</LINE>
4291 <LINE>Capitol; Brutus killed me.</LINE>
4292 </SPEECH>
4293
4294 <SPEECH>
4295 <SPEAKER>HAMLET</SPEAKER>
4296 <LINE>It was a brute part of him to kill so capital a calf</LINE>
4297 <LINE>there. Be the players ready?</LINE>
4298 </SPEECH>
4299
4300 <SPEECH>
4301 <SPEAKER>ROSENCRANTZ</SPEAKER>
4302 <LINE>Ay, my lord; they stay upon your patience.</LINE>
4303 </SPEECH>
4304
4305 <SPEECH>
4306 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
4307 <LINE>Come hither, my dear Hamlet, sit by me.</LINE>
4308 </SPEECH>
4309
4310 <SPEECH>
4311 <SPEAKER>HAMLET</SPEAKER>
4312 <LINE>No, good mother, here's metal more attractive.</LINE>
4313 </SPEECH>
4314
4315 <SPEECH>
4316 <SPEAKER>LORD POLONIUS</SPEAKER>
4317 <LINE><STAGEDIR>To KING CLAUDIUS</STAGEDIR> O, ho! do you mark that?</LINE>
4318 </SPEECH>
4319
4320 <SPEECH>
4321 <SPEAKER>HAMLET</SPEAKER>
4322 <LINE>Lady, shall I lie in your lap?</LINE>
4323 </SPEECH>
4324
4325
4326 <STAGEDIR>Lying down at OPHELIA's feet</STAGEDIR>
4327
4328 <SPEECH>
4329 <SPEAKER>OPHELIA</SPEAKER>
4330 <LINE>No, my lord.</LINE>
4331 </SPEECH>
4332
4333 <SPEECH>
4334 <SPEAKER>HAMLET</SPEAKER>
4335 <LINE>I mean, my head upon your lap?</LINE>
4336 </SPEECH>
4337
4338 <SPEECH>
4339 <SPEAKER>OPHELIA</SPEAKER>
4340 <LINE>Ay, my lord.</LINE>
4341 </SPEECH>
4342
4343 <SPEECH>
4344 <SPEAKER>HAMLET</SPEAKER>
4345 <LINE>Do you think I meant country matters?</LINE>
4346 </SPEECH>
4347
4348 <SPEECH>
4349 <SPEAKER>OPHELIA</SPEAKER>
4350 <LINE>I think nothing, my lord.</LINE>
4351 </SPEECH>
4352
4353 <SPEECH>
4354 <SPEAKER>HAMLET</SPEAKER>
4355 <LINE>That's a fair thought to lie between maids' legs.</LINE>
4356 </SPEECH>
4357
4358 <SPEECH>
4359 <SPEAKER>OPHELIA</SPEAKER>
4360 <LINE>What is, my lord?</LINE>
4361 </SPEECH>
4362
4363 <SPEECH>
4364 <SPEAKER>HAMLET</SPEAKER>
4365 <LINE>Nothing.</LINE>
4366 </SPEECH>
4367
4368 <SPEECH>
4369 <SPEAKER>OPHELIA</SPEAKER>
4370 <LINE>You are merry, my lord.</LINE>
4371 </SPEECH>
4372
4373 <SPEECH>
4374 <SPEAKER>HAMLET</SPEAKER>
4375 <LINE>Who, I?</LINE>
4376 </SPEECH>
4377
4378 <SPEECH>
4379 <SPEAKER>OPHELIA</SPEAKER>
4380 <LINE>Ay, my lord.</LINE>
4381 </SPEECH>
4382
4383 <SPEECH>
4384 <SPEAKER>HAMLET</SPEAKER>
4385 <LINE>O God, your only jig-maker. What should a man do</LINE>
4386 <LINE>but be merry? for, look you, how cheerfully my</LINE>
4387 <LINE>mother looks, and my father died within these two hours.</LINE>
4388 </SPEECH>
4389
4390 <SPEECH>
4391 <SPEAKER>OPHELIA</SPEAKER>
4392 <LINE>Nay, 'tis twice two months, my lord.</LINE>
4393 </SPEECH>
4394
4395 <SPEECH>
4396 <SPEAKER>HAMLET</SPEAKER>
4397 <LINE>So long? Nay then, let the devil wear black, for</LINE>
4398 <LINE>I'll have a suit of sables. O heavens! die two</LINE>
4399 <LINE>months ago, and not forgotten yet? Then there's</LINE>
4400 <LINE>hope a great man's memory may outlive his life half</LINE>
4401 <LINE>a year: but, by'r lady, he must build churches,</LINE>
4402 <LINE>then; or else shall he suffer not thinking on, with</LINE>
4403 <LINE>the hobby-horse, whose epitaph is 'For, O, for, O,</LINE>
4404 <LINE>the hobby-horse is forgot.'</LINE>
4405 <STAGEDIR>Hautboys play. The dumb-show enters</STAGEDIR>
4406 </SPEECH>
4407
4408 <STAGEDIR>Enter a King and a Queen very lovingly; the Queen
4409 embracing him, and he her. She kneels, and makes
4410 show of protestation unto him. He takes her up,
4411 and declines his head upon her neck: lays him down
4412 upon a bank of flowers: she, seeing him asleep,
4413 leaves him. Anon comes in a fellow, takes off his
4414 crown, kisses it, and pours poison in the King's
4415 ears, and exit. The Queen returns; finds the King
4416 dead, and makes passionate action. The Poisoner,
4417 with some two or three Mutes, comes in again,
4418 seeming to lament with her. The dead body is
4419 carried away. The Poisoner wooes the Queen with
4420 gifts: she seems loath and unwilling awhile, but
4421 in the end accepts his love</STAGEDIR>
4422 <STAGEDIR>Exeunt</STAGEDIR>
4423
4424 <SPEECH>
4425 <SPEAKER>OPHELIA</SPEAKER>
4426 <LINE>What means this, my lord?</LINE>
4427 </SPEECH>
4428
4429 <SPEECH>
4430 <SPEAKER>HAMLET</SPEAKER>
4431 <LINE>Marry, this is miching mallecho; it means mischief.</LINE>
4432 </SPEECH>
4433
4434 <SPEECH>
4435 <SPEAKER>OPHELIA</SPEAKER>
4436 <LINE>Belike this show imports the argument of the play.</LINE>
4437 </SPEECH>
4438
4439
4440 <STAGEDIR>Enter Prologue</STAGEDIR>
4441
4442 <SPEECH>
4443 <SPEAKER>HAMLET</SPEAKER>
4444 <LINE>We shall know by this fellow: the players cannot</LINE>
4445 <LINE>keep counsel; they'll tell all.</LINE>
4446 </SPEECH>
4447
4448 <SPEECH>
4449 <SPEAKER>OPHELIA</SPEAKER>
4450 <LINE>Will he tell us what this show meant?</LINE>
4451 </SPEECH>
4452
4453 <SPEECH>
4454 <SPEAKER>HAMLET</SPEAKER>
4455 <LINE>Ay, or any show that you'll show him: be not you</LINE>
4456 <LINE>ashamed to show, he'll not shame to tell you what it means.</LINE>
4457 </SPEECH>
4458
4459 <SPEECH>
4460 <SPEAKER>OPHELIA</SPEAKER>
4461 <LINE>You are naught, you are naught: I'll mark the play.</LINE>
4462 </SPEECH>
4463
4464 <SPEECH>
4465 <SPEAKER>Prologue</SPEAKER>
4466 <LINE>For us, and for our tragedy,</LINE>
4467 <LINE>Here stooping to your clemency,</LINE>
4468 <LINE>We beg your hearing patiently.</LINE>
4469 </SPEECH>
4470
4471
4472 <STAGEDIR>Exit</STAGEDIR>
4473
4474 <SPEECH>
4475 <SPEAKER>HAMLET</SPEAKER>
4476 <LINE>Is this a prologue, or the posy of a ring?</LINE>
4477 </SPEECH>
4478
4479 <SPEECH>
4480 <SPEAKER>OPHELIA</SPEAKER>
4481 <LINE>'Tis brief, my lord.</LINE>
4482 </SPEECH>
4483
4484 <SPEECH>
4485 <SPEAKER>HAMLET</SPEAKER>
4486 <LINE>As woman's love.</LINE>
4487 </SPEECH>
4488
4489
4490 <STAGEDIR>Enter two Players, King and Queen</STAGEDIR>
4491
4492 <SPEECH>
4493 <SPEAKER>Player King</SPEAKER>
4494 <LINE>Full thirty times hath Phoebus' cart gone round</LINE>
4495 <LINE>Neptune's salt wash and Tellus' orbed ground,</LINE>
4496 <LINE>And thirty dozen moons with borrow'd sheen</LINE>
4497 <LINE>About the world have times twelve thirties been,</LINE>
4498 <LINE>Since love our hearts and Hymen did our hands</LINE>
4499 <LINE>Unite commutual in most sacred bands.</LINE>
4500 </SPEECH>
4501
4502 <SPEECH>
4503 <SPEAKER>Player Queen</SPEAKER>
4504 <LINE>So many journeys may the sun and moon</LINE>
4505 <LINE>Make us again count o'er ere love be done!</LINE>
4506 <LINE>But, woe is me, you are so sick of late,</LINE>
4507 <LINE>So far from cheer and from your former state,</LINE>
4508 <LINE>That I distrust you. Yet, though I distrust,</LINE>
4509 <LINE>Discomfort you, my lord, it nothing must:</LINE>
4510 <LINE>For women's fear and love holds quantity;</LINE>
4511 <LINE>In neither aught, or in extremity.</LINE>
4512 <LINE>Now, what my love is, proof hath made you know;</LINE>
4513 <LINE>And as my love is sized, my fear is so:</LINE>
4514 <LINE>Where love is great, the littlest doubts are fear;</LINE>
4515 <LINE>Where little fears grow great, great love grows there.</LINE>
4516 </SPEECH>
4517
4518 <SPEECH>
4519 <SPEAKER>Player King</SPEAKER>
4520 <LINE>'Faith, I must leave thee, love, and shortly too;</LINE>
4521 <LINE>My operant powers their functions leave to do:</LINE>
4522 <LINE>And thou shalt live in this fair world behind,</LINE>
4523 <LINE>Honour'd, beloved; and haply one as kind</LINE>
4524 <LINE>For husband shalt thou--</LINE>
4525 </SPEECH>
4526
4527 <SPEECH>
4528 <SPEAKER>Player Queen</SPEAKER>
4529 <LINE>O, confound the rest!</LINE>
4530 <LINE>Such love must needs be treason in my breast:</LINE>
4531 <LINE>In second husband let me be accurst!</LINE>
4532 <LINE>None wed the second but who kill'd the first.</LINE>
4533 </SPEECH>
4534
4535 <SPEECH>
4536 <SPEAKER>HAMLET</SPEAKER>
4537 <LINE><STAGEDIR>Aside</STAGEDIR> Wormwood, wormwood.</LINE>
4538 </SPEECH>
4539
4540 <SPEECH>
4541 <SPEAKER>Player Queen</SPEAKER>
4542 <LINE>The instances that second marriage move</LINE>
4543 <LINE>Are base respects of thrift, but none of love:</LINE>
4544 <LINE>A second time I kill my husband dead,</LINE>
4545 <LINE>When second husband kisses me in bed.</LINE>
4546 </SPEECH>
4547
4548 <SPEECH>
4549 <SPEAKER>Player King</SPEAKER>
4550 <LINE>I do believe you think what now you speak;</LINE>
4551 <LINE>But what we do determine oft we break.</LINE>
4552 <LINE>Purpose is but the slave to memory,</LINE>
4553 <LINE>Of violent birth, but poor validity;</LINE>
4554 <LINE>Which now, like fruit unripe, sticks on the tree;</LINE>
4555 <LINE>But fall, unshaken, when they mellow be.</LINE>
4556 <LINE>Most necessary 'tis that we forget</LINE>
4557 <LINE>To pay ourselves what to ourselves is debt:</LINE>
4558 <LINE>What to ourselves in passion we propose,</LINE>
4559 <LINE>The passion ending, doth the purpose lose.</LINE>
4560 <LINE>The violence of either grief or joy</LINE>
4561 <LINE>Their own enactures with themselves destroy:</LINE>
4562 <LINE>Where joy most revels, grief doth most lament;</LINE>
4563 <LINE>Grief joys, joy grieves, on slender accident.</LINE>
4564 <LINE>This world is not for aye, nor 'tis not strange</LINE>
4565 <LINE>That even our loves should with our fortunes change;</LINE>
4566 <LINE>For 'tis a question left us yet to prove,</LINE>
4567 <LINE>Whether love lead fortune, or else fortune love.</LINE>
4568 <LINE>The great man down, you mark his favourite flies;</LINE>
4569 <LINE>The poor advanced makes friends of enemies.</LINE>
4570 <LINE>And hitherto doth love on fortune tend;</LINE>
4571 <LINE>For who not needs shall never lack a friend,</LINE>
4572 <LINE>And who in want a hollow friend doth try,</LINE>
4573 <LINE>Directly seasons him his enemy.</LINE>
4574 <LINE>But, orderly to end where I begun,</LINE>
4575 <LINE>Our wills and fates do so contrary run</LINE>
4576 <LINE>That our devices still are overthrown;</LINE>
4577 <LINE>Our thoughts are ours, their ends none of our own:</LINE>
4578 <LINE>So think thou wilt no second husband wed;</LINE>
4579 <LINE>But die thy thoughts when thy first lord is dead.</LINE>
4580 </SPEECH>
4581
4582 <SPEECH>
4583 <SPEAKER>Player Queen</SPEAKER>
4584 <LINE>Nor earth to me give food, nor heaven light!</LINE>
4585 <LINE>Sport and repose lock from me day and night!</LINE>
4586 <LINE>To desperation turn my trust and hope!</LINE>
4587 <LINE>An anchor's cheer in prison be my scope!</LINE>
4588 <LINE>Each opposite that blanks the face of joy</LINE>
4589 <LINE>Meet what I would have well and it destroy!</LINE>
4590 <LINE>Both here and hence pursue me lasting strife,</LINE>
4591 <LINE>If, once a widow, ever I be wife!</LINE>
4592 </SPEECH>
4593
4594 <SPEECH>
4595 <SPEAKER>HAMLET</SPEAKER>
4596 <LINE>If she should break it now!</LINE>
4597 </SPEECH>
4598
4599 <SPEECH>
4600 <SPEAKER>Player King</SPEAKER>
4601 <LINE>'Tis deeply sworn. Sweet, leave me here awhile;</LINE>
4602 <LINE>My spirits grow dull, and fain I would beguile</LINE>
4603 <LINE>The tedious day with sleep.</LINE>
4604 </SPEECH>
4605
4606
4607 <STAGEDIR>Sleeps</STAGEDIR>
4608
4609 <SPEECH>
4610 <SPEAKER>Player Queen</SPEAKER>
4611 <LINE>Sleep rock thy brain,</LINE>
4612 <LINE>And never come mischance between us twain!</LINE>
4613 </SPEECH>
4614
4615
4616 <STAGEDIR>Exit</STAGEDIR>
4617
4618 <SPEECH>
4619 <SPEAKER>HAMLET</SPEAKER>
4620 <LINE>Madam, how like you this play?</LINE>
4621 </SPEECH>
4622
4623 <SPEECH>
4624 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
4625 <LINE>The lady protests too much, methinks.</LINE>
4626 </SPEECH>
4627
4628 <SPEECH>
4629 <SPEAKER>HAMLET</SPEAKER>
4630 <LINE>O, but she'll keep her word.</LINE>
4631 </SPEECH>
4632
4633 <SPEECH>
4634 <SPEAKER>KING CLAUDIUS</SPEAKER>
4635 <LINE>Have you heard the argument? Is there no offence in 't?</LINE>
4636 </SPEECH>
4637
4638 <SPEECH>
4639 <SPEAKER>HAMLET</SPEAKER>
4640 <LINE>No, no, they do but jest, poison in jest; no offence</LINE>
4641 <LINE>i' the world.</LINE>
4642 </SPEECH>
4643
4644 <SPEECH>
4645 <SPEAKER>KING CLAUDIUS</SPEAKER>
4646 <LINE>What do you call the play?</LINE>
4647 </SPEECH>
4648
4649 <SPEECH>
4650 <SPEAKER>HAMLET</SPEAKER>
4651 <LINE>The Mouse-trap. Marry, how? Tropically. This play</LINE>
4652 <LINE>is the image of a murder done in Vienna: Gonzago is</LINE>
4653 <LINE>the duke's name; his wife, Baptista: you shall see</LINE>
4654 <LINE>anon; 'tis a knavish piece of work: but what o'</LINE>
4655 <LINE>that? your majesty and we that have free souls, it</LINE>
4656 <LINE>touches us not: let the galled jade wince, our</LINE>
4657 <LINE>withers are unwrung.</LINE>
4658 <STAGEDIR>Enter LUCIANUS</STAGEDIR>
4659 <LINE>This is one Lucianus, nephew to the king.</LINE>
4660 </SPEECH>
4661
4662 <SPEECH>
4663 <SPEAKER>OPHELIA</SPEAKER>
4664 <LINE>You are as good as a chorus, my lord.</LINE>
4665 </SPEECH>
4666
4667 <SPEECH>
4668 <SPEAKER>HAMLET</SPEAKER>
4669 <LINE>I could interpret between you and your love, if I</LINE>
4670 <LINE>could see the puppets dallying.</LINE>
4671 </SPEECH>
4672
4673 <SPEECH>
4674 <SPEAKER>OPHELIA</SPEAKER>
4675 <LINE>You are keen, my lord, you are keen.</LINE>
4676 </SPEECH>
4677
4678 <SPEECH>
4679 <SPEAKER>HAMLET</SPEAKER>
4680 <LINE>It would cost you a groaning to take off my edge.</LINE>
4681 </SPEECH>
4682
4683 <SPEECH>
4684 <SPEAKER>OPHELIA</SPEAKER>
4685 <LINE>Still better, and worse.</LINE>
4686 </SPEECH>
4687
4688 <SPEECH>
4689 <SPEAKER>HAMLET</SPEAKER>
4690 <LINE>So you must take your husbands. Begin, murderer;</LINE>
4691 <LINE>pox, leave thy damnable faces, and begin. Come:</LINE>
4692 <LINE>'the croaking raven doth bellow for revenge.'</LINE>
4693 </SPEECH>
4694
4695 <SPEECH>
4696 <SPEAKER>LUCIANUS</SPEAKER>
4697 <LINE>Thoughts black, hands apt, drugs fit, and time agreeing;</LINE>
4698 <LINE>Confederate season, else no creature seeing;</LINE>
4699 <LINE>Thou mixture rank, of midnight weeds collected,</LINE>
4700 <LINE>With Hecate's ban thrice blasted, thrice infected,</LINE>
4701 <LINE>Thy natural magic and dire property,</LINE>
4702 <LINE>On wholesome life usurp immediately.</LINE>
4703 </SPEECH>
4704
4705
4706 <STAGEDIR>Pours the poison into the sleeper's ears</STAGEDIR>
4707
4708 <SPEECH>
4709 <SPEAKER>HAMLET</SPEAKER>
4710 <LINE>He poisons him i' the garden for's estate. His</LINE>
4711 <LINE>name's Gonzago: the story is extant, and writ in</LINE>
4712 <LINE>choice Italian: you shall see anon how the murderer</LINE>
4713 <LINE>gets the love of Gonzago's wife.</LINE>
4714 </SPEECH>
4715
4716 <SPEECH>
4717 <SPEAKER>OPHELIA</SPEAKER>
4718 <LINE>The king rises.</LINE>
4719 </SPEECH>
4720
4721 <SPEECH>
4722 <SPEAKER>HAMLET</SPEAKER>
4723 <LINE>What, frighted with false fire!</LINE>
4724 </SPEECH>
4725
4726 <SPEECH>
4727 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
4728 <LINE>How fares my lord?</LINE>
4729 </SPEECH>
4730
4731 <SPEECH>
4732 <SPEAKER>LORD POLONIUS</SPEAKER>
4733 <LINE>Give o'er the play.</LINE>
4734 </SPEECH>
4735
4736 <SPEECH>
4737 <SPEAKER>KING CLAUDIUS</SPEAKER>
4738 <LINE>Give me some light: away!</LINE>
4739 </SPEECH>
4740
4741 <SPEECH>
4742 <SPEAKER>All</SPEAKER>
4743 <LINE>Lights, lights, lights!</LINE>
4744 </SPEECH>
4745
4746
4747 <STAGEDIR>Exeunt all but HAMLET and HORATIO</STAGEDIR>
4748
4749 <SPEECH>
4750 <SPEAKER>HAMLET</SPEAKER>
4751 <LINE>Why, let the stricken deer go weep,</LINE>
4752 <LINE>The hart ungalled play;</LINE>
4753 <LINE>For some must watch, while some must sleep:</LINE>
4754 <LINE>So runs the world away.</LINE>
4755 <LINE>Would not this, sir, and a forest of feathers-- if</LINE>
4756 <LINE>the rest of my fortunes turn Turk with me--with two</LINE>
4757 <LINE>Provincial roses on my razed shoes, get me a</LINE>
4758 <LINE>fellowship in a cry of players, sir?</LINE>
4759 </SPEECH>
4760
4761 <SPEECH>
4762 <SPEAKER>HORATIO</SPEAKER>
4763 <LINE>Half a share.</LINE>
4764 </SPEECH>
4765
4766 <SPEECH>
4767 <SPEAKER>HAMLET</SPEAKER>
4768 <LINE>A whole one, I.</LINE>
4769 <LINE>For thou dost know, O Damon dear,</LINE>
4770 <LINE>This realm dismantled was</LINE>
4771 <LINE>Of Jove himself; and now reigns here</LINE>
4772 <LINE>A very, very--pajock.</LINE>
4773 </SPEECH>
4774
4775 <SPEECH>
4776 <SPEAKER>HORATIO</SPEAKER>
4777 <LINE>You might have rhymed.</LINE>
4778 </SPEECH>
4779
4780 <SPEECH>
4781 <SPEAKER>HAMLET</SPEAKER>
4782 <LINE>O good Horatio, I'll take the ghost's word for a</LINE>
4783 <LINE>thousand pound. Didst perceive?</LINE>
4784 </SPEECH>
4785
4786 <SPEECH>
4787 <SPEAKER>HORATIO</SPEAKER>
4788 <LINE>Very well, my lord.</LINE>
4789 </SPEECH>
4790
4791 <SPEECH>
4792 <SPEAKER>HAMLET</SPEAKER>
4793 <LINE>Upon the talk of the poisoning?</LINE>
4794 </SPEECH>
4795
4796 <SPEECH>
4797 <SPEAKER>HORATIO</SPEAKER>
4798 <LINE>I did very well note him.</LINE>
4799 </SPEECH>
4800
4801 <SPEECH>
4802 <SPEAKER>HAMLET</SPEAKER>
4803 <LINE>Ah, ha! Come, some music! come, the recorders!</LINE>
4804 <LINE>For if the king like not the comedy,</LINE>
4805 <LINE>Why then, belike, he likes it not, perdy.</LINE>
4806 <LINE>Come, some music!</LINE>
4807 </SPEECH>
4808
4809
4810 <STAGEDIR>Re-enter ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
4811
4812 <SPEECH>
4813 <SPEAKER>GUILDENSTERN</SPEAKER>
4814 <LINE>Good my lord, vouchsafe me a word with you.</LINE>
4815 </SPEECH>
4816
4817 <SPEECH>
4818 <SPEAKER>HAMLET</SPEAKER>
4819 <LINE>Sir, a whole history.</LINE>
4820 </SPEECH>
4821
4822 <SPEECH>
4823 <SPEAKER>GUILDENSTERN</SPEAKER>
4824 <LINE>The king, sir,--</LINE>
4825 </SPEECH>
4826
4827 <SPEECH>
4828 <SPEAKER>HAMLET</SPEAKER>
4829 <LINE>Ay, sir, what of him?</LINE>
4830 </SPEECH>
4831
4832 <SPEECH>
4833 <SPEAKER>GUILDENSTERN</SPEAKER>
4834 <LINE>Is in his retirement marvellous distempered.</LINE>
4835 </SPEECH>
4836
4837 <SPEECH>
4838 <SPEAKER>HAMLET</SPEAKER>
4839 <LINE>With drink, sir?</LINE>
4840 </SPEECH>
4841
4842 <SPEECH>
4843 <SPEAKER>GUILDENSTERN</SPEAKER>
4844 <LINE>No, my lord, rather with choler.</LINE>
4845 </SPEECH>
4846
4847 <SPEECH>
4848 <SPEAKER>HAMLET</SPEAKER>
4849 <LINE>Your wisdom should show itself more richer to</LINE>
4850 <LINE>signify this to his doctor; for, for me to put him</LINE>
4851 <LINE>to his purgation would perhaps plunge him into far</LINE>
4852 <LINE>more choler.</LINE>
4853 </SPEECH>
4854
4855 <SPEECH>
4856 <SPEAKER>GUILDENSTERN</SPEAKER>
4857 <LINE>Good my lord, put your discourse into some frame and</LINE>
4858 <LINE>start not so wildly from my affair.</LINE>
4859 </SPEECH>
4860
4861 <SPEECH>
4862 <SPEAKER>HAMLET</SPEAKER>
4863 <LINE>I am tame, sir: pronounce.</LINE>
4864 </SPEECH>
4865
4866 <SPEECH>
4867 <SPEAKER>GUILDENSTERN</SPEAKER>
4868 <LINE>The queen, your mother, in most great affliction of</LINE>
4869 <LINE>spirit, hath sent me to you.</LINE>
4870 </SPEECH>
4871
4872 <SPEECH>
4873 <SPEAKER>HAMLET</SPEAKER>
4874 <LINE>You are welcome.</LINE>
4875 </SPEECH>
4876
4877 <SPEECH>
4878 <SPEAKER>GUILDENSTERN</SPEAKER>
4879 <LINE>Nay, good my lord, this courtesy is not of the right</LINE>
4880 <LINE>breed. If it shall please you to make me a</LINE>
4881 <LINE>wholesome answer, I will do your mother's</LINE>
4882 <LINE>commandment: if not, your pardon and my return</LINE>
4883 <LINE>shall be the end of my business.</LINE>
4884 </SPEECH>
4885
4886 <SPEECH>
4887 <SPEAKER>HAMLET</SPEAKER>
4888 <LINE>Sir, I cannot.</LINE>
4889 </SPEECH>
4890
4891 <SPEECH>
4892 <SPEAKER>GUILDENSTERN</SPEAKER>
4893 <LINE>What, my lord?</LINE>
4894 </SPEECH>
4895
4896 <SPEECH>
4897 <SPEAKER>HAMLET</SPEAKER>
4898 <LINE>Make you a wholesome answer; my wit's diseased: but,</LINE>
4899 <LINE>sir, such answer as I can make, you shall command;</LINE>
4900 <LINE>or, rather, as you say, my mother: therefore no</LINE>
4901 <LINE>more, but to the matter: my mother, you say,--</LINE>
4902 </SPEECH>
4903
4904 <SPEECH>
4905 <SPEAKER>ROSENCRANTZ</SPEAKER>
4906 <LINE>Then thus she says; your behavior hath struck her</LINE>
4907 <LINE>into amazement and admiration.</LINE>
4908 </SPEECH>
4909
4910 <SPEECH>
4911 <SPEAKER>HAMLET</SPEAKER>
4912 <LINE>O wonderful son, that can so astonish a mother! But</LINE>
4913 <LINE>is there no sequel at the heels of this mother's</LINE>
4914 <LINE>admiration? Impart.</LINE>
4915 </SPEECH>
4916
4917 <SPEECH>
4918 <SPEAKER>ROSENCRANTZ</SPEAKER>
4919 <LINE>She desires to speak with you in her closet, ere you</LINE>
4920 <LINE>go to bed.</LINE>
4921 </SPEECH>
4922
4923 <SPEECH>
4924 <SPEAKER>HAMLET</SPEAKER>
4925 <LINE>We shall obey, were she ten times our mother. Have</LINE>
4926 <LINE>you any further trade with us?</LINE>
4927 </SPEECH>
4928
4929 <SPEECH>
4930 <SPEAKER>ROSENCRANTZ</SPEAKER>
4931 <LINE>My lord, you once did love me.</LINE>
4932 </SPEECH>
4933
4934 <SPEECH>
4935 <SPEAKER>HAMLET</SPEAKER>
4936 <LINE>So I do still, by these pickers and stealers.</LINE>
4937 </SPEECH>
4938
4939 <SPEECH>
4940 <SPEAKER>ROSENCRANTZ</SPEAKER>
4941 <LINE>Good my lord, what is your cause of distemper? you</LINE>
4942 <LINE>do, surely, bar the door upon your own liberty, if</LINE>
4943 <LINE>you deny your griefs to your friend.</LINE>
4944 </SPEECH>
4945
4946 <SPEECH>
4947 <SPEAKER>HAMLET</SPEAKER>
4948 <LINE>Sir, I lack advancement.</LINE>
4949 </SPEECH>
4950
4951 <SPEECH>
4952 <SPEAKER>ROSENCRANTZ</SPEAKER>
4953 <LINE>How can that be, when you have the voice of the king</LINE>
4954 <LINE>himself for your succession in Denmark?</LINE>
4955 </SPEECH>
4956
4957 <SPEECH>
4958 <SPEAKER>HAMLET</SPEAKER>
4959 <LINE>Ay, but sir, 'While the grass grows,'--the proverb</LINE>
4960 <LINE>is something musty.</LINE>
4961 <STAGEDIR>Re-enter Players with recorders</STAGEDIR>
4962 <LINE>O, the recorders! let me see one. To withdraw with</LINE>
4963 <LINE>you:--why do you go about to recover the wind of me,</LINE>
4964 <LINE>as if you would drive me into a toil?</LINE>
4965 </SPEECH>
4966
4967 <SPEECH>
4968 <SPEAKER>GUILDENSTERN</SPEAKER>
4969 <LINE>O, my lord, if my duty be too bold, my love is too</LINE>
4970 <LINE>unmannerly.</LINE>
4971 </SPEECH>
4972
4973 <SPEECH>
4974 <SPEAKER>HAMLET</SPEAKER>
4975 <LINE>I do not well understand that. Will you play upon</LINE>
4976 <LINE>this pipe?</LINE>
4977 </SPEECH>
4978
4979 <SPEECH>
4980 <SPEAKER>GUILDENSTERN</SPEAKER>
4981 <LINE>My lord, I cannot.</LINE>
4982 </SPEECH>
4983
4984 <SPEECH>
4985 <SPEAKER>HAMLET</SPEAKER>
4986 <LINE>I pray you.</LINE>
4987 </SPEECH>
4988
4989 <SPEECH>
4990 <SPEAKER>GUILDENSTERN</SPEAKER>
4991 <LINE>Believe me, I cannot.</LINE>
4992 </SPEECH>
4993
4994 <SPEECH>
4995 <SPEAKER>HAMLET</SPEAKER>
4996 <LINE>I do beseech you.</LINE>
4997 </SPEECH>
4998
4999 <SPEECH>
5000 <SPEAKER>GUILDENSTERN</SPEAKER>
5001 <LINE>I know no touch of it, my lord.</LINE>
5002 </SPEECH>
5003
5004 <SPEECH>
5005 <SPEAKER>HAMLET</SPEAKER>
5006 <LINE>'Tis as easy as lying: govern these ventages with</LINE>
5007 <LINE>your lingers and thumb, give it breath with your</LINE>
5008 <LINE>mouth, and it will discourse most eloquent music.</LINE>
5009 <LINE>Look you, these are the stops.</LINE>
5010 </SPEECH>
5011
5012 <SPEECH>
5013 <SPEAKER>GUILDENSTERN</SPEAKER>
5014 <LINE>But these cannot I command to any utterance of</LINE>
5015 <LINE>harmony; I have not the skill.</LINE>
5016 </SPEECH>
5017
5018 <SPEECH>
5019 <SPEAKER>HAMLET</SPEAKER>
5020 <LINE>Why, look you now, how unworthy a thing you make of</LINE>
5021 <LINE>me! You would play upon me; you would seem to know</LINE>
5022 <LINE>my stops; you would pluck out the heart of my</LINE>
5023 <LINE>mystery; you would sound me from my lowest note to</LINE>
5024 <LINE>the top of my compass: and there is much music,</LINE>
5025 <LINE>excellent voice, in this little organ; yet cannot</LINE>
5026 <LINE>you make it speak. 'Sblood, do you think I am</LINE>
5027 <LINE>easier to be played on than a pipe? Call me what</LINE>
5028 <LINE>instrument you will, though you can fret me, yet you</LINE>
5029 <LINE>cannot play upon me.</LINE>
5030 <STAGEDIR>Enter POLONIUS</STAGEDIR>
5031 <LINE>God bless you, sir!</LINE>
5032 </SPEECH>
5033
5034 <SPEECH>
5035 <SPEAKER>LORD POLONIUS</SPEAKER>
5036 <LINE>My lord, the queen would speak with you, and</LINE>
5037 <LINE>presently.</LINE>
5038 </SPEECH>
5039
5040 <SPEECH>
5041 <SPEAKER>HAMLET</SPEAKER>
5042 <LINE>Do you see yonder cloud that's almost in shape of a camel?</LINE>
5043 </SPEECH>
5044
5045 <SPEECH>
5046 <SPEAKER>LORD POLONIUS</SPEAKER>
5047 <LINE>By the mass, and 'tis like a camel, indeed.</LINE>
5048 </SPEECH>
5049
5050 <SPEECH>
5051 <SPEAKER>HAMLET</SPEAKER>
5052 <LINE>Methinks it is like a weasel.</LINE>
5053 </SPEECH>
5054
5055 <SPEECH>
5056 <SPEAKER>LORD POLONIUS</SPEAKER>
5057 <LINE>It is backed like a weasel.</LINE>
5058 </SPEECH>
5059
5060 <SPEECH>
5061 <SPEAKER>HAMLET</SPEAKER>
5062 <LINE>Or like a whale?</LINE>
5063 </SPEECH>
5064
5065 <SPEECH>
5066 <SPEAKER>LORD POLONIUS</SPEAKER>
5067 <LINE>Very like a whale.</LINE>
5068 </SPEECH>
5069
5070 <SPEECH>
5071 <SPEAKER>HAMLET</SPEAKER>
5072 <LINE>Then I will come to my mother by and by. They fool</LINE>
5073 <LINE>me to the top of my bent. I will come by and by.</LINE>
5074 </SPEECH>
5075
5076 <SPEECH>
5077 <SPEAKER>LORD POLONIUS</SPEAKER>
5078 <LINE>I will say so.</LINE>
5079 </SPEECH>
5080
5081 <SPEECH>
5082 <SPEAKER>HAMLET</SPEAKER>
5083 <LINE>By and by is easily said.</LINE>
5084 <STAGEDIR>Exit POLONIUS</STAGEDIR>
5085 <LINE>Leave me, friends.</LINE>
5086 <STAGEDIR>Exeunt all but HAMLET</STAGEDIR>
5087 <LINE>Tis now the very witching time of night,</LINE>
5088 <LINE>When churchyards yawn and hell itself breathes out</LINE>
5089 <LINE>Contagion to this world: now could I drink hot blood,</LINE>
5090 <LINE>And do such bitter business as the day</LINE>
5091 <LINE>Would quake to look on. Soft! now to my mother.</LINE>
5092 <LINE>O heart, lose not thy nature; let not ever</LINE>
5093 <LINE>The soul of Nero enter this firm bosom:</LINE>
5094 <LINE>Let me be cruel, not unnatural:</LINE>
5095 <LINE>I will speak daggers to her, but use none;</LINE>
5096 <LINE>My tongue and soul in this be hypocrites;</LINE>
5097 <LINE>How in my words soever she be shent,</LINE>
5098 <LINE>To give them seals never, my soul, consent!</LINE>
5099 </SPEECH>
5100
5101
5102 <STAGEDIR>Exit</STAGEDIR>
5103 </SCENE>
5104
5105 <SCENE><TITLE>SCENE III. A room in the castle.</TITLE>
5106 <STAGEDIR>Enter KING CLAUDIUS, ROSENCRANTZ, and GUILDENSTERN</STAGEDIR>
5107
5108 <SPEECH>
5109 <SPEAKER>KING CLAUDIUS</SPEAKER>
5110 <LINE>I like him not, nor stands it safe with us</LINE>
5111 <LINE>To let his madness range. Therefore prepare you;</LINE>
5112 <LINE>I your commission will forthwith dispatch,</LINE>
5113 <LINE>And he to England shall along with you:</LINE>
5114 <LINE>The terms of our estate may not endure</LINE>
5115 <LINE>Hazard so dangerous as doth hourly grow</LINE>
5116 <LINE>Out of his lunacies.</LINE>
5117 </SPEECH>
5118
5119 <SPEECH>
5120 <SPEAKER>GUILDENSTERN</SPEAKER>
5121 <LINE>We will ourselves provide:</LINE>
5122 <LINE>Most holy and religious fear it is</LINE>
5123 <LINE>To keep those many many bodies safe</LINE>
5124 <LINE>That live and feed upon your majesty.</LINE>
5125 </SPEECH>
5126
5127 <SPEECH>
5128 <SPEAKER>ROSENCRANTZ</SPEAKER>
5129 <LINE>The single and peculiar life is bound,</LINE>
5130 <LINE>With all the strength and armour of the mind,</LINE>
5131 <LINE>To keep itself from noyance; but much more</LINE>
5132 <LINE>That spirit upon whose weal depend and rest</LINE>
5133 <LINE>The lives of many. The cease of majesty</LINE>
5134 <LINE>Dies not alone; but, like a gulf, doth draw</LINE>
5135 <LINE>What's near it with it: it is a massy wheel,</LINE>
5136 <LINE>Fix'd on the summit of the highest mount,</LINE>
5137 <LINE>To whose huge spokes ten thousand lesser things</LINE>
5138 <LINE>Are mortised and adjoin'd; which, when it falls,</LINE>
5139 <LINE>Each small annexment, petty consequence,</LINE>
5140 <LINE>Attends the boisterous ruin. Never alone</LINE>
5141 <LINE>Did the king sigh, but with a general groan.</LINE>
5142 </SPEECH>
5143
5144 <SPEECH>
5145 <SPEAKER>KING CLAUDIUS</SPEAKER>
5146 <LINE>Arm you, I pray you, to this speedy voyage;</LINE>
5147 <LINE>For we will fetters put upon this fear,</LINE>
5148 <LINE>Which now goes too free-footed.</LINE>
5149 </SPEECH>
5150
5151 <SPEECH>
5152 <SPEAKER>ROSENCRANTZ</SPEAKER>
5153 <SPEAKER>GUILDENSTERN</SPEAKER>
5154 <LINE>We will haste us.</LINE>
5155 </SPEECH>
5156
5157 <STAGEDIR>Exeunt ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
5158 <STAGEDIR>Enter POLONIUS</STAGEDIR>
5159
5160 <SPEECH>
5161 <SPEAKER>LORD POLONIUS</SPEAKER>
5162 <LINE>My lord, he's going to his mother's closet:</LINE>
5163 <LINE>Behind the arras I'll convey myself,</LINE>
5164 <LINE>To hear the process; and warrant she'll tax him home:</LINE>
5165 <LINE>And, as you said, and wisely was it said,</LINE>
5166 <LINE>'Tis meet that some more audience than a mother,</LINE>
5167 <LINE>Since nature makes them partial, should o'erhear</LINE>
5168 <LINE>The speech, of vantage. Fare you well, my liege:</LINE>
5169 <LINE>I'll call upon you ere you go to bed,</LINE>
5170 <LINE>And tell you what I know.</LINE>
5171 </SPEECH>
5172
5173 <SPEECH>
5174 <SPEAKER>KING CLAUDIUS</SPEAKER>
5175 <LINE>Thanks, dear my lord.</LINE>
5176 <STAGEDIR>Exit POLONIUS</STAGEDIR>
5177 <LINE>O, my offence is rank it smells to heaven;</LINE>
5178 <LINE>It hath the primal eldest curse upon't,</LINE>
5179 <LINE>A brother's murder. Pray can I not,</LINE>
5180 <LINE>Though inclination be as sharp as will:</LINE>
5181 <LINE>My stronger guilt defeats my strong intent;</LINE>
5182 <LINE>And, like a man to double business bound,</LINE>
5183 <LINE>I stand in pause where I shall first begin,</LINE>
5184 <LINE>And both neglect. What if this cursed hand</LINE>
5185 <LINE>Were thicker than itself with brother's blood,</LINE>
5186 <LINE>Is there not rain enough in the sweet heavens</LINE>
5187 <LINE>To wash it white as snow? Whereto serves mercy</LINE>
5188 <LINE>But to confront the visage of offence?</LINE>
5189 <LINE>And what's in prayer but this two-fold force,</LINE>
5190 <LINE>To be forestalled ere we come to fall,</LINE>
5191 <LINE>Or pardon'd being down? Then I'll look up;</LINE>
5192 <LINE>My fault is past. But, O, what form of prayer</LINE>
5193 <LINE>Can serve my turn? 'Forgive me my foul murder'?</LINE>
5194 <LINE>That cannot be; since I am still possess'd</LINE>
5195 <LINE>Of those effects for which I did the murder,</LINE>
5196 <LINE>My crown, mine own ambition and my queen.</LINE>
5197 <LINE>May one be pardon'd and retain the offence?</LINE>
5198 <LINE>In the corrupted currents of this world</LINE>
5199 <LINE>Offence's gilded hand may shove by justice,</LINE>
5200 <LINE>And oft 'tis seen the wicked prize itself</LINE>
5201 <LINE>Buys out the law: but 'tis not so above;</LINE>
5202 <LINE>There is no shuffling, there the action lies</LINE>
5203 <LINE>In his true nature; and we ourselves compell'd,</LINE>
5204 <LINE>Even to the teeth and forehead of our faults,</LINE>
5205 <LINE>To give in evidence. What then? what rests?</LINE>
5206 <LINE>Try what repentance can: what can it not?</LINE>
5207 <LINE>Yet what can it when one can not repent?</LINE>
5208 <LINE>O wretched state! O bosom black as death!</LINE>
5209 <LINE>O limed soul, that, struggling to be free,</LINE>
5210 <LINE>Art more engaged! Help, angels! Make assay!</LINE>
5211 <LINE>Bow, stubborn knees; and, heart with strings of steel,</LINE>
5212 <LINE>Be soft as sinews of the newborn babe!</LINE>
5213 <LINE>All may be well.</LINE>
5214 </SPEECH>
5215
5216 <STAGEDIR>Retires and kneels</STAGEDIR>
5217 <STAGEDIR>Enter HAMLET</STAGEDIR>
5218
5219 <SPEECH>
5220 <SPEAKER>HAMLET</SPEAKER>
5221 <LINE>Now might I do it pat, now he is praying;</LINE>
5222 <LINE>And now I'll do't. And so he goes to heaven;</LINE>
5223 <LINE>And so am I revenged. That would be scann'd:</LINE>
5224 <LINE>A villain kills my father; and for that,</LINE>
5225 <LINE>I, his sole son, do this same villain send</LINE>
5226 <LINE>To heaven.</LINE>
5227 <LINE>O, this is hire and salary, not revenge.</LINE>
5228 <LINE>He took my father grossly, full of bread;</LINE>
5229 <LINE>With all his crimes broad blown, as flush as May;</LINE>
5230 <LINE>And how his audit stands who knows save heaven?</LINE>
5231 <LINE>But in our circumstance and course of thought,</LINE>
5232 <LINE>'Tis heavy with him: and am I then revenged,</LINE>
5233 <LINE>To take him in the purging of his soul,</LINE>
5234 <LINE>When he is fit and season'd for his passage?</LINE>
5235 <LINE>No!</LINE>
5236 <LINE>Up, sword; and know thou a more horrid hent:</LINE>
5237 <LINE>When he is drunk asleep, or in his rage,</LINE>
5238 <LINE>Or in the incestuous pleasure of his bed;</LINE>
5239 <LINE>At gaming, swearing, or about some act</LINE>
5240 <LINE>That has no relish of salvation in't;</LINE>
5241 <LINE>Then trip him, that his heels may kick at heaven,</LINE>
5242 <LINE>And that his soul may be as damn'd and black</LINE>
5243 <LINE>As hell, whereto it goes. My mother stays:</LINE>
5244 <LINE>This physic but prolongs thy sickly days.</LINE>
5245 </SPEECH>
5246
5247
5248 <STAGEDIR>Exit</STAGEDIR>
5249
5250 <SPEECH>
5251 <SPEAKER>KING CLAUDIUS</SPEAKER>
5252 <LINE><STAGEDIR>Rising</STAGEDIR> My words fly up, my thoughts remain below:</LINE>
5253 <LINE>Words without thoughts never to heaven go.</LINE>
5254 </SPEECH>
5255
5256
5257 <STAGEDIR>Exit</STAGEDIR>
5258 </SCENE>
5259
5260 <SCENE><TITLE>SCENE IV. The Queen's closet.</TITLE>
5261 <STAGEDIR>Enter QUEEN MARGARET and POLONIUS</STAGEDIR>
5262
5263 <SPEECH>
5264 <SPEAKER>LORD POLONIUS</SPEAKER>
5265 <LINE>He will come straight. Look you lay home to him:</LINE>
5266 <LINE>Tell him his pranks have been too broad to bear with,</LINE>
5267 <LINE>And that your grace hath screen'd and stood between</LINE>
5268 <LINE>Much heat and him. I'll sconce me even here.</LINE>
5269 <LINE>Pray you, be round with him.</LINE>
5270 </SPEECH>
5271
5272 <SPEECH>
5273 <SPEAKER>HAMLET</SPEAKER>
5274 <LINE><STAGEDIR>Within</STAGEDIR> Mother, mother, mother!</LINE>
5275 </SPEECH>
5276
5277 <SPEECH>
5278 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5279 <LINE>I'll warrant you,</LINE>
5280 <LINE>Fear me not: withdraw, I hear him coming.</LINE>
5281 </SPEECH>
5282
5283 <STAGEDIR>POLONIUS hides behind the arras</STAGEDIR>
5284 <STAGEDIR>Enter HAMLET</STAGEDIR>
5285
5286 <SPEECH>
5287 <SPEAKER>HAMLET</SPEAKER>
5288 <LINE>Now, mother, what's the matter?</LINE>
5289 </SPEECH>
5290
5291 <SPEECH>
5292 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5293 <LINE>Hamlet, thou hast thy father much offended.</LINE>
5294 </SPEECH>
5295
5296 <SPEECH>
5297 <SPEAKER>HAMLET</SPEAKER>
5298 <LINE>Mother, you have my father much offended.</LINE>
5299 </SPEECH>
5300
5301 <SPEECH>
5302 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5303 <LINE>Come, come, you answer with an idle tongue.</LINE>
5304 </SPEECH>
5305
5306 <SPEECH>
5307 <SPEAKER>HAMLET</SPEAKER>
5308 <LINE>Go, go, you question with a wicked tongue.</LINE>
5309 </SPEECH>
5310
5311 <SPEECH>
5312 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5313 <LINE>Why, how now, Hamlet!</LINE>
5314 </SPEECH>
5315
5316 <SPEECH>
5317 <SPEAKER>HAMLET</SPEAKER>
5318 <LINE>What's the matter now?</LINE>
5319 </SPEECH>
5320
5321 <SPEECH>
5322 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5323 <LINE>Have you forgot me?</LINE>
5324 </SPEECH>
5325
5326 <SPEECH>
5327 <SPEAKER>HAMLET</SPEAKER>
5328 <LINE>No, by the rood, not so:</LINE>
5329 <LINE>You are the queen, your husband's brother's wife;</LINE>
5330 <LINE>And--would it were not so!--you are my mother.</LINE>
5331 </SPEECH>
5332
5333 <SPEECH>
5334 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5335 <LINE>Nay, then, I'll set those to you that can speak.</LINE>
5336 </SPEECH>
5337
5338 <SPEECH>
5339 <SPEAKER>HAMLET</SPEAKER>
5340 <LINE>Come, come, and sit you down; you shall not budge;</LINE>
5341 <LINE>You go not till I set you up a glass</LINE>
5342 <LINE>Where you may see the inmost part of you.</LINE>
5343 </SPEECH>
5344
5345 <SPEECH>
5346 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5347 <LINE>What wilt thou do? thou wilt not murder me?</LINE>
5348 <LINE>Help, help, ho!</LINE>
5349 </SPEECH>
5350
5351 <SPEECH>
5352 <SPEAKER>LORD POLONIUS</SPEAKER>
5353 <LINE><STAGEDIR>Behind</STAGEDIR> What, ho! help, help, help!</LINE>
5354 </SPEECH>
5355
5356 <SPEECH>
5357 <SPEAKER>HAMLET</SPEAKER>
5358 <LINE><STAGEDIR>Drawing</STAGEDIR> How now! a rat? Dead, for a ducat, dead!</LINE>
5359 </SPEECH>
5360
5361
5362 <STAGEDIR>Makes a pass through the arras</STAGEDIR>
5363
5364 <SPEECH>
5365 <SPEAKER>LORD POLONIUS</SPEAKER>
5366 <LINE><STAGEDIR>Behind</STAGEDIR> O, I am slain!</LINE>
5367 </SPEECH>
5368
5369
5370 <STAGEDIR>Falls and dies</STAGEDIR>
5371
5372 <SPEECH>
5373 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5374 <LINE>O me, what hast thou done?</LINE>
5375 </SPEECH>
5376
5377 <SPEECH>
5378 <SPEAKER>HAMLET</SPEAKER>
5379 <LINE>Nay, I know not:</LINE>
5380 <LINE>Is it the king?</LINE>
5381 </SPEECH>
5382
5383 <SPEECH>
5384 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5385 <LINE>O, what a rash and bloody deed is this!</LINE>
5386 </SPEECH>
5387
5388 <SPEECH>
5389 <SPEAKER>HAMLET</SPEAKER>
5390 <LINE>A bloody deed! almost as bad, good mother,</LINE>
5391 <LINE>As kill a king, and marry with his brother.</LINE>
5392 </SPEECH>
5393
5394 <SPEECH>
5395 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5396 <LINE>As kill a king!</LINE>
5397 </SPEECH>
5398
5399 <SPEECH>
5400 <SPEAKER>HAMLET</SPEAKER>
5401 <LINE>Ay, lady, 'twas my word.</LINE>
5402 <STAGEDIR>Lifts up the array and discovers POLONIUS</STAGEDIR>
5403 <LINE>Thou wretched, rash, intruding fool, farewell!</LINE>
5404 <LINE>I took thee for thy better: take thy fortune;</LINE>
5405 <LINE>Thou find'st to be too busy is some danger.</LINE>
5406 <LINE>Leave wringing of your hands: peace! sit you down,</LINE>
5407 <LINE>And let me wring your heart; for so I shall,</LINE>
5408 <LINE>If it be made of penetrable stuff,</LINE>
5409 <LINE>If damned custom have not brass'd it so</LINE>
5410 <LINE>That it is proof and bulwark against sense.</LINE>
5411 </SPEECH>
5412
5413 <SPEECH>
5414 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5415 <LINE>What have I done, that thou darest wag thy tongue</LINE>
5416 <LINE>In noise so rude against me?</LINE>
5417 </SPEECH>
5418
5419 <SPEECH>
5420 <SPEAKER>HAMLET</SPEAKER>
5421 <LINE>Such an act</LINE>
5422 <LINE>That blurs the grace and blush of modesty,</LINE>
5423 <LINE>Calls virtue hypocrite, takes off the rose</LINE>
5424 <LINE>From the fair forehead of an innocent love</LINE>
5425 <LINE>And sets a blister there, makes marriage-vows</LINE>
5426 <LINE>As false as dicers' oaths: O, such a deed</LINE>
5427 <LINE>As from the body of contraction plucks</LINE>
5428 <LINE>The very soul, and sweet religion makes</LINE>
5429 <LINE>A rhapsody of words: heaven's face doth glow:</LINE>
5430 <LINE>Yea, this solidity and compound mass,</LINE>
5431 <LINE>With tristful visage, as against the doom,</LINE>
5432 <LINE>Is thought-sick at the act.</LINE>
5433 </SPEECH>
5434
5435 <SPEECH>
5436 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5437 <LINE>Ay me, what act,</LINE>
5438 <LINE>That roars so loud, and thunders in the index?</LINE>
5439 </SPEECH>
5440
5441 <SPEECH>
5442 <SPEAKER>HAMLET</SPEAKER>
5443 <LINE>Look here, upon this picture, and on this,</LINE>
5444 <LINE>The counterfeit presentment of two brothers.</LINE>
5445 <LINE>See, what a grace was seated on this brow;</LINE>
5446 <LINE>Hyperion's curls; the front of Jove himself;</LINE>
5447 <LINE>An eye like Mars, to threaten and command;</LINE>
5448 <LINE>A station like the herald Mercury</LINE>
5449 <LINE>New-lighted on a heaven-kissing hill;</LINE>
5450 <LINE>A combination and a form indeed,</LINE>
5451 <LINE>Where every god did seem to set his seal,</LINE>
5452 <LINE>To give the world assurance of a man:</LINE>
5453 <LINE>This was your husband. Look you now, what follows:</LINE>
5454 <LINE>Here is your husband; like a mildew'd ear,</LINE>
5455 <LINE>Blasting his wholesome brother. Have you eyes?</LINE>
5456 <LINE>Could you on this fair mountain leave to feed,</LINE>
5457 <LINE>And batten on this moor? Ha! have you eyes?</LINE>
5458 <LINE>You cannot call it love; for at your age</LINE>
5459 <LINE>The hey-day in the blood is tame, it's humble,</LINE>
5460 <LINE>And waits upon the judgment: and what judgment</LINE>
5461 <LINE>Would step from this to this? Sense, sure, you have,</LINE>
5462 <LINE>Else could you not have motion; but sure, that sense</LINE>
5463 <LINE>Is apoplex'd; for madness would not err,</LINE>
5464 <LINE>Nor sense to ecstasy was ne'er so thrall'd</LINE>
5465 <LINE>But it reserved some quantity of choice,</LINE>
5466 <LINE>To serve in such a difference. What devil was't</LINE>
5467 <LINE>That thus hath cozen'd you at hoodman-blind?</LINE>
5468 <LINE>Eyes without feeling, feeling without sight,</LINE>
5469 <LINE>Ears without hands or eyes, smelling sans all,</LINE>
5470 <LINE>Or but a sickly part of one true sense</LINE>
5471 <LINE>Could not so mope.</LINE>
5472 <LINE>O shame! where is thy blush? Rebellious hell,</LINE>
5473 <LINE>If thou canst mutine in a matron's bones,</LINE>
5474 <LINE>To flaming youth let virtue be as wax,</LINE>
5475 <LINE>And melt in her own fire: proclaim no shame</LINE>
5476 <LINE>When the compulsive ardour gives the charge,</LINE>
5477 <LINE>Since frost itself as actively doth burn</LINE>
5478 <LINE>And reason panders will.</LINE>
5479 </SPEECH>
5480
5481 <SPEECH>
5482 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5483 <LINE>O Hamlet, speak no more:</LINE>
5484 <LINE>Thou turn'st mine eyes into my very soul;</LINE>
5485 <LINE>And there I see such black and grained spots</LINE>
5486 <LINE>As will not leave their tinct.</LINE>
5487 </SPEECH>
5488
5489 <SPEECH>
5490 <SPEAKER>HAMLET</SPEAKER>
5491 <LINE>Nay, but to live</LINE>
5492 <LINE>In the rank sweat of an enseamed bed,</LINE>
5493 <LINE>Stew'd in corruption, honeying and making love</LINE>
5494 <LINE>Over the nasty sty,--</LINE>
5495 </SPEECH>
5496
5497 <SPEECH>
5498 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5499 <LINE>O, speak to me no more;</LINE>
5500 <LINE>These words, like daggers, enter in mine ears;</LINE>
5501 <LINE>No more, sweet Hamlet!</LINE>
5502 </SPEECH>
5503
5504 <SPEECH>
5505 <SPEAKER>HAMLET</SPEAKER>
5506 <LINE>A murderer and a villain;</LINE>
5507 <LINE>A slave that is not twentieth part the tithe</LINE>
5508 <LINE>Of your precedent lord; a vice of kings;</LINE>
5509 <LINE>A cutpurse of the empire and the rule,</LINE>
5510 <LINE>That from a shelf the precious diadem stole,</LINE>
5511 <LINE>And put it in his pocket!</LINE>
5512 </SPEECH>
5513
5514 <SPEECH>
5515 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5516 <LINE>No more!</LINE>
5517 </SPEECH>
5518
5519 <SPEECH>
5520 <SPEAKER>HAMLET</SPEAKER>
5521 <LINE>A king of shreds and patches,--</LINE>
5522 <STAGEDIR>Enter Ghost</STAGEDIR>
5523 <LINE>Save me, and hover o'er me with your wings,</LINE>
5524 <LINE>You heavenly guards! What would your gracious figure?</LINE>
5525 </SPEECH>
5526
5527 <SPEECH>
5528 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5529 <LINE>Alas, he's mad!</LINE>
5530 </SPEECH>
5531
5532 <SPEECH>
5533 <SPEAKER>HAMLET</SPEAKER>
5534 <LINE>Do you not come your tardy son to chide,</LINE>
5535 <LINE>That, lapsed in time and passion, lets go by</LINE>
5536 <LINE>The important acting of your dread command? O, say!</LINE>
5537 </SPEECH>
5538
5539 <SPEECH>
5540 <SPEAKER>Ghost</SPEAKER>
5541 <LINE>Do not forget: this visitation</LINE>
5542 <LINE>Is but to whet thy almost blunted purpose.</LINE>
5543 <LINE>But, look, amazement on thy mother sits:</LINE>
5544 <LINE>O, step between her and her fighting soul:</LINE>
5545 <LINE>Conceit in weakest bodies strongest works:</LINE>
5546 <LINE>Speak to her, Hamlet.</LINE>
5547 </SPEECH>
5548
5549 <SPEECH>
5550 <SPEAKER>HAMLET</SPEAKER>
5551 <LINE>How is it with you, lady?</LINE>
5552 </SPEECH>
5553
5554 <SPEECH>
5555 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5556 <LINE>Alas, how is't with you,</LINE>
5557 <LINE>That you do bend your eye on vacancy</LINE>
5558 <LINE>And with the incorporal air do hold discourse?</LINE>
5559 <LINE>Forth at your eyes your spirits wildly peep;</LINE>
5560 <LINE>And, as the sleeping soldiers in the alarm,</LINE>
5561 <LINE>Your bedded hair, like life in excrements,</LINE>
5562 <LINE>Starts up, and stands on end. O gentle son,</LINE>
5563 <LINE>Upon the heat and flame of thy distemper</LINE>
5564 <LINE>Sprinkle cool patience. Whereon do you look?</LINE>
5565 </SPEECH>
5566
5567 <SPEECH>
5568 <SPEAKER>HAMLET</SPEAKER>
5569 <LINE>On him, on him! Look you, how pale he glares!</LINE>
5570 <LINE>His form and cause conjoin'd, preaching to stones,</LINE>
5571 <LINE>Would make them capable. Do not look upon me;</LINE>
5572 <LINE>Lest with this piteous action you convert</LINE>
5573 <LINE>My stern effects: then what I have to do</LINE>
5574 <LINE>Will want true colour; tears perchance for blood.</LINE>
5575 </SPEECH>
5576
5577 <SPEECH>
5578 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5579 <LINE>To whom do you speak this?</LINE>
5580 </SPEECH>
5581
5582 <SPEECH>
5583 <SPEAKER>HAMLET</SPEAKER>
5584 <LINE>Do you see nothing there?</LINE>
5585 </SPEECH>
5586
5587 <SPEECH>
5588 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5589 <LINE>Nothing at all; yet all that is I see.</LINE>
5590 </SPEECH>
5591
5592 <SPEECH>
5593 <SPEAKER>HAMLET</SPEAKER>
5594 <LINE>Nor did you nothing hear?</LINE>
5595 </SPEECH>
5596
5597 <SPEECH>
5598 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5599 <LINE>No, nothing but ourselves.</LINE>
5600 </SPEECH>
5601
5602 <SPEECH>
5603 <SPEAKER>HAMLET</SPEAKER>
5604 <LINE>Why, look you there! look, how it steals away!</LINE>
5605 <LINE>My father, in his habit as he lived!</LINE>
5606 <LINE>Look, where he goes, even now, out at the portal!</LINE>
5607 </SPEECH>
5608
5609
5610 <STAGEDIR>Exit Ghost</STAGEDIR>
5611
5612 <SPEECH>
5613 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5614 <LINE>This the very coinage of your brain:</LINE>
5615 <LINE>This bodiless creation ecstasy</LINE>
5616 <LINE>Is very cunning in.</LINE>
5617 </SPEECH>
5618
5619 <SPEECH>
5620 <SPEAKER>HAMLET</SPEAKER>
5621 <LINE>Ecstasy!</LINE>
5622 <LINE>My pulse, as yours, doth temperately keep time,</LINE>
5623 <LINE>And makes as healthful music: it is not madness</LINE>
5624 <LINE>That I have utter'd: bring me to the test,</LINE>
5625 <LINE>And I the matter will re-word; which madness</LINE>
5626 <LINE>Would gambol from. Mother, for love of grace,</LINE>
5627 <LINE>Lay not that mattering unction to your soul,</LINE>
5628 <LINE>That not your trespass, but my madness speaks:</LINE>
5629 <LINE>It will but skin and film the ulcerous place,</LINE>
5630 <LINE>Whilst rank corruption, mining all within,</LINE>
5631 <LINE>Infects unseen. Confess yourself to heaven;</LINE>
5632 <LINE>Repent what's past; avoid what is to come;</LINE>
5633 <LINE>And do not spread the compost on the weeds,</LINE>
5634 <LINE>To make them ranker. Forgive me this my virtue;</LINE>
5635 <LINE>For in the fatness of these pursy times</LINE>
5636 <LINE>Virtue itself of vice must pardon beg,</LINE>
5637 <LINE>Yea, curb and woo for leave to do him good.</LINE>
5638 </SPEECH>
5639
5640 <SPEECH>
5641 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5642 <LINE>O Hamlet, thou hast cleft my heart in twain.</LINE>
5643 </SPEECH>
5644
5645 <SPEECH>
5646 <SPEAKER>HAMLET</SPEAKER>
5647 <LINE>O, throw away the worser part of it,</LINE>
5648 <LINE>And live the purer with the other half.</LINE>
5649 <LINE>Good night: but go not to mine uncle's bed;</LINE>
5650 <LINE>Assume a virtue, if you have it not.</LINE>
5651 <LINE>That monster, custom, who all sense doth eat,</LINE>
5652 <LINE>Of habits devil, is angel yet in this,</LINE>
5653 <LINE>That to the use of actions fair and good</LINE>
5654 <LINE>He likewise gives a frock or livery,</LINE>
5655 <LINE>That aptly is put on. Refrain to-night,</LINE>
5656 <LINE>And that shall lend a kind of easiness</LINE>
5657 <LINE>To the next abstinence: the next more easy;</LINE>
5658 <LINE>For use almost can change the stamp of nature,</LINE>
5659 <LINE>And either ... the devil, or throw him out</LINE>
5660 <LINE>With wondrous potency. Once more, good night:</LINE>
5661 <LINE>And when you are desirous to be bless'd,</LINE>
5662 <LINE>I'll blessing beg of you. For this same lord,</LINE>
5663 <STAGEDIR>Pointing to POLONIUS</STAGEDIR>
5664 <LINE>I do repent: but heaven hath pleased it so,</LINE>
5665 <LINE>To punish me with this and this with me,</LINE>
5666 <LINE>That I must be their scourge and minister.</LINE>
5667 <LINE>I will bestow him, and will answer well</LINE>
5668 <LINE>The death I gave him. So, again, good night.</LINE>
5669 <LINE>I must be cruel, only to be kind:</LINE>
5670 <LINE>Thus bad begins and worse remains behind.</LINE>
5671 <LINE>One word more, good lady.</LINE>
5672 </SPEECH>
5673
5674 <SPEECH>
5675 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5676 <LINE>What shall I do?</LINE>
5677 </SPEECH>
5678
5679 <SPEECH>
5680 <SPEAKER>HAMLET</SPEAKER>
5681 <LINE>Not this, by no means, that I bid you do:</LINE>
5682 <LINE>Let the bloat king tempt you again to bed;</LINE>
5683 <LINE>Pinch wanton on your cheek; call you his mouse;</LINE>
5684 <LINE>And let him, for a pair of reechy kisses,</LINE>
5685 <LINE>Or paddling in your neck with his damn'd fingers,</LINE>
5686 <LINE>Make you to ravel all this matter out,</LINE>
5687 <LINE>That I essentially am not in madness,</LINE>
5688 <LINE>But mad in craft. 'Twere good you let him know;</LINE>
5689 <LINE>For who, that's but a queen, fair, sober, wise,</LINE>
5690 <LINE>Would from a paddock, from a bat, a gib,</LINE>
5691 <LINE>Such dear concernings hide? who would do so?</LINE>
5692 <LINE>No, in despite of sense and secrecy,</LINE>
5693 <LINE>Unpeg the basket on the house's top.</LINE>
5694 <LINE>Let the birds fly, and, like the famous ape,</LINE>
5695 <LINE>To try conclusions, in the basket creep,</LINE>
5696 <LINE>And break your own neck down.</LINE>
5697 </SPEECH>
5698
5699 <SPEECH>
5700 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5701 <LINE>Be thou assured, if words be made of breath,</LINE>
5702 <LINE>And breath of life, I have no life to breathe</LINE>
5703 <LINE>What thou hast said to me.</LINE>
5704 </SPEECH>
5705
5706 <SPEECH>
5707 <SPEAKER>HAMLET</SPEAKER>
5708 <LINE>I must to England; you know that?</LINE>
5709 </SPEECH>
5710
5711 <SPEECH>
5712 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5713 <LINE>Alack,</LINE>
5714 <LINE>I had forgot: 'tis so concluded on.</LINE>
5715 </SPEECH>
5716
5717 <SPEECH>
5718 <SPEAKER>HAMLET</SPEAKER>
5719 <LINE>There's letters seal'd: and my two schoolfellows,</LINE>
5720 <LINE>Whom I will trust as I will adders fang'd,</LINE>
5721 <LINE>They bear the mandate; they must sweep my way,</LINE>
5722 <LINE>And marshal me to knavery. Let it work;</LINE>
5723 <LINE>For 'tis the sport to have the engineer</LINE>
5724 <LINE>Hoist with his own petard: and 't shall go hard</LINE>
5725 <LINE>But I will delve one yard below their mines,</LINE>
5726 <LINE>And blow them at the moon: O, 'tis most sweet,</LINE>
5727 <LINE>When in one line two crafts directly meet.</LINE>
5728 <LINE>This man shall set me packing:</LINE>
5729 <LINE>I'll lug the guts into the neighbour room.</LINE>
5730 <LINE>Mother, good night. Indeed this counsellor</LINE>
5731 <LINE>Is now most still, most secret and most grave,</LINE>
5732 <LINE>Who was in life a foolish prating knave.</LINE>
5733 <LINE>Come, sir, to draw toward an end with you.</LINE>
5734 <LINE>Good night, mother.</LINE>
5735 </SPEECH>
5736
5737
5738 <STAGEDIR>Exeunt severally; HAMLET dragging in POLONIUS</STAGEDIR>
5739 </SCENE>
5740
5741 </ACT>
5742
5743 <ACT><TITLE>ACT IV</TITLE>
5744
5745 <SCENE><TITLE>SCENE I. A room in the castle.</TITLE>
5746 <STAGEDIR>Enter KING CLAUDIUS, QUEEN GERTRUDE, ROSENCRANTZ,
5747 and GUILDENSTERN</STAGEDIR>
5748
5749 <SPEECH>
5750 <SPEAKER>KING CLAUDIUS</SPEAKER>
5751 <LINE>There's matter in these sighs, these profound heaves:</LINE>
5752 <LINE>You must translate: 'tis fit we understand them.</LINE>
5753 <LINE>Where is your son?</LINE>
5754 </SPEECH>
5755
5756 <SPEECH>
5757 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5758 <LINE>Bestow this place on us a little while.</LINE>
5759 <STAGEDIR>Exeunt ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
5760 <LINE>Ah, my good lord, what have I seen to-night!</LINE>
5761 </SPEECH>
5762
5763 <SPEECH>
5764 <SPEAKER>KING CLAUDIUS</SPEAKER>
5765 <LINE>What, Gertrude? How does Hamlet?</LINE>
5766 </SPEECH>
5767
5768 <SPEECH>
5769 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5770 <LINE>Mad as the sea and wind, when both contend</LINE>
5771 <LINE>Which is the mightier: in his lawless fit,</LINE>
5772 <LINE>Behind the arras hearing something stir,</LINE>
5773 <LINE>Whips out his rapier, cries, 'A rat, a rat!'</LINE>
5774 <LINE>And, in this brainish apprehension, kills</LINE>
5775 <LINE>The unseen good old man.</LINE>
5776 </SPEECH>
5777
5778 <SPEECH>
5779 <SPEAKER>KING CLAUDIUS</SPEAKER>
5780 <LINE>O heavy deed!</LINE>
5781 <LINE>It had been so with us, had we been there:</LINE>
5782 <LINE>His liberty is full of threats to all;</LINE>
5783 <LINE>To you yourself, to us, to every one.</LINE>
5784 <LINE>Alas, how shall this bloody deed be answer'd?</LINE>
5785 <LINE>It will be laid to us, whose providence</LINE>
5786 <LINE>Should have kept short, restrain'd and out of haunt,</LINE>
5787 <LINE>This mad young man: but so much was our love,</LINE>
5788 <LINE>We would not understand what was most fit;</LINE>
5789 <LINE>But, like the owner of a foul disease,</LINE>
5790 <LINE>To keep it from divulging, let it feed</LINE>
5791 <LINE>Even on the pith of Life. Where is he gone?</LINE>
5792 </SPEECH>
5793
5794 <SPEECH>
5795 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
5796 <LINE>To draw apart the body he hath kill'd:</LINE>
5797 <LINE>O'er whom his very madness, like some ore</LINE>
5798 <LINE>Among a mineral of metals base,</LINE>
5799 <LINE>Shows itself pure; he weeps for what is done.</LINE>
5800 </SPEECH>
5801
5802 <SPEECH>
5803 <SPEAKER>KING CLAUDIUS</SPEAKER>
5804 <LINE>O Gertrude, come away!</LINE>
5805 <LINE>The sun no sooner shall the mountains touch,</LINE>
5806 <LINE>But we will ship him hence: and this vile deed</LINE>
5807 <LINE>We must, with all our majesty and skill,</LINE>
5808 <LINE>Both countenance and excuse. Ho, Guildenstern!</LINE>
5809 <STAGEDIR>Re-enter ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
5810 <LINE>Friends both, go join you with some further aid:</LINE>
5811 <LINE>Hamlet in madness hath Polonius slain,</LINE>
5812 <LINE>And from his mother's closet hath he dragg'd him:</LINE>
5813 <LINE>Go seek him out; speak fair, and bring the body</LINE>
5814 <LINE>Into the chapel. I pray you, haste in this.</LINE>
5815 <STAGEDIR>Exeunt ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
5816 <LINE>Come, Gertrude, we'll call up our wisest friends;</LINE>
5817 <LINE>And let them know, both what we mean to do,</LINE>
5818 <LINE>And what's untimely done...</LINE>
5819 <LINE>Whose whisper o'er the world's diameter,</LINE>
5820 <LINE>As level as the cannon to his blank,</LINE>
5821 <LINE>Transports his poison'd shot, may miss our name,</LINE>
5822 <LINE>And hit the woundless air. O, come away!</LINE>
5823 <LINE>My soul is full of discord and dismay.</LINE>
5824 </SPEECH>
5825
5826
5827 <STAGEDIR>Exeunt</STAGEDIR>
5828 </SCENE>
5829
5830 <SCENE><TITLE>SCENE II. Another room in the castle.</TITLE>
5831 <STAGEDIR>Enter HAMLET</STAGEDIR>
5832
5833 <SPEECH>
5834 <SPEAKER>HAMLET</SPEAKER>
5835 <LINE>Safely stowed.</LINE>
5836 </SPEECH>
5837
5838 <SPEECH>
5839 <SPEAKER>ROSENCRANTZ</SPEAKER>
5840 <SPEAKER>GUILDENSTERN</SPEAKER>
5841 <LINE><STAGEDIR>Within</STAGEDIR> Hamlet! Lord Hamlet!</LINE>
5842 </SPEECH>
5843
5844 <SPEECH>
5845 <SPEAKER>HAMLET</SPEAKER>
5846 <LINE>What noise? who calls on Hamlet?</LINE>
5847 <LINE>O, here they come.</LINE>
5848 </SPEECH>
5849
5850
5851 <STAGEDIR>Enter ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
5852
5853 <SPEECH>
5854 <SPEAKER>ROSENCRANTZ</SPEAKER>
5855 <LINE>What have you done, my lord, with the dead body?</LINE>
5856 </SPEECH>
5857
5858 <SPEECH>
5859 <SPEAKER>HAMLET</SPEAKER>
5860 <LINE>Compounded it with dust, whereto 'tis kin.</LINE>
5861 </SPEECH>
5862
5863 <SPEECH>
5864 <SPEAKER>ROSENCRANTZ</SPEAKER>
5865 <LINE>Tell us where 'tis, that we may take it thence</LINE>
5866 <LINE>And bear it to the chapel.</LINE>
5867 </SPEECH>
5868
5869 <SPEECH>
5870 <SPEAKER>HAMLET</SPEAKER>
5871 <LINE>Do not believe it.</LINE>
5872 </SPEECH>
5873
5874 <SPEECH>
5875 <SPEAKER>ROSENCRANTZ</SPEAKER>
5876 <LINE>Believe what?</LINE>
5877 </SPEECH>
5878
5879 <SPEECH>
5880 <SPEAKER>HAMLET</SPEAKER>
5881 <LINE>That I can keep your counsel and not mine own.</LINE>
5882 <LINE>Besides, to be demanded of a sponge! what</LINE>
5883 <LINE>replication should be made by the son of a king?</LINE>
5884 </SPEECH>
5885
5886 <SPEECH>
5887 <SPEAKER>ROSENCRANTZ</SPEAKER>
5888 <LINE>Take you me for a sponge, my lord?</LINE>
5889 </SPEECH>
5890
5891 <SPEECH>
5892 <SPEAKER>HAMLET</SPEAKER>
5893 <LINE>Ay, sir, that soaks up the king's countenance, his</LINE>
5894 <LINE>rewards, his authorities. But such officers do the</LINE>
5895 <LINE>king best service in the end: he keeps them, like</LINE>
5896 <LINE>an ape, in the corner of his jaw; first mouthed, to</LINE>
5897 <LINE>be last swallowed: when he needs what you have</LINE>
5898 <LINE>gleaned, it is but squeezing you, and, sponge, you</LINE>
5899 <LINE>shall be dry again.</LINE>
5900 </SPEECH>
5901
5902 <SPEECH>
5903 <SPEAKER>ROSENCRANTZ</SPEAKER>
5904 <LINE>I understand you not, my lord.</LINE>
5905 </SPEECH>
5906
5907 <SPEECH>
5908 <SPEAKER>HAMLET</SPEAKER>
5909 <LINE>I am glad of it: a knavish speech sleeps in a</LINE>
5910 <LINE>foolish ear.</LINE>
5911 </SPEECH>
5912
5913 <SPEECH>
5914 <SPEAKER>ROSENCRANTZ</SPEAKER>
5915 <LINE>My lord, you must tell us where the body is, and go</LINE>
5916 <LINE>with us to the king.</LINE>
5917 </SPEECH>
5918
5919 <SPEECH>
5920 <SPEAKER>HAMLET</SPEAKER>
5921 <LINE>The body is with the king, but the king is not with</LINE>
5922 <LINE>the body. The king is a thing--</LINE>
5923 </SPEECH>
5924
5925 <SPEECH>
5926 <SPEAKER>GUILDENSTERN</SPEAKER>
5927 <LINE>A thing, my lord!</LINE>
5928 </SPEECH>
5929
5930 <SPEECH>
5931 <SPEAKER>HAMLET</SPEAKER>
5932 <LINE>Of nothing: bring me to him. Hide fox, and all after.</LINE>
5933 </SPEECH>
5934
5935
5936 <STAGEDIR>Exeunt</STAGEDIR>
5937 </SCENE>
5938
5939 <SCENE><TITLE>SCENE III. Another room in the castle.</TITLE>
5940 <STAGEDIR>Enter KING CLAUDIUS, attended</STAGEDIR>
5941
5942 <SPEECH>
5943 <SPEAKER>KING CLAUDIUS</SPEAKER>
5944 <LINE>I have sent to seek him, and to find the body.</LINE>
5945 <LINE>How dangerous is it that this man goes loose!</LINE>
5946 <LINE>Yet must not we put the strong law on him:</LINE>
5947 <LINE>He's loved of the distracted multitude,</LINE>
5948 <LINE>Who like not in their judgment, but their eyes;</LINE>
5949 <LINE>And where tis so, the offender's scourge is weigh'd,</LINE>
5950 <LINE>But never the offence. To bear all smooth and even,</LINE>
5951 <LINE>This sudden sending him away must seem</LINE>
5952 <LINE>Deliberate pause: diseases desperate grown</LINE>
5953 <LINE>By desperate appliance are relieved,</LINE>
5954 <LINE>Or not at all.</LINE>
5955 <STAGEDIR>Enter ROSENCRANTZ</STAGEDIR>
5956 <LINE>How now! what hath befall'n?</LINE>
5957 </SPEECH>
5958
5959 <SPEECH>
5960 <SPEAKER>ROSENCRANTZ</SPEAKER>
5961 <LINE>Where the dead body is bestow'd, my lord,</LINE>
5962 <LINE>We cannot get from him.</LINE>
5963 </SPEECH>
5964
5965 <SPEECH>
5966 <SPEAKER>KING CLAUDIUS</SPEAKER>
5967 <LINE>But where is he?</LINE>
5968 </SPEECH>
5969
5970 <SPEECH>
5971 <SPEAKER>ROSENCRANTZ</SPEAKER>
5972 <LINE>Without, my lord; guarded, to know your pleasure.</LINE>
5973 </SPEECH>
5974
5975 <SPEECH>
5976 <SPEAKER>KING CLAUDIUS</SPEAKER>
5977 <LINE>Bring him before us.</LINE>
5978 </SPEECH>
5979
5980 <SPEECH>
5981 <SPEAKER>ROSENCRANTZ</SPEAKER>
5982 <LINE>Ho, Guildenstern! bring in my lord.</LINE>
5983 </SPEECH>
5984
5985
5986 <STAGEDIR>Enter HAMLET and GUILDENSTERN</STAGEDIR>
5987
5988 <SPEECH>
5989 <SPEAKER>KING CLAUDIUS</SPEAKER>
5990 <LINE>Now, Hamlet, where's Polonius?</LINE>
5991 </SPEECH>
5992
5993 <SPEECH>
5994 <SPEAKER>HAMLET</SPEAKER>
5995 <LINE>At supper.</LINE>
5996 </SPEECH>
5997
5998 <SPEECH>
5999 <SPEAKER>KING CLAUDIUS</SPEAKER>
6000 <LINE>At supper! where?</LINE>
6001 </SPEECH>
6002
6003 <SPEECH>
6004 <SPEAKER>HAMLET</SPEAKER>
6005 <LINE>Not where he eats, but where he is eaten: a certain</LINE>
6006 <LINE>convocation of politic worms are e'en at him. Your</LINE>
6007 <LINE>worm is your only emperor for diet: we fat all</LINE>
6008 <LINE>creatures else to fat us, and we fat ourselves for</LINE>
6009 <LINE>maggots: your fat king and your lean beggar is but</LINE>
6010 <LINE>variable service, two dishes, but to one table:</LINE>
6011 <LINE>that's the end.</LINE>
6012 </SPEECH>
6013
6014 <SPEECH>
6015 <SPEAKER>KING CLAUDIUS</SPEAKER>
6016 <LINE>Alas, alas!</LINE>
6017 </SPEECH>
6018
6019 <SPEECH>
6020 <SPEAKER>HAMLET</SPEAKER>
6021 <LINE>A man may fish with the worm that hath eat of a</LINE>
6022 <LINE>king, and cat of the fish that hath fed of that worm.</LINE>
6023 </SPEECH>
6024
6025 <SPEECH>
6026 <SPEAKER>KING CLAUDIUS</SPEAKER>
6027 <LINE>What dost you mean by this?</LINE>
6028 </SPEECH>
6029
6030 <SPEECH>
6031 <SPEAKER>HAMLET</SPEAKER>
6032 <LINE>Nothing but to show you how a king may go a</LINE>
6033 <LINE>progress through the guts of a beggar.</LINE>
6034 </SPEECH>
6035
6036 <SPEECH>
6037 <SPEAKER>KING CLAUDIUS</SPEAKER>
6038 <LINE>Where is Polonius?</LINE>
6039 </SPEECH>
6040
6041 <SPEECH>
6042 <SPEAKER>HAMLET</SPEAKER>
6043 <LINE>In heaven; send hither to see: if your messenger</LINE>
6044 <LINE>find him not there, seek him i' the other place</LINE>
6045 <LINE>yourself. But indeed, if you find him not within</LINE>
6046 <LINE>this month, you shall nose him as you go up the</LINE>
6047 <LINE>stairs into the lobby.</LINE>
6048 </SPEECH>
6049
6050 <SPEECH>
6051 <SPEAKER>KING CLAUDIUS</SPEAKER>
6052 <LINE>Go seek him there.</LINE>
6053 </SPEECH>
6054
6055
6056 <STAGEDIR>To some Attendants</STAGEDIR>
6057
6058 <SPEECH>
6059 <SPEAKER>HAMLET</SPEAKER>
6060 <LINE>He will stay till ye come.</LINE>
6061 </SPEECH>
6062
6063
6064 <STAGEDIR>Exeunt Attendants</STAGEDIR>
6065
6066 <SPEECH>
6067 <SPEAKER>KING CLAUDIUS</SPEAKER>
6068 <LINE>Hamlet, this deed, for thine especial safety,--</LINE>
6069 <LINE>Which we do tender, as we dearly grieve</LINE>
6070 <LINE>For that which thou hast done,--must send thee hence</LINE>
6071 <LINE>With fiery quickness: therefore prepare thyself;</LINE>
6072 <LINE>The bark is ready, and the wind at help,</LINE>
6073 <LINE>The associates tend, and every thing is bent</LINE>
6074 <LINE>For England.</LINE>
6075 </SPEECH>
6076
6077 <SPEECH>
6078 <SPEAKER>HAMLET</SPEAKER>
6079 <LINE>For England!</LINE>
6080 </SPEECH>
6081
6082 <SPEECH>
6083 <SPEAKER>KING CLAUDIUS</SPEAKER>
6084 <LINE>Ay, Hamlet.</LINE>
6085 </SPEECH>
6086
6087 <SPEECH>
6088 <SPEAKER>HAMLET</SPEAKER>
6089 <LINE>Good.</LINE>
6090 </SPEECH>
6091
6092 <SPEECH>
6093 <SPEAKER>KING CLAUDIUS</SPEAKER>
6094 <LINE>So is it, if thou knew'st our purposes.</LINE>
6095 </SPEECH>
6096
6097 <SPEECH>
6098 <SPEAKER>HAMLET</SPEAKER>
6099 <LINE>I see a cherub that sees them. But, come; for</LINE>
6100 <LINE>England! Farewell, dear mother.</LINE>
6101 </SPEECH>
6102
6103 <SPEECH>
6104 <SPEAKER>KING CLAUDIUS</SPEAKER>
6105 <LINE>Thy loving father, Hamlet.</LINE>
6106 </SPEECH>
6107
6108 <SPEECH>
6109 <SPEAKER>HAMLET</SPEAKER>
6110 <LINE>My mother: father and mother is man and wife; man</LINE>
6111 <LINE>and wife is one flesh; and so, my mother. Come, for England!</LINE>
6112 </SPEECH>
6113
6114
6115 <STAGEDIR>Exit</STAGEDIR>
6116
6117 <SPEECH>
6118 <SPEAKER>KING CLAUDIUS</SPEAKER>
6119 <LINE>Follow him at foot; tempt him with speed aboard;</LINE>
6120 <LINE>Delay it not; I'll have him hence to-night:</LINE>
6121 <LINE>Away! for every thing is seal'd and done</LINE>
6122 <LINE>That else leans on the affair: pray you, make haste.</LINE>
6123 <STAGEDIR>Exeunt ROSENCRANTZ and GUILDENSTERN</STAGEDIR>
6124 <LINE>And, England, if my love thou hold'st at aught--</LINE>
6125 <LINE>As my great power thereof may give thee sense,</LINE>
6126 <LINE>Since yet thy cicatrice looks raw and red</LINE>
6127 <LINE>After the Danish sword, and thy free awe</LINE>
6128 <LINE>Pays homage to us--thou mayst not coldly set</LINE>
6129 <LINE>Our sovereign process; which imports at full,</LINE>
6130 <LINE>By letters congruing to that effect,</LINE>
6131 <LINE>The present death of Hamlet. Do it, England;</LINE>
6132 <LINE>For like the hectic in my blood he rages,</LINE>
6133 <LINE>And thou must cure me: till I know 'tis done,</LINE>
6134 <LINE>Howe'er my haps, my joys were ne'er begun.</LINE>
6135 </SPEECH>
6136
6137
6138 <STAGEDIR>Exit</STAGEDIR>
6139 </SCENE>
6140
6141 <SCENE><TITLE>SCENE IV. A plain in Denmark.</TITLE>
6142 <STAGEDIR>Enter FORTINBRAS, a Captain, and Soldiers, marching</STAGEDIR>
6143
6144 <SPEECH>
6145 <SPEAKER>PRINCE FORTINBRAS</SPEAKER>
6146 <LINE>Go, captain, from me greet the Danish king;</LINE>
6147 <LINE>Tell him that, by his licence, Fortinbras</LINE>
6148 <LINE>Craves the conveyance of a promised march</LINE>
6149 <LINE>Over his kingdom. You know the rendezvous.</LINE>
6150 <LINE>If that his majesty would aught with us,</LINE>
6151 <LINE>We shall express our duty in his eye;</LINE>
6152 <LINE>And let him know so.</LINE>
6153 </SPEECH>
6154
6155 <SPEECH>
6156 <SPEAKER>Captain</SPEAKER>
6157 <LINE>I will do't, my lord.</LINE>
6158 </SPEECH>
6159
6160 <SPEECH>
6161 <SPEAKER>PRINCE FORTINBRAS</SPEAKER>
6162 <LINE>Go softly on.</LINE>
6163 </SPEECH>
6164
6165 <STAGEDIR>Exeunt FORTINBRAS and Soldiers</STAGEDIR>
6166 <STAGEDIR>Enter HAMLET, ROSENCRANTZ, GUILDENSTERN, and others</STAGEDIR>
6167
6168 <SPEECH>
6169 <SPEAKER>HAMLET</SPEAKER>
6170 <LINE>Good sir, whose powers are these?</LINE>
6171 </SPEECH>
6172
6173 <SPEECH>
6174 <SPEAKER>Captain</SPEAKER>
6175 <LINE>They are of Norway, sir.</LINE>
6176 </SPEECH>
6177
6178 <SPEECH>
6179 <SPEAKER>HAMLET</SPEAKER>
6180 <LINE>How purposed, sir, I pray you?</LINE>
6181 </SPEECH>
6182
6183 <SPEECH>
6184 <SPEAKER>Captain</SPEAKER>
6185 <LINE>Against some part of Poland.</LINE>
6186 </SPEECH>
6187
6188 <SPEECH>
6189 <SPEAKER>HAMLET</SPEAKER>
6190 <LINE>Who commands them, sir?</LINE>
6191 </SPEECH>
6192
6193 <SPEECH>
6194 <SPEAKER>Captain</SPEAKER>
6195 <LINE>The nephews to old Norway, Fortinbras.</LINE>
6196 </SPEECH>
6197
6198 <SPEECH>
6199 <SPEAKER>HAMLET</SPEAKER>
6200 <LINE>Goes it against the main of Poland, sir,</LINE>
6201 <LINE>Or for some frontier?</LINE>
6202 </SPEECH>
6203
6204 <SPEECH>
6205 <SPEAKER>Captain</SPEAKER>
6206 <LINE>Truly to speak, and with no addition,</LINE>
6207 <LINE>We go to gain a little patch of ground</LINE>
6208 <LINE>That hath in it no profit but the name.</LINE>
6209 <LINE>To pay five ducats, five, I would not farm it;</LINE>
6210 <LINE>Nor will it yield to Norway or the Pole</LINE>
6211 <LINE>A ranker rate, should it be sold in fee.</LINE>
6212 </SPEECH>
6213
6214 <SPEECH>
6215 <SPEAKER>HAMLET</SPEAKER>
6216 <LINE>Why, then the Polack never will defend it.</LINE>
6217 </SPEECH>
6218
6219 <SPEECH>
6220 <SPEAKER>Captain</SPEAKER>
6221 <LINE>Yes, it is already garrison'd.</LINE>
6222 </SPEECH>
6223
6224 <SPEECH>
6225 <SPEAKER>HAMLET</SPEAKER>
6226 <LINE>Two thousand souls and twenty thousand ducats</LINE>
6227 <LINE>Will not debate the question of this straw:</LINE>
6228 <LINE>This is the imposthume of much wealth and peace,</LINE>
6229 <LINE>That inward breaks, and shows no cause without</LINE>
6230 <LINE>Why the man dies. I humbly thank you, sir.</LINE>
6231 </SPEECH>
6232
6233 <SPEECH>
6234 <SPEAKER>Captain</SPEAKER>
6235 <LINE>God be wi' you, sir.</LINE>
6236 </SPEECH>
6237
6238
6239 <STAGEDIR>Exit</STAGEDIR>
6240
6241 <SPEECH>
6242 <SPEAKER>ROSENCRANTZ</SPEAKER>
6243 <LINE>Wilt please you go, my lord?</LINE>
6244 </SPEECH>
6245
6246 <SPEECH>
6247 <SPEAKER>HAMLET</SPEAKER>
6248 <LINE>I'll be with you straight go a little before.</LINE>
6249 <STAGEDIR>Exeunt all except HAMLET</STAGEDIR>
6250 <LINE>How all occasions do inform against me,</LINE>
6251 <LINE>And spur my dull revenge! What is a man,</LINE>
6252 <LINE>If his chief good and market of his time</LINE>
6253 <LINE>Be but to sleep and feed? a beast, no more.</LINE>
6254 <LINE>Sure, he that made us with such large discourse,</LINE>
6255 <LINE>Looking before and after, gave us not</LINE>
6256 <LINE>That capability and god-like reason</LINE>
6257 <LINE>To fust in us unused. Now, whether it be</LINE>
6258 <LINE>Bestial oblivion, or some craven scruple</LINE>
6259 <LINE>Of thinking too precisely on the event,</LINE>
6260 <LINE>A thought which, quarter'd, hath but one part wisdom</LINE>
6261 <LINE>And ever three parts coward, I do not know</LINE>
6262 <LINE>Why yet I live to say 'This thing's to do;'</LINE>
6263 <LINE>Sith I have cause and will and strength and means</LINE>
6264 <LINE>To do't. Examples gross as earth exhort me:</LINE>
6265 <LINE>Witness this army of such mass and charge</LINE>
6266 <LINE>Led by a delicate and tender prince,</LINE>
6267 <LINE>Whose spirit with divine ambition puff'd</LINE>
6268 <LINE>Makes mouths at the invisible event,</LINE>
6269 <LINE>Exposing what is mortal and unsure</LINE>
6270 <LINE>To all that fortune, death and danger dare,</LINE>
6271 <LINE>Even for an egg-shell. Rightly to be great</LINE>
6272 <LINE>Is not to stir without great argument,</LINE>
6273 <LINE>But greatly to find quarrel in a straw</LINE>
6274 <LINE>When honour's at the stake. How stand I then,</LINE>
6275 <LINE>That have a father kill'd, a mother stain'd,</LINE>
6276 <LINE>Excitements of my reason and my blood,</LINE>
6277 <LINE>And let all sleep? while, to my shame, I see</LINE>
6278 <LINE>The imminent death of twenty thousand men,</LINE>
6279 <LINE>That, for a fantasy and trick of fame,</LINE>
6280 <LINE>Go to their graves like beds, fight for a plot</LINE>
6281 <LINE>Whereon the numbers cannot try the cause,</LINE>
6282 <LINE>Which is not tomb enough and continent</LINE>
6283 <LINE>To hide the slain? O, from this time forth,</LINE>
6284 <LINE>My thoughts be bloody, or be nothing worth!</LINE>
6285 </SPEECH>
6286
6287
6288 <STAGEDIR>Exit</STAGEDIR>
6289 </SCENE>
6290
6291 <SCENE><TITLE>SCENE V. Elsinore. A room in the castle.</TITLE>
6292 <STAGEDIR>Enter QUEEN GERTRUDE, HORATIO, and a Gentleman</STAGEDIR>
6293
6294 <SPEECH>
6295 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6296 <LINE>I will not speak with her.</LINE>
6297 </SPEECH>
6298
6299 <SPEECH>
6300 <SPEAKER>Gentleman</SPEAKER>
6301 <LINE>She is importunate, indeed distract:</LINE>
6302 <LINE>Her mood will needs be pitied.</LINE>
6303 </SPEECH>
6304
6305 <SPEECH>
6306 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6307 <LINE>What would she have?</LINE>
6308 </SPEECH>
6309
6310 <SPEECH>
6311 <SPEAKER>Gentleman</SPEAKER>
6312 <LINE>She speaks much of her father; says she hears</LINE>
6313 <LINE>There's tricks i' the world; and hems, and beats her heart;</LINE>
6314 <LINE>Spurns enviously at straws; speaks things in doubt,</LINE>
6315 <LINE>That carry but half sense: her speech is nothing,</LINE>
6316 <LINE>Yet the unshaped use of it doth move</LINE>
6317 <LINE>The hearers to collection; they aim at it,</LINE>
6318 <LINE>And botch the words up fit to their own thoughts;</LINE>
6319 <LINE>Which, as her winks, and nods, and gestures</LINE>
6320 <LINE>yield them,</LINE>
6321 <LINE>Indeed would make one think there might be thought,</LINE>
6322 <LINE>Though nothing sure, yet much unhappily.</LINE>
6323 </SPEECH>
6324
6325 <SPEECH>
6326 <SPEAKER>HORATIO</SPEAKER>
6327 <LINE>'Twere good she were spoken with; for she may strew</LINE>
6328 <LINE>Dangerous conjectures in ill-breeding minds.</LINE>
6329 </SPEECH>
6330
6331 <SPEECH>
6332 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6333 <LINE>Let her come in.</LINE>
6334 <STAGEDIR>Exit HORATIO</STAGEDIR>
6335 <LINE>To my sick soul, as sin's true nature is,</LINE>
6336 <LINE>Each toy seems prologue to some great amiss:</LINE>
6337 <LINE>So full of artless jealousy is guilt,</LINE>
6338 <LINE>It spills itself in fearing to be spilt.</LINE>
6339 </SPEECH>
6340
6341
6342 <STAGEDIR>Re-enter HORATIO, with OPHELIA</STAGEDIR>
6343
6344 <SPEECH>
6345 <SPEAKER>OPHELIA</SPEAKER>
6346 <LINE>Where is the beauteous majesty of Denmark?</LINE>
6347 </SPEECH>
6348
6349 <SPEECH>
6350 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6351 <LINE>How now, Ophelia!</LINE>
6352 </SPEECH>
6353
6354 <SPEECH>
6355 <SPEAKER>OPHELIA</SPEAKER>
6356 <LINE><STAGEDIR>Sings</STAGEDIR></LINE>
6357 <LINE>How should I your true love know</LINE>
6358 <LINE>From another one?</LINE>
6359 <LINE>By his cockle hat and staff,</LINE>
6360 <LINE>And his sandal shoon.</LINE>
6361 </SPEECH>
6362
6363 <SPEECH>
6364 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6365 <LINE>Alas, sweet lady, what imports this song?</LINE>
6366 </SPEECH>
6367
6368 <SPEECH>
6369 <SPEAKER>OPHELIA</SPEAKER>
6370 <LINE>Say you? nay, pray you, mark.</LINE>
6371 <STAGEDIR>Sings</STAGEDIR>
6372 <LINE>He is dead and gone, lady,</LINE>
6373 <LINE>He is dead and gone;</LINE>
6374 <LINE>At his head a grass-green turf,</LINE>
6375 <LINE>At his heels a stone.</LINE>
6376 </SPEECH>
6377
6378 <SPEECH>
6379 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6380 <LINE>Nay, but, Ophelia,--</LINE>
6381 </SPEECH>
6382
6383 <SPEECH>
6384 <SPEAKER>OPHELIA</SPEAKER>
6385 <LINE>Pray you, mark.</LINE>
6386 <STAGEDIR>Sings</STAGEDIR>
6387 <LINE>White his shroud as the mountain snow,--</LINE>
6388 </SPEECH>
6389
6390
6391 <STAGEDIR>Enter KING CLAUDIUS</STAGEDIR>
6392
6393 <SPEECH>
6394 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6395 <LINE>Alas, look here, my lord.</LINE>
6396 </SPEECH>
6397
6398 <SPEECH>
6399 <SPEAKER>OPHELIA</SPEAKER>
6400 <LINE><STAGEDIR>Sings</STAGEDIR></LINE>
6401 <LINE>Larded with sweet flowers</LINE>
6402 <LINE>Which bewept to the grave did go</LINE>
6403 <LINE>With true-love showers.</LINE>
6404 </SPEECH>
6405
6406 <SPEECH>
6407 <SPEAKER>KING CLAUDIUS</SPEAKER>
6408 <LINE>How do you, pretty lady?</LINE>
6409 </SPEECH>
6410
6411 <SPEECH>
6412 <SPEAKER>OPHELIA</SPEAKER>
6413 <LINE>Well, God 'ild you! They say the owl was a baker's</LINE>
6414 <LINE>daughter. Lord, we know what we are, but know not</LINE>
6415 <LINE>what we may be. God be at your table!</LINE>
6416 </SPEECH>
6417
6418 <SPEECH>
6419 <SPEAKER>KING CLAUDIUS</SPEAKER>
6420 <LINE>Conceit upon her father.</LINE>
6421 </SPEECH>
6422
6423 <SPEECH>
6424 <SPEAKER>OPHELIA</SPEAKER>
6425 <LINE>Pray you, let's have no words of this; but when they</LINE>
6426 <LINE>ask you what it means, say you this:</LINE>
6427 <STAGEDIR>Sings</STAGEDIR>
6428 <LINE>To-morrow is Saint Valentine's day,</LINE>
6429 <LINE>All in the morning betime,</LINE>
6430 <LINE>And I a maid at your window,</LINE>
6431 <LINE>To be your Valentine.</LINE>
6432 <LINE>Then up he rose, and donn'd his clothes,</LINE>
6433 <LINE>And dupp'd the chamber-door;</LINE>
6434 <LINE>Let in the maid, that out a maid</LINE>
6435 <LINE>Never departed more.</LINE>
6436 </SPEECH>
6437
6438 <SPEECH>
6439 <SPEAKER>KING CLAUDIUS</SPEAKER>
6440 <LINE>Pretty Ophelia!</LINE>
6441 </SPEECH>
6442
6443 <SPEECH>
6444 <SPEAKER>OPHELIA</SPEAKER>
6445 <LINE>Indeed, la, without an oath, I'll make an end on't:</LINE>
6446 <STAGEDIR>Sings</STAGEDIR>
6447 <LINE>By Gis and by Saint Charity,</LINE>
6448 <LINE>Alack, and fie for shame!</LINE>
6449 <LINE>Young men will do't, if they come to't;</LINE>
6450 <LINE>By cock, they are to blame.</LINE>
6451 <LINE>Quoth she, before you tumbled me,</LINE>
6452 <LINE>You promised me to wed.</LINE>
6453 <LINE>So would I ha' done, by yonder sun,</LINE>
6454 <LINE>An thou hadst not come to my bed.</LINE>
6455 </SPEECH>
6456
6457 <SPEECH>
6458 <SPEAKER>KING CLAUDIUS</SPEAKER>
6459 <LINE>How long hath she been thus?</LINE>
6460 </SPEECH>
6461
6462 <SPEECH>
6463 <SPEAKER>OPHELIA</SPEAKER>
6464 <LINE>I hope all will be well. We must be patient: but I</LINE>
6465 <LINE>cannot choose but weep, to think they should lay him</LINE>
6466 <LINE>i' the cold ground. My brother shall know of it:</LINE>
6467 <LINE>and so I thank you for your good counsel. Come, my</LINE>
6468 <LINE>coach! Good night, ladies; good night, sweet ladies;</LINE>
6469 <LINE>good night, good night.</LINE>
6470 </SPEECH>
6471
6472
6473 <STAGEDIR>Exit</STAGEDIR>
6474
6475 <SPEECH>
6476 <SPEAKER>KING CLAUDIUS</SPEAKER>
6477 <LINE>Follow her close; give her good watch,</LINE>
6478 <LINE>I pray you.</LINE>
6479 <STAGEDIR>Exit HORATIO</STAGEDIR>
6480 <LINE>O, this is the poison of deep grief; it springs</LINE>
6481 <LINE>All from her father's death. O Gertrude, Gertrude,</LINE>
6482 <LINE>When sorrows come, they come not single spies</LINE>
6483 <LINE>But in battalions. First, her father slain:</LINE>
6484 <LINE>Next, your son gone; and he most violent author</LINE>
6485 <LINE>Of his own just remove: the people muddied,</LINE>
6486 <LINE>Thick and unwholesome in their thoughts and whispers,</LINE>
6487 <LINE>For good Polonius' death; and we have done but greenly,</LINE>
6488 <LINE>In hugger-mugger to inter him: poor Ophelia</LINE>
6489 <LINE>Divided from herself and her fair judgment,</LINE>
6490 <LINE>Without the which we are pictures, or mere beasts:</LINE>
6491 <LINE>Last, and as much containing as all these,</LINE>
6492 <LINE>Her brother is in secret come from France;</LINE>
6493 <LINE>Feeds on his wonder, keeps himself in clouds,</LINE>
6494 <LINE>And wants not buzzers to infect his ear</LINE>
6495 <LINE>With pestilent speeches of his father's death;</LINE>
6496 <LINE>Wherein necessity, of matter beggar'd,</LINE>
6497 <LINE>Will nothing stick our person to arraign</LINE>
6498 <LINE>In ear and ear. O my dear Gertrude, this,</LINE>
6499 <LINE>Like to a murdering-piece, in many places</LINE>
6500 <LINE>Gives me superfluous death.</LINE>
6501 </SPEECH>
6502
6503
6504 <STAGEDIR>A noise within</STAGEDIR>
6505
6506 <SPEECH>
6507 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6508 <LINE>Alack, what noise is this?</LINE>
6509 </SPEECH>
6510
6511 <SPEECH>
6512 <SPEAKER>KING CLAUDIUS</SPEAKER>
6513 <LINE>Where are my Switzers? Let them guard the door.</LINE>
6514 <STAGEDIR>Enter another Gentleman</STAGEDIR>
6515 <LINE>What is the matter?</LINE>
6516 </SPEECH>
6517
6518 <SPEECH>
6519 <SPEAKER>Gentleman</SPEAKER>
6520 <LINE>Save yourself, my lord:</LINE>
6521 <LINE>The ocean, overpeering of his list,</LINE>
6522 <LINE>Eats not the flats with more impetuous haste</LINE>
6523 <LINE>Than young Laertes, in a riotous head,</LINE>
6524 <LINE>O'erbears your officers. The rabble call him lord;</LINE>
6525 <LINE>And, as the world were now but to begin,</LINE>
6526 <LINE>Antiquity forgot, custom not known,</LINE>
6527 <LINE>The ratifiers and props of every word,</LINE>
6528 <LINE>They cry 'Choose we: Laertes shall be king:'</LINE>
6529 <LINE>Caps, hands, and tongues, applaud it to the clouds:</LINE>
6530 <LINE>'Laertes shall be king, Laertes king!'</LINE>
6531 </SPEECH>
6532
6533 <SPEECH>
6534 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6535 <LINE>How cheerfully on the false trail they cry!</LINE>
6536 <LINE>O, this is counter, you false Danish dogs!</LINE>
6537 </SPEECH>
6538
6539 <SPEECH>
6540 <SPEAKER>KING CLAUDIUS</SPEAKER>
6541 <LINE>The doors are broke.</LINE>
6542 </SPEECH>
6543
6544 <STAGEDIR>Noise within</STAGEDIR>
6545 <STAGEDIR>Enter LAERTES, armed; Danes following</STAGEDIR>
6546
6547 <SPEECH>
6548 <SPEAKER>LAERTES</SPEAKER>
6549 <LINE>Where is this king? Sirs, stand you all without.</LINE>
6550 </SPEECH>
6551
6552 <SPEECH>
6553 <SPEAKER>Danes</SPEAKER>
6554 <LINE>No, let's come in.</LINE>
6555 </SPEECH>
6556
6557 <SPEECH>
6558 <SPEAKER>LAERTES</SPEAKER>
6559 <LINE>I pray you, give me leave.</LINE>
6560 </SPEECH>
6561
6562 <SPEECH>
6563 <SPEAKER>Danes</SPEAKER>
6564 <LINE>We will, we will.</LINE>
6565 </SPEECH>
6566
6567
6568 <STAGEDIR>They retire without the door</STAGEDIR>
6569
6570 <SPEECH>
6571 <SPEAKER>LAERTES</SPEAKER>
6572 <LINE>I thank you: keep the door. O thou vile king,</LINE>
6573 <LINE>Give me my father!</LINE>
6574 </SPEECH>
6575
6576 <SPEECH>
6577 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6578 <LINE>Calmly, good Laertes.</LINE>
6579 </SPEECH>
6580
6581 <SPEECH>
6582 <SPEAKER>LAERTES</SPEAKER>
6583 <LINE>That drop of blood that's calm proclaims me bastard,</LINE>
6584 <LINE>Cries cuckold to my father, brands the harlot</LINE>
6585 <LINE>Even here, between the chaste unsmirched brow</LINE>
6586 <LINE>Of my true mother.</LINE>
6587 </SPEECH>
6588
6589 <SPEECH>
6590 <SPEAKER>KING CLAUDIUS</SPEAKER>
6591 <LINE>What is the cause, Laertes,</LINE>
6592 <LINE>That thy rebellion looks so giant-like?</LINE>
6593 <LINE>Let him go, Gertrude; do not fear our person:</LINE>
6594 <LINE>There's such divinity doth hedge a king,</LINE>
6595 <LINE>That treason can but peep to what it would,</LINE>
6596 <LINE>Acts little of his will. Tell me, Laertes,</LINE>
6597 <LINE>Why thou art thus incensed. Let him go, Gertrude.</LINE>
6598 <LINE>Speak, man.</LINE>
6599 </SPEECH>
6600
6601 <SPEECH>
6602 <SPEAKER>LAERTES</SPEAKER>
6603 <LINE>Where is my father?</LINE>
6604 </SPEECH>
6605
6606 <SPEECH>
6607 <SPEAKER>KING CLAUDIUS</SPEAKER>
6608 <LINE>Dead.</LINE>
6609 </SPEECH>
6610
6611 <SPEECH>
6612 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
6613 <LINE>But not by him.</LINE>
6614 </SPEECH>
6615
6616 <SPEECH>
6617 <SPEAKER>KING CLAUDIUS</SPEAKER>
6618 <LINE>Let him demand his fill.</LINE>
6619 </SPEECH>
6620
6621 <SPEECH>
6622 <SPEAKER>LAERTES</SPEAKER>
6623 <LINE>How came he dead? I'll not be juggled with:</LINE>
6624 <LINE>To hell, allegiance! vows, to the blackest devil!</LINE>
6625 <LINE>Conscience and grace, to the profoundest pit!</LINE>
6626 <LINE>I dare damnation. To this point I stand,</LINE>
6627 <LINE>That both the worlds I give to negligence,</LINE>
6628 <LINE>Let come what comes; only I'll be revenged</LINE>
6629 <LINE>Most thoroughly for my father.</LINE>
6630 </SPEECH>
6631
6632 <SPEECH>
6633 <SPEAKER>KING CLAUDIUS</SPEAKER>
6634 <LINE>Who shall stay you?</LINE>
6635 </SPEECH>
6636
6637 <SPEECH>
6638 <SPEAKER>LAERTES</SPEAKER>
6639 <LINE>My will, not all the world:</LINE>
6640 <LINE>And for my means, I'll husband them so well,</LINE>
6641 <LINE>They shall go far with little.</LINE>
6642 </SPEECH>
6643
6644 <SPEECH>
6645 <SPEAKER>KING CLAUDIUS</SPEAKER>
6646 <LINE>Good Laertes,</LINE>
6647 <LINE>If you desire to know the certainty</LINE>
6648 <LINE>Of your dear father's death, is't writ in your revenge,</LINE>
6649 <LINE>That, swoopstake, you will draw both friend and foe,</LINE>
6650 <LINE>Winner and loser?</LINE>
6651 </SPEECH>
6652
6653 <SPEECH>
6654 <SPEAKER>LAERTES</SPEAKER>
6655 <LINE>None but his enemies.</LINE>
6656 </SPEECH>
6657
6658 <SPEECH>
6659 <SPEAKER>KING CLAUDIUS</SPEAKER>
6660 <LINE>Will you know them then?</LINE>
6661 </SPEECH>
6662
6663 <SPEECH>
6664 <SPEAKER>LAERTES</SPEAKER>
6665 <LINE>To his good friends thus wide I'll ope my arms;</LINE>
6666 <LINE>And like the kind life-rendering pelican,</LINE>
6667 <LINE>Repast them with my blood.</LINE>
6668 </SPEECH>
6669
6670 <SPEECH>
6671 <SPEAKER>KING CLAUDIUS</SPEAKER>
6672 <LINE>Why, now you speak</LINE>
6673 <LINE>Like a good child and a true gentleman.</LINE>
6674 <LINE>That I am guiltless of your father's death,</LINE>
6675 <LINE>And am most sensible in grief for it,</LINE>
6676 <LINE>It shall as level to your judgment pierce</LINE>
6677 <LINE>As day does to your eye.</LINE>
6678 </SPEECH>
6679
6680 <SPEECH>
6681 <SPEAKER>Danes</SPEAKER>
6682 <LINE><STAGEDIR>Within</STAGEDIR> Let her come in.</LINE>
6683 </SPEECH>
6684
6685 <SPEECH>
6686 <SPEAKER>LAERTES</SPEAKER>
6687 <LINE>How now! what noise is that?</LINE>
6688 <STAGEDIR>Re-enter OPHELIA</STAGEDIR>
6689 <LINE>O heat, dry up my brains! tears seven times salt,</LINE>
6690 <LINE>Burn out the sense and virtue of mine eye!</LINE>
6691 <LINE>By heaven, thy madness shall be paid by weight,</LINE>
6692 <LINE>Till our scale turn the beam. O rose of May!</LINE>
6693 <LINE>Dear maid, kind sister, sweet Ophelia!</LINE>
6694 <LINE>O heavens! is't possible, a young maid's wits</LINE>
6695 <LINE>Should be as moral as an old man's life?</LINE>
6696 <LINE>Nature is fine in love, and where 'tis fine,</LINE>
6697 <LINE>It sends some precious instance of itself</LINE>
6698 <LINE>After the thing it loves.</LINE>
6699 </SPEECH>
6700
6701 <SPEECH>
6702 <SPEAKER>OPHELIA</SPEAKER>
6703 <LINE><STAGEDIR>Sings</STAGEDIR></LINE>
6704 <LINE>They bore him barefaced on the bier;</LINE>
6705 <LINE>Hey non nonny, nonny, hey nonny;</LINE>
6706 <LINE>And in his grave rain'd many a tear:--</LINE>
6707 <LINE>Fare you well, my dove!</LINE>
6708 </SPEECH>
6709
6710 <SPEECH>
6711 <SPEAKER>LAERTES</SPEAKER>
6712 <LINE>Hadst thou thy wits, and didst persuade revenge,</LINE>
6713 <LINE>It could not move thus.</LINE>
6714 </SPEECH>
6715
6716 <SPEECH>
6717 <SPEAKER>OPHELIA</SPEAKER>
6718 <LINE><STAGEDIR>Sings</STAGEDIR></LINE>
6719 <LINE>You must sing a-down a-down,</LINE>
6720 <LINE>An you call him a-down-a.</LINE>
6721 <LINE>O, how the wheel becomes it! It is the false</LINE>
6722 <LINE>steward, that stole his master's daughter.</LINE>
6723 </SPEECH>
6724
6725 <SPEECH>
6726 <SPEAKER>LAERTES</SPEAKER>
6727 <LINE>This nothing's more than matter.</LINE>
6728 </SPEECH>
6729
6730 <SPEECH>
6731 <SPEAKER>OPHELIA</SPEAKER>
6732 <LINE>There's rosemary, that's for remembrance; pray,</LINE>
6733 <LINE>love, remember: and there is pansies. that's for thoughts.</LINE>
6734 </SPEECH>
6735
6736 <SPEECH>
6737 <SPEAKER>LAERTES</SPEAKER>
6738 <LINE>A document in madness, thoughts and remembrance fitted.</LINE>
6739 </SPEECH>
6740
6741 <SPEECH>
6742 <SPEAKER>OPHELIA</SPEAKER>
6743 <LINE>There's fennel for you, and columbines: there's rue</LINE>
6744 <LINE>for you; and here's some for me: we may call it</LINE>
6745 <LINE>herb-grace o' Sundays: O you must wear your rue with</LINE>
6746 <LINE>a difference. There's a daisy: I would give you</LINE>
6747 <LINE>some violets, but they withered all when my father</LINE>
6748 <LINE>died: they say he made a good end,--</LINE>
6749 <STAGEDIR>Sings</STAGEDIR>
6750 <LINE>For bonny sweet Robin is all my joy.</LINE>
6751 </SPEECH>
6752
6753 <SPEECH>
6754 <SPEAKER>LAERTES</SPEAKER>
6755 <LINE>Thought and affliction, passion, hell itself,</LINE>
6756 <LINE>She turns to favour and to prettiness.</LINE>
6757 </SPEECH>
6758
6759 <SPEECH>
6760 <SPEAKER>OPHELIA</SPEAKER>
6761 <LINE><STAGEDIR>Sings</STAGEDIR></LINE>
6762 <LINE>And will he not come again?</LINE>
6763 <LINE>And will he not come again?</LINE>
6764 <LINE>No, no, he is dead:</LINE>
6765 <LINE>Go to thy death-bed:</LINE>
6766 <LINE>He never will come again.</LINE>
6767 <LINE>His beard was as white as snow,</LINE>
6768 <LINE>All flaxen was his poll:</LINE>
6769 <LINE>He is gone, he is gone,</LINE>
6770 <LINE>And we cast away moan:</LINE>
6771 <LINE>God ha' mercy on his soul!</LINE>
6772 <LINE>And of all Christian souls, I pray God. God be wi' ye.</LINE>
6773 </SPEECH>
6774
6775
6776 <STAGEDIR>Exit</STAGEDIR>
6777
6778 <SPEECH>
6779 <SPEAKER>LAERTES</SPEAKER>
6780 <LINE>Do you see this, O God?</LINE>
6781 </SPEECH>
6782
6783 <SPEECH>
6784 <SPEAKER>KING CLAUDIUS</SPEAKER>
6785 <LINE>Laertes, I must commune with your grief,</LINE>
6786 <LINE>Or you deny me right. Go but apart,</LINE>
6787 <LINE>Make choice of whom your wisest friends you will.</LINE>
6788 <LINE>And they shall hear and judge 'twixt you and me:</LINE>
6789 <LINE>If by direct or by collateral hand</LINE>
6790 <LINE>They find us touch'd, we will our kingdom give,</LINE>
6791 <LINE>Our crown, our life, and all that we can ours,</LINE>
6792 <LINE>To you in satisfaction; but if not,</LINE>
6793 <LINE>Be you content to lend your patience to us,</LINE>
6794 <LINE>And we shall jointly labour with your soul</LINE>
6795 <LINE>To give it due content.</LINE>
6796 </SPEECH>
6797
6798 <SPEECH>
6799 <SPEAKER>LAERTES</SPEAKER>
6800 <LINE>Let this be so;</LINE>
6801 <LINE>His means of death, his obscure funeral--</LINE>
6802 <LINE>No trophy, sword, nor hatchment o'er his bones,</LINE>
6803 <LINE>No noble rite nor formal ostentation--</LINE>
6804 <LINE>Cry to be heard, as 'twere from heaven to earth,</LINE>
6805 <LINE>That I must call't in question.</LINE>
6806 </SPEECH>
6807
6808 <SPEECH>
6809 <SPEAKER>KING CLAUDIUS</SPEAKER>
6810 <LINE>So you shall;</LINE>
6811 <LINE>And where the offence is let the great axe fall.</LINE>
6812 <LINE>I pray you, go with me.</LINE>
6813 </SPEECH>
6814
6815
6816 <STAGEDIR>Exeunt</STAGEDIR>
6817 </SCENE>
6818
6819 <SCENE><TITLE>SCENE VI. Another room in the castle.</TITLE>
6820 <STAGEDIR>Enter HORATIO and a Servant</STAGEDIR>
6821
6822 <SPEECH>
6823 <SPEAKER>HORATIO</SPEAKER>
6824 <LINE>What are they that would speak with me?</LINE>
6825 </SPEECH>
6826
6827 <SPEECH>
6828 <SPEAKER>Servant</SPEAKER>
6829 <LINE>Sailors, sir: they say they have letters for you.</LINE>
6830 </SPEECH>
6831
6832 <SPEECH>
6833 <SPEAKER>HORATIO</SPEAKER>
6834 <LINE>Let them come in.</LINE>
6835 <STAGEDIR>Exit Servant</STAGEDIR>
6836 <LINE>I do not know from what part of the world</LINE>
6837 <LINE>I should be greeted, if not from Lord Hamlet.</LINE>
6838 </SPEECH>
6839
6840
6841 <STAGEDIR>Enter Sailors</STAGEDIR>
6842
6843 <SPEECH>
6844 <SPEAKER>First Sailor</SPEAKER>
6845 <LINE>God bless you, sir.</LINE>
6846 </SPEECH>
6847
6848 <SPEECH>
6849 <SPEAKER>HORATIO</SPEAKER>
6850 <LINE>Let him bless thee too.</LINE>
6851 </SPEECH>
6852
6853 <SPEECH>
6854 <SPEAKER>First Sailor</SPEAKER>
6855 <LINE>He shall, sir, an't please him. There's a letter for</LINE>
6856 <LINE>you, sir; it comes from the ambassador that was</LINE>
6857 <LINE>bound for England; if your name be Horatio, as I am</LINE>
6858 <LINE>let to know it is.</LINE>
6859 </SPEECH>
6860
6861 <SPEECH>
6862 <SPEAKER>HORATIO</SPEAKER>
6863 <LINE><STAGEDIR>Reads</STAGEDIR> 'Horatio, when thou shalt have overlooked</LINE>
6864 <LINE>this, give these fellows some means to the king:</LINE>
6865 <LINE>they have letters for him. Ere we were two days old</LINE>
6866 <LINE>at sea, a pirate of very warlike appointment gave us</LINE>
6867 <LINE>chase. Finding ourselves too slow of sail, we put on</LINE>
6868 <LINE>a compelled valour, and in the grapple I boarded</LINE>
6869 <LINE>them: on the instant they got clear of our ship; so</LINE>
6870 <LINE>I alone became their prisoner. They have dealt with</LINE>
6871 <LINE>me like thieves of mercy: but they knew what they</LINE>
6872 <LINE>did; I am to do a good turn for them. Let the king</LINE>
6873 <LINE>have the letters I have sent; and repair thou to me</LINE>
6874 <LINE>with as much speed as thou wouldst fly death. I</LINE>
6875 <LINE>have words to speak in thine ear will make thee</LINE>
6876 <LINE>dumb; yet are they much too light for the bore of</LINE>
6877 <LINE>the matter. These good fellows will bring thee</LINE>
6878 <LINE>where I am. Rosencrantz and Guildenstern hold their</LINE>
6879 <LINE>course for England: of them I have much to tell</LINE>
6880 <LINE>thee. Farewell.</LINE>
6881 <LINE>'He that thou knowest thine, HAMLET.'</LINE>
6882 <LINE>Come, I will make you way for these your letters;</LINE>
6883 <LINE>And do't the speedier, that you may direct me</LINE>
6884 <LINE>To him from whom you brought them.</LINE>
6885 </SPEECH>
6886
6887
6888 <STAGEDIR>Exeunt</STAGEDIR>
6889 </SCENE>
6890
6891 <SCENE><TITLE>SCENE VII. Another room in the castle.</TITLE>
6892 <STAGEDIR>Enter KING CLAUDIUS and LAERTES</STAGEDIR>
6893
6894 <SPEECH>
6895 <SPEAKER>KING CLAUDIUS</SPEAKER>
6896 <LINE>Now must your conscience my acquaintance seal,</LINE>
6897 <LINE>And you must put me in your heart for friend,</LINE>
6898 <LINE>Sith you have heard, and with a knowing ear,</LINE>
6899 <LINE>That he which hath your noble father slain</LINE>
6900 <LINE>Pursued my life.</LINE>
6901 </SPEECH>
6902
6903 <SPEECH>
6904 <SPEAKER>LAERTES</SPEAKER>
6905 <LINE>It well appears: but tell me</LINE>
6906 <LINE>Why you proceeded not against these feats,</LINE>
6907 <LINE>So crimeful and so capital in nature,</LINE>
6908 <LINE>As by your safety, wisdom, all things else,</LINE>
6909 <LINE>You mainly were stirr'd up.</LINE>
6910 </SPEECH>
6911
6912 <SPEECH>
6913 <SPEAKER>KING CLAUDIUS</SPEAKER>
6914 <LINE>O, for two special reasons;</LINE>
6915 <LINE>Which may to you, perhaps, seem much unsinew'd,</LINE>
6916 <LINE>But yet to me they are strong. The queen his mother</LINE>
6917 <LINE>Lives almost by his looks; and for myself--</LINE>
6918 <LINE>My virtue or my plague, be it either which--</LINE>
6919 <LINE>She's so conjunctive to my life and soul,</LINE>
6920 <LINE>That, as the star moves not but in his sphere,</LINE>
6921 <LINE>I could not but by her. The other motive,</LINE>
6922 <LINE>Why to a public count I might not go,</LINE>
6923 <LINE>Is the great love the general gender bear him;</LINE>
6924 <LINE>Who, dipping all his faults in their affection,</LINE>
6925 <LINE>Would, like the spring that turneth wood to stone,</LINE>
6926 <LINE>Convert his gyves to graces; so that my arrows,</LINE>
6927 <LINE>Too slightly timber'd for so loud a wind,</LINE>
6928 <LINE>Would have reverted to my bow again,</LINE>
6929 <LINE>And not where I had aim'd them.</LINE>
6930 </SPEECH>
6931
6932 <SPEECH>
6933 <SPEAKER>LAERTES</SPEAKER>
6934 <LINE>And so have I a noble father lost;</LINE>
6935 <LINE>A sister driven into desperate terms,</LINE>
6936 <LINE>Whose worth, if praises may go back again,</LINE>
6937 <LINE>Stood challenger on mount of all the age</LINE>
6938 <LINE>For her perfections: but my revenge will come.</LINE>
6939 </SPEECH>
6940
6941 <SPEECH>
6942 <SPEAKER>KING CLAUDIUS</SPEAKER>
6943 <LINE>Break not your sleeps for that: you must not think</LINE>
6944 <LINE>That we are made of stuff so flat and dull</LINE>
6945 <LINE>That we can let our beard be shook with danger</LINE>
6946 <LINE>And think it pastime. You shortly shall hear more:</LINE>
6947 <LINE>I loved your father, and we love ourself;</LINE>
6948 <LINE>And that, I hope, will teach you to imagine--</LINE>
6949 <STAGEDIR>Enter a Messenger</STAGEDIR>
6950 <LINE>How now! what news?</LINE>
6951 </SPEECH>
6952
6953 <SPEECH>
6954 <SPEAKER>Messenger</SPEAKER>
6955 <LINE>Letters, my lord, from Hamlet:</LINE>
6956 <LINE>This to your majesty; this to the queen.</LINE>
6957 </SPEECH>
6958
6959 <SPEECH>
6960 <SPEAKER>KING CLAUDIUS</SPEAKER>
6961 <LINE>From Hamlet! who brought them?</LINE>
6962 </SPEECH>
6963
6964 <SPEECH>
6965 <SPEAKER>Messenger</SPEAKER>
6966 <LINE>Sailors, my lord, they say; I saw them not:</LINE>
6967 <LINE>They were given me by Claudio; he received them</LINE>
6968 <LINE>Of him that brought them.</LINE>
6969 </SPEECH>
6970
6971 <SPEECH>
6972 <SPEAKER>KING CLAUDIUS</SPEAKER>
6973 <LINE>Laertes, you shall hear them. Leave us.</LINE>
6974 <STAGEDIR>Exit Messenger</STAGEDIR>
6975 <STAGEDIR>Reads</STAGEDIR>
6976 <LINE>'High and mighty, You shall know I am set naked on</LINE>
6977 <LINE>your kingdom. To-morrow shall I beg leave to see</LINE>
6978 <LINE>your kingly eyes: when I shall, first asking your</LINE>
6979 <LINE>pardon thereunto, recount the occasion of my sudden</LINE>
6980 <LINE>and more strange return. 'HAMLET.'</LINE>
6981 <LINE>What should this mean? Are all the rest come back?</LINE>
6982 <LINE>Or is it some abuse, and no such thing?</LINE>
6983 </SPEECH>
6984
6985 <SPEECH>
6986 <SPEAKER>LAERTES</SPEAKER>
6987 <LINE>Know you the hand?</LINE>
6988 </SPEECH>
6989
6990 <SPEECH>
6991 <SPEAKER>KING CLAUDIUS</SPEAKER>
6992 <LINE>'Tis Hamlets character. 'Naked!</LINE>
6993 <LINE>And in a postscript here, he says 'alone.'</LINE>
6994 <LINE>Can you advise me?</LINE>
6995 </SPEECH>
6996
6997 <SPEECH>
6998 <SPEAKER>LAERTES</SPEAKER>
6999 <LINE>I'm lost in it, my lord. But let him come;</LINE>
7000 <LINE>It warms the very sickness in my heart,</LINE>
7001 <LINE>That I shall live and tell him to his teeth,</LINE>
7002 <LINE>'Thus didest thou.'</LINE>
7003 </SPEECH>
7004
7005 <SPEECH>
7006 <SPEAKER>KING CLAUDIUS</SPEAKER>
7007 <LINE>If it be so, Laertes--</LINE>
7008 <LINE>As how should it be so? how otherwise?--</LINE>
7009 <LINE>Will you be ruled by me?</LINE>
7010 </SPEECH>
7011
7012 <SPEECH>
7013 <SPEAKER>LAERTES</SPEAKER>
7014 <LINE>Ay, my lord;</LINE>
7015 <LINE>So you will not o'errule me to a peace.</LINE>
7016 </SPEECH>
7017
7018 <SPEECH>
7019 <SPEAKER>KING CLAUDIUS</SPEAKER>
7020 <LINE>To thine own peace. If he be now return'd,</LINE>
7021 <LINE>As checking at his voyage, and that he means</LINE>
7022 <LINE>No more to undertake it, I will work him</LINE>
7023 <LINE>To an exploit, now ripe in my device,</LINE>
7024 <LINE>Under the which he shall not choose but fall:</LINE>
7025 <LINE>And for his death no wind of blame shall breathe,</LINE>
7026 <LINE>But even his mother shall uncharge the practise</LINE>
7027 <LINE>And call it accident.</LINE>
7028 </SPEECH>
7029
7030 <SPEECH>
7031 <SPEAKER>LAERTES</SPEAKER>
7032 <LINE>My lord, I will be ruled;</LINE>
7033 <LINE>The rather, if you could devise it so</LINE>
7034 <LINE>That I might be the organ.</LINE>
7035 </SPEECH>
7036
7037 <SPEECH>
7038 <SPEAKER>KING CLAUDIUS</SPEAKER>
7039 <LINE>It falls right.</LINE>
7040 <LINE>You have been talk'd of since your travel much,</LINE>
7041 <LINE>And that in Hamlet's hearing, for a quality</LINE>
7042 <LINE>Wherein, they say, you shine: your sum of parts</LINE>
7043 <LINE>Did not together pluck such envy from him</LINE>
7044 <LINE>As did that one, and that, in my regard,</LINE>
7045 <LINE>Of the unworthiest siege.</LINE>
7046 </SPEECH>
7047
7048 <SPEECH>
7049 <SPEAKER>LAERTES</SPEAKER>
7050 <LINE>What part is that, my lord?</LINE>
7051 </SPEECH>
7052
7053 <SPEECH>
7054 <SPEAKER>KING CLAUDIUS</SPEAKER>
7055 <LINE>A very riband in the cap of youth,</LINE>
7056 <LINE>Yet needful too; for youth no less becomes</LINE>
7057 <LINE>The light and careless livery that it wears</LINE>
7058 <LINE>Than settled age his sables and his weeds,</LINE>
7059 <LINE>Importing health and graveness. Two months since,</LINE>
7060 <LINE>Here was a gentleman of Normandy:--</LINE>
7061 <LINE>I've seen myself, and served against, the French,</LINE>
7062 <LINE>And they can well on horseback: but this gallant</LINE>
7063 <LINE>Had witchcraft in't; he grew unto his seat;</LINE>
7064 <LINE>And to such wondrous doing brought his horse,</LINE>
7065 <LINE>As he had been incorpsed and demi-natured</LINE>
7066 <LINE>With the brave beast: so far he topp'd my thought,</LINE>
7067 <LINE>That I, in forgery of shapes and tricks,</LINE>
7068 <LINE>Come short of what he did.</LINE>
7069 </SPEECH>
7070
7071 <SPEECH>
7072 <SPEAKER>LAERTES</SPEAKER>
7073 <LINE>A Norman was't?</LINE>
7074 </SPEECH>
7075
7076 <SPEECH>
7077 <SPEAKER>KING CLAUDIUS</SPEAKER>
7078 <LINE>A Norman.</LINE>
7079 </SPEECH>
7080
7081 <SPEECH>
7082 <SPEAKER>LAERTES</SPEAKER>
7083 <LINE>Upon my life, Lamond.</LINE>
7084 </SPEECH>
7085
7086 <SPEECH>
7087 <SPEAKER>KING CLAUDIUS</SPEAKER>
7088 <LINE>The very same.</LINE>
7089 </SPEECH>
7090
7091 <SPEECH>
7092 <SPEAKER>LAERTES</SPEAKER>
7093 <LINE>I know him well: he is the brooch indeed</LINE>
7094 <LINE>And gem of all the nation.</LINE>
7095 </SPEECH>
7096
7097 <SPEECH>
7098 <SPEAKER>KING CLAUDIUS</SPEAKER>
7099 <LINE>He made confession of you,</LINE>
7100 <LINE>And gave you such a masterly report</LINE>
7101 <LINE>For art and exercise in your defence</LINE>
7102 <LINE>And for your rapier most especially,</LINE>
7103 <LINE>That he cried out, 'twould be a sight indeed,</LINE>
7104 <LINE>If one could match you: the scrimers of their nation,</LINE>
7105 <LINE>He swore, had had neither motion, guard, nor eye,</LINE>
7106 <LINE>If you opposed them. Sir, this report of his</LINE>
7107 <LINE>Did Hamlet so envenom with his envy</LINE>
7108 <LINE>That he could nothing do but wish and beg</LINE>
7109 <LINE>Your sudden coming o'er, to play with him.</LINE>
7110 <LINE>Now, out of this,--</LINE>
7111 </SPEECH>
7112
7113 <SPEECH>
7114 <SPEAKER>LAERTES</SPEAKER>
7115 <LINE>What out of this, my lord?</LINE>
7116 </SPEECH>
7117
7118 <SPEECH>
7119 <SPEAKER>KING CLAUDIUS</SPEAKER>
7120 <LINE>Laertes, was your father dear to you?</LINE>
7121 <LINE>Or are you like the painting of a sorrow,</LINE>
7122 <LINE>A face without a heart?</LINE>
7123 </SPEECH>
7124
7125 <SPEECH>
7126 <SPEAKER>LAERTES</SPEAKER>
7127 <LINE>Why ask you this?</LINE>
7128 </SPEECH>
7129
7130 <SPEECH>
7131 <SPEAKER>KING CLAUDIUS</SPEAKER>
7132 <LINE>Not that I think you did not love your father;</LINE>
7133 <LINE>But that I know love is begun by time;</LINE>
7134 <LINE>And that I see, in passages of proof,</LINE>
7135 <LINE>Time qualifies the spark and fire of it.</LINE>
7136 <LINE>There lives within the very flame of love</LINE>
7137 <LINE>A kind of wick or snuff that will abate it;</LINE>
7138 <LINE>And nothing is at a like goodness still;</LINE>
7139 <LINE>For goodness, growing to a plurisy,</LINE>
7140 <LINE>Dies in his own too much: that we would do</LINE>
7141 <LINE>We should do when we would; for this 'would' changes</LINE>
7142 <LINE>And hath abatements and delays as many</LINE>
7143 <LINE>As there are tongues, are hands, are accidents;</LINE>
7144 <LINE>And then this 'should' is like a spendthrift sigh,</LINE>
7145 <LINE>That hurts by easing. But, to the quick o' the ulcer:--</LINE>
7146 <LINE>Hamlet comes back: what would you undertake,</LINE>
7147 <LINE>To show yourself your father's son in deed</LINE>
7148 <LINE>More than in words?</LINE>
7149 </SPEECH>
7150
7151 <SPEECH>
7152 <SPEAKER>LAERTES</SPEAKER>
7153 <LINE>To cut his throat i' the church.</LINE>
7154 </SPEECH>
7155
7156 <SPEECH>
7157 <SPEAKER>KING CLAUDIUS</SPEAKER>
7158 <LINE>No place, indeed, should murder sanctuarize;</LINE>
7159 <LINE>Revenge should have no bounds. But, good Laertes,</LINE>
7160 <LINE>Will you do this, keep close within your chamber.</LINE>
7161 <LINE>Hamlet return'd shall know you are come home:</LINE>
7162 <LINE>We'll put on those shall praise your excellence</LINE>
7163 <LINE>And set a double varnish on the fame</LINE>
7164 <LINE>The Frenchman gave you, bring you in fine together</LINE>
7165 <LINE>And wager on your heads: he, being remiss,</LINE>
7166 <LINE>Most generous and free from all contriving,</LINE>
7167 <LINE>Will not peruse the foils; so that, with ease,</LINE>
7168 <LINE>Or with a little shuffling, you may choose</LINE>
7169 <LINE>A sword unbated, and in a pass of practise</LINE>
7170 <LINE>Requite him for your father.</LINE>
7171 </SPEECH>
7172
7173 <SPEECH>
7174 <SPEAKER>LAERTES</SPEAKER>
7175 <LINE>I will do't:</LINE>
7176 <LINE>And, for that purpose, I'll anoint my sword.</LINE>
7177 <LINE>I bought an unction of a mountebank,</LINE>
7178 <LINE>So mortal that, but dip a knife in it,</LINE>
7179 <LINE>Where it draws blood no cataplasm so rare,</LINE>
7180 <LINE>Collected from all simples that have virtue</LINE>
7181 <LINE>Under the moon, can save the thing from death</LINE>
7182 <LINE>That is but scratch'd withal: I'll touch my point</LINE>
7183 <LINE>With this contagion, that, if I gall him slightly,</LINE>
7184 <LINE>It may be death.</LINE>
7185 </SPEECH>
7186
7187 <SPEECH>
7188 <SPEAKER>KING CLAUDIUS</SPEAKER>
7189 <LINE>Let's further think of this;</LINE>
7190 <LINE>Weigh what convenience both of time and means</LINE>
7191 <LINE>May fit us to our shape: if this should fail,</LINE>
7192 <LINE>And that our drift look through our bad performance,</LINE>
7193 <LINE>'Twere better not assay'd: therefore this project</LINE>
7194 <LINE>Should have a back or second, that might hold,</LINE>
7195 <LINE>If this should blast in proof. Soft! let me see:</LINE>
7196 <LINE>We'll make a solemn wager on your cunnings: I ha't.</LINE>
7197 <LINE>When in your motion you are hot and dry--</LINE>
7198 <LINE>As make your bouts more violent to that end--</LINE>
7199 <LINE>And that he calls for drink, I'll have prepared him</LINE>
7200 <LINE>A chalice for the nonce, whereon but sipping,</LINE>
7201 <LINE>If he by chance escape your venom'd stuck,</LINE>
7202 <LINE>Our purpose may hold there.</LINE>
7203 <STAGEDIR>Enter QUEEN GERTRUDE</STAGEDIR>
7204 <LINE>How now, sweet queen!</LINE>
7205 </SPEECH>
7206
7207 <SPEECH>
7208 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
7209 <LINE>One woe doth tread upon another's heel,</LINE>
7210 <LINE>So fast they follow; your sister's drown'd, Laertes.</LINE>
7211 </SPEECH>
7212
7213 <SPEECH>
7214 <SPEAKER>LAERTES</SPEAKER>
7215 <LINE>Drown'd! O, where?</LINE>
7216 </SPEECH>
7217
7218 <SPEECH>
7219 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
7220 <LINE>There is a willow grows aslant a brook,</LINE>
7221 <LINE>That shows his hoar leaves in the glassy stream;</LINE>
7222 <LINE>There with fantastic garlands did she come</LINE>
7223 <LINE>Of crow-flowers, nettles, daisies, and long purples</LINE>
7224 <LINE>That liberal shepherds give a grosser name,</LINE>
7225 <LINE>But our cold maids do dead men's fingers call them:</LINE>
7226 <LINE>There, on the pendent boughs her coronet weeds</LINE>
7227 <LINE>Clambering to hang, an envious sliver broke;</LINE>
7228 <LINE>When down her weedy trophies and herself</LINE>
7229 <LINE>Fell in the weeping brook. Her clothes spread wide;</LINE>
7230 <LINE>And, mermaid-like, awhile they bore her up:</LINE>
7231 <LINE>Which time she chanted snatches of old tunes;</LINE>
7232 <LINE>As one incapable of her own distress,</LINE>
7233 <LINE>Or like a creature native and indued</LINE>
7234 <LINE>Unto that element: but long it could not be</LINE>
7235 <LINE>Till that her garments, heavy with their drink,</LINE>
7236 <LINE>Pull'd the poor wretch from her melodious lay</LINE>
7237 <LINE>To muddy death.</LINE>
7238 </SPEECH>
7239
7240 <SPEECH>
7241 <SPEAKER>LAERTES</SPEAKER>
7242 <LINE>Alas, then, she is drown'd?</LINE>
7243 </SPEECH>
7244
7245 <SPEECH>
7246 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
7247 <LINE>Drown'd, drown'd.</LINE>
7248 </SPEECH>
7249
7250 <SPEECH>
7251 <SPEAKER>LAERTES</SPEAKER>
7252 <LINE>Too much of water hast thou, poor Ophelia,</LINE>
7253 <LINE>And therefore I forbid my tears: but yet</LINE>
7254 <LINE>It is our trick; nature her custom holds,</LINE>
7255 <LINE>Let shame say what it will: when these are gone,</LINE>
7256 <LINE>The woman will be out. Adieu, my lord:</LINE>
7257 <LINE>I have a speech of fire, that fain would blaze,</LINE>
7258 <LINE>But that this folly douts it.</LINE>
7259 </SPEECH>
7260
7261
7262 <STAGEDIR>Exit</STAGEDIR>
7263
7264 <SPEECH>
7265 <SPEAKER>KING CLAUDIUS</SPEAKER>
7266 <LINE>Let's follow, Gertrude:</LINE>
7267 <LINE>How much I had to do to calm his rage!</LINE>
7268 <LINE>Now fear I this will give it start again;</LINE>
7269 <LINE>Therefore let's follow.</LINE>
7270 </SPEECH>
7271
7272
7273 <STAGEDIR>Exeunt</STAGEDIR>
7274 </SCENE>
7275
7276 </ACT>
7277
7278 <ACT><TITLE>ACT V</TITLE>
7279
7280 <SCENE><TITLE>SCENE I. A churchyard.</TITLE>
7281 <STAGEDIR>Enter two Clowns, with spades, &amp;c</STAGEDIR>
7282
7283 <SPEECH>
7284 <SPEAKER>First Clown</SPEAKER>
7285 <LINE>Is she to be buried in Christian burial that</LINE>
7286 <LINE>wilfully seeks her own salvation?</LINE>
7287 </SPEECH>
7288
7289 <SPEECH>
7290 <SPEAKER>Second Clown</SPEAKER>
7291 <LINE>I tell thee she is: and therefore make her grave</LINE>
7292 <LINE>straight: the crowner hath sat on her, and finds it</LINE>
7293 <LINE>Christian burial.</LINE>
7294 </SPEECH>
7295
7296 <SPEECH>
7297 <SPEAKER>First Clown</SPEAKER>
7298 <LINE>How can that be, unless she drowned herself in her</LINE>
7299 <LINE>own defence?</LINE>
7300 </SPEECH>
7301
7302 <SPEECH>
7303 <SPEAKER>Second Clown</SPEAKER>
7304 <LINE>Why, 'tis found so.</LINE>
7305 </SPEECH>
7306
7307 <SPEECH>
7308 <SPEAKER>First Clown</SPEAKER>
7309 <LINE>It must be 'se offendendo;' it cannot be else. For</LINE>
7310 <LINE>here lies the point: if I drown myself wittingly,</LINE>
7311 <LINE>it argues an act: and an act hath three branches: it</LINE>
7312 <LINE>is, to act, to do, to perform: argal, she drowned</LINE>
7313 <LINE>herself wittingly.</LINE>
7314 </SPEECH>
7315
7316 <SPEECH>
7317 <SPEAKER>Second Clown</SPEAKER>
7318 <LINE>Nay, but hear you, goodman delver,--</LINE>
7319 </SPEECH>
7320
7321 <SPEECH>
7322 <SPEAKER>First Clown</SPEAKER>
7323 <LINE>Give me leave. Here lies the water; good: here</LINE>
7324 <LINE>stands the man; good; if the man go to this water,</LINE>
7325 <LINE>and drown himself, it is, will he, nill he, he</LINE>
7326 <LINE>goes,--mark you that; but if the water come to him</LINE>
7327 <LINE>and drown him, he drowns not himself: argal, he</LINE>
7328 <LINE>that is not guilty of his own death shortens not his own life.</LINE>
7329 </SPEECH>
7330
7331 <SPEECH>
7332 <SPEAKER>Second Clown</SPEAKER>
7333 <LINE>But is this law?</LINE>
7334 </SPEECH>
7335
7336 <SPEECH>
7337 <SPEAKER>First Clown</SPEAKER>
7338 <LINE>Ay, marry, is't; crowner's quest law.</LINE>
7339 </SPEECH>
7340
7341 <SPEECH>
7342 <SPEAKER>Second Clown</SPEAKER>
7343 <LINE>Will you ha' the truth on't? If this had not been</LINE>
7344 <LINE>a gentlewoman, she should have been buried out o'</LINE>
7345 <LINE>Christian burial.</LINE>
7346 </SPEECH>
7347
7348 <SPEECH>
7349 <SPEAKER>First Clown</SPEAKER>
7350 <LINE>Why, there thou say'st: and the more pity that</LINE>
7351 <LINE>great folk should have countenance in this world to</LINE>
7352 <LINE>drown or hang themselves, more than their even</LINE>
7353 <LINE>Christian. Come, my spade. There is no ancient</LINE>
7354 <LINE>gentleman but gardeners, ditchers, and grave-makers:</LINE>
7355 <LINE>they hold up Adam's profession.</LINE>
7356 </SPEECH>
7357
7358 <SPEECH>
7359 <SPEAKER>Second Clown</SPEAKER>
7360 <LINE>Was he a gentleman?</LINE>
7361 </SPEECH>
7362
7363 <SPEECH>
7364 <SPEAKER>First Clown</SPEAKER>
7365 <LINE>He was the first that ever bore arms.</LINE>
7366 </SPEECH>
7367
7368 <SPEECH>
7369 <SPEAKER>Second Clown</SPEAKER>
7370 <LINE>Why, he had none.</LINE>
7371 </SPEECH>
7372
7373 <SPEECH>
7374 <SPEAKER>First Clown</SPEAKER>
7375 <LINE>What, art a heathen? How dost thou understand the</LINE>
7376 <LINE>Scripture? The Scripture says 'Adam digged:'</LINE>
7377 <LINE>could he dig without arms? I'll put another</LINE>
7378 <LINE>question to thee: if thou answerest me not to the</LINE>
7379 <LINE>purpose, confess thyself--</LINE>
7380 </SPEECH>
7381
7382 <SPEECH>
7383 <SPEAKER>Second Clown</SPEAKER>
7384 <LINE>Go to.</LINE>
7385 </SPEECH>
7386
7387 <SPEECH>
7388 <SPEAKER>First Clown</SPEAKER>
7389 <LINE>What is he that builds stronger than either the</LINE>
7390 <LINE>mason, the shipwright, or the carpenter?</LINE>
7391 </SPEECH>
7392
7393 <SPEECH>
7394 <SPEAKER>Second Clown</SPEAKER>
7395 <LINE>The gallows-maker; for that frame outlives a</LINE>
7396 <LINE>thousand tenants.</LINE>
7397 </SPEECH>
7398
7399 <SPEECH>
7400 <SPEAKER>First Clown</SPEAKER>
7401 <LINE>I like thy wit well, in good faith: the gallows</LINE>
7402 <LINE>does well; but how does it well? it does well to</LINE>
7403 <LINE>those that do in: now thou dost ill to say the</LINE>
7404 <LINE>gallows is built stronger than the church: argal,</LINE>
7405 <LINE>the gallows may do well to thee. To't again, come.</LINE>
7406 </SPEECH>
7407
7408 <SPEECH>
7409 <SPEAKER>Second Clown</SPEAKER>
7410 <LINE>'Who builds stronger than a mason, a shipwright, or</LINE>
7411 <LINE>a carpenter?'</LINE>
7412 </SPEECH>
7413
7414 <SPEECH>
7415 <SPEAKER>First Clown</SPEAKER>
7416 <LINE>Ay, tell me that, and unyoke.</LINE>
7417 </SPEECH>
7418
7419 <SPEECH>
7420 <SPEAKER>Second Clown</SPEAKER>
7421 <LINE>Marry, now I can tell.</LINE>
7422 </SPEECH>
7423
7424 <SPEECH>
7425 <SPEAKER>First Clown</SPEAKER>
7426 <LINE>To't.</LINE>
7427 </SPEECH>
7428
7429 <SPEECH>
7430 <SPEAKER>Second Clown</SPEAKER>
7431 <LINE>Mass, I cannot tell.</LINE>
7432 </SPEECH>
7433
7434
7435 <STAGEDIR>Enter HAMLET and HORATIO, at a distance</STAGEDIR>
7436
7437 <SPEECH>
7438 <SPEAKER>First Clown</SPEAKER>
7439 <LINE>Cudgel thy brains no more about it, for your dull</LINE>
7440 <LINE>ass will not mend his pace with beating; and, when</LINE>
7441 <LINE>you are asked this question next, say 'a</LINE>
7442 <LINE>grave-maker: 'the houses that he makes last till</LINE>
7443 <LINE>doomsday. Go, get thee to Yaughan: fetch me a</LINE>
7444 <LINE>stoup of liquor.</LINE>
7445 <STAGEDIR>Exit Second Clown</STAGEDIR>
7446 <STAGEDIR>He digs and sings</STAGEDIR>
7447 <LINE>In youth, when I did love, did love,</LINE>
7448 <LINE>Methought it was very sweet,</LINE>
7449 <LINE>To contract, O, the time, for, ah, my behove,</LINE>
7450 <LINE>O, methought, there was nothing meet.</LINE>
7451 </SPEECH>
7452
7453 <SPEECH>
7454 <SPEAKER>HAMLET</SPEAKER>
7455 <LINE>Has this fellow no feeling of his business, that he</LINE>
7456 <LINE>sings at grave-making?</LINE>
7457 </SPEECH>
7458
7459 <SPEECH>
7460 <SPEAKER>HORATIO</SPEAKER>
7461 <LINE>Custom hath made it in him a property of easiness.</LINE>
7462 </SPEECH>
7463
7464 <SPEECH>
7465 <SPEAKER>HAMLET</SPEAKER>
7466 <LINE>'Tis e'en so: the hand of little employment hath</LINE>
7467 <LINE>the daintier sense.</LINE>
7468 </SPEECH>
7469
7470 <SPEECH>
7471 <SPEAKER>First Clown</SPEAKER>
7472 <LINE><STAGEDIR>Sings</STAGEDIR></LINE>
7473 <LINE>But age, with his stealing steps,</LINE>
7474 <LINE>Hath claw'd me in his clutch,</LINE>
7475 <LINE>And hath shipped me intil the land,</LINE>
7476 <LINE>As if I had never been such.</LINE>
7477 </SPEECH>
7478
7479
7480 <STAGEDIR>Throws up a skull</STAGEDIR>
7481
7482 <SPEECH>
7483 <SPEAKER>HAMLET</SPEAKER>
7484 <LINE>That skull had a tongue in it, and could sing once:</LINE>
7485 <LINE>how the knave jowls it to the ground, as if it were</LINE>
7486 <LINE>Cain's jaw-bone, that did the first murder! It</LINE>
7487 <LINE>might be the pate of a politician, which this ass</LINE>
7488 <LINE>now o'er-reaches; one that would circumvent God,</LINE>
7489 <LINE>might it not?</LINE>
7490 </SPEECH>
7491
7492 <SPEECH>
7493 <SPEAKER>HORATIO</SPEAKER>
7494 <LINE>It might, my lord.</LINE>
7495 </SPEECH>
7496
7497 <SPEECH>
7498 <SPEAKER>HAMLET</SPEAKER>
7499 <LINE>Or of a courtier; which could say 'Good morrow,</LINE>
7500 <LINE>sweet lord! How dost thou, good lord?' This might</LINE>
7501 <LINE>be my lord such-a-one, that praised my lord</LINE>
7502 <LINE>such-a-one's horse, when he meant to beg it; might it not?</LINE>
7503 </SPEECH>
7504
7505 <SPEECH>
7506 <SPEAKER>HORATIO</SPEAKER>
7507 <LINE>Ay, my lord.</LINE>
7508 </SPEECH>
7509
7510 <SPEECH>
7511 <SPEAKER>HAMLET</SPEAKER>
7512 <LINE>Why, e'en so: and now my Lady Worm's; chapless, and</LINE>
7513 <LINE>knocked about the mazzard with a sexton's spade:</LINE>
7514 <LINE>here's fine revolution, an we had the trick to</LINE>
7515 <LINE>see't. Did these bones cost no more the breeding,</LINE>
7516 <LINE>but to play at loggats with 'em? mine ache to think on't.</LINE>
7517 </SPEECH>
7518
7519 <SPEECH>
7520 <SPEAKER>First Clown</SPEAKER>
7521 <STAGEDIR>Sings</STAGEDIR>
7522 <LINE>A pick-axe, and a spade, a spade,</LINE>
7523 <LINE>For and a shrouding sheet:</LINE>
7524 <LINE>O, a pit of clay for to be made</LINE>
7525 <LINE>For such a guest is meet.</LINE>
7526 </SPEECH>
7527
7528
7529 <STAGEDIR>Throws up another skull</STAGEDIR>
7530
7531 <SPEECH>
7532 <SPEAKER>HAMLET</SPEAKER>
7533 <LINE>There's another: why may not that be the skull of a</LINE>
7534 <LINE>lawyer? Where be his quiddities now, his quillets,</LINE>
7535 <LINE>his cases, his tenures, and his tricks? why does he</LINE>
7536 <LINE>suffer this rude knave now to knock him about the</LINE>
7537 <LINE>sconce with a dirty shovel, and will not tell him of</LINE>
7538 <LINE>his action of battery? Hum! This fellow might be</LINE>
7539 <LINE>in's time a great buyer of land, with his statutes,</LINE>
7540 <LINE>his recognizances, his fines, his double vouchers,</LINE>
7541 <LINE>his recoveries: is this the fine of his fines, and</LINE>
7542 <LINE>the recovery of his recoveries, to have his fine</LINE>
7543 <LINE>pate full of fine dirt? will his vouchers vouch him</LINE>
7544 <LINE>no more of his purchases, and double ones too, than</LINE>
7545 <LINE>the length and breadth of a pair of indentures? The</LINE>
7546 <LINE>very conveyances of his lands will hardly lie in</LINE>
7547 <LINE>this box; and must the inheritor himself have no more, ha?</LINE>
7548 </SPEECH>
7549
7550 <SPEECH>
7551 <SPEAKER>HORATIO</SPEAKER>
7552 <LINE>Not a jot more, my lord.</LINE>
7553 </SPEECH>
7554
7555 <SPEECH>
7556 <SPEAKER>HAMLET</SPEAKER>
7557 <LINE>Is not parchment made of sheepskins?</LINE>
7558 </SPEECH>
7559
7560 <SPEECH>
7561 <SPEAKER>HORATIO</SPEAKER>
7562 <LINE>Ay, my lord, and of calf-skins too.</LINE>
7563 </SPEECH>
7564
7565 <SPEECH>
7566 <SPEAKER>HAMLET</SPEAKER>
7567 <LINE>They are sheep and calves which seek out assurance</LINE>
7568 <LINE>in that. I will speak to this fellow. Whose</LINE>
7569 <LINE>grave's this, sirrah?</LINE>
7570 </SPEECH>
7571
7572 <SPEECH>
7573 <SPEAKER>First Clown</SPEAKER>
7574 <LINE>Mine, sir.</LINE>
7575 <STAGEDIR>Sings</STAGEDIR>
7576 <LINE>O, a pit of clay for to be made</LINE>
7577 <LINE>For such a guest is meet.</LINE>
7578 </SPEECH>
7579
7580 <SPEECH>
7581 <SPEAKER>HAMLET</SPEAKER>
7582 <LINE>I think it be thine, indeed; for thou liest in't.</LINE>
7583 </SPEECH>
7584
7585 <SPEECH>
7586 <SPEAKER>First Clown</SPEAKER>
7587 <LINE>You lie out on't, sir, and therefore it is not</LINE>
7588 <LINE>yours: for my part, I do not lie in't, and yet it is mine.</LINE>
7589 </SPEECH>
7590
7591 <SPEECH>
7592 <SPEAKER>HAMLET</SPEAKER>
7593 <LINE>'Thou dost lie in't, to be in't and say it is thine:</LINE>
7594 <LINE>'tis for the dead, not for the quick; therefore thou liest.</LINE>
7595 </SPEECH>
7596
7597 <SPEECH>
7598 <SPEAKER>First Clown</SPEAKER>
7599 <LINE>'Tis a quick lie, sir; 'twill away gain, from me to</LINE>
7600 <LINE>you.</LINE>
7601 </SPEECH>
7602
7603 <SPEECH>
7604 <SPEAKER>HAMLET</SPEAKER>
7605 <LINE>What man dost thou dig it for?</LINE>
7606 </SPEECH>
7607
7608 <SPEECH>
7609 <SPEAKER>First Clown</SPEAKER>
7610 <LINE>For no man, sir.</LINE>
7611 </SPEECH>
7612
7613 <SPEECH>
7614 <SPEAKER>HAMLET</SPEAKER>
7615 <LINE>What woman, then?</LINE>
7616 </SPEECH>
7617
7618 <SPEECH>
7619 <SPEAKER>First Clown</SPEAKER>
7620 <LINE>For none, neither.</LINE>
7621 </SPEECH>
7622
7623 <SPEECH>
7624 <SPEAKER>HAMLET</SPEAKER>
7625 <LINE>Who is to be buried in't?</LINE>
7626 </SPEECH>
7627
7628 <SPEECH>
7629 <SPEAKER>First Clown</SPEAKER>
7630 <LINE>One that was a woman, sir; but, rest her soul, she's dead.</LINE>
7631 </SPEECH>
7632
7633 <SPEECH>
7634 <SPEAKER>HAMLET</SPEAKER>
7635 <LINE>How absolute the knave is! we must speak by the</LINE>
7636 <LINE>card, or equivocation will undo us. By the Lord,</LINE>
7637 <LINE>Horatio, these three years I have taken a note of</LINE>
7638 <LINE>it; the age is grown so picked that the toe of the</LINE>
7639 <LINE>peasant comes so near the heel of the courtier, he</LINE>
7640 <LINE>gaffs his kibe. How long hast thou been a</LINE>
7641 <LINE>grave-maker?</LINE>
7642 </SPEECH>
7643
7644 <SPEECH>
7645 <SPEAKER>First Clown</SPEAKER>
7646 <LINE>Of all the days i' the year, I came to't that day</LINE>
7647 <LINE>that our last king Hamlet overcame Fortinbras.</LINE>
7648 </SPEECH>
7649
7650 <SPEECH>
7651 <SPEAKER>HAMLET</SPEAKER>
7652 <LINE>How long is that since?</LINE>
7653 </SPEECH>
7654
7655 <SPEECH>
7656 <SPEAKER>First Clown</SPEAKER>
7657 <LINE>Cannot you tell that? every fool can tell that: it</LINE>
7658 <LINE>was the very day that young Hamlet was born; he that</LINE>
7659 <LINE>is mad, and sent into England.</LINE>
7660 </SPEECH>
7661
7662 <SPEECH>
7663 <SPEAKER>HAMLET</SPEAKER>
7664 <LINE>Ay, marry, why was he sent into England?</LINE>
7665 </SPEECH>
7666
7667 <SPEECH>
7668 <SPEAKER>First Clown</SPEAKER>
7669 <LINE>Why, because he was mad: he shall recover his wits</LINE>
7670 <LINE>there; or, if he do not, it's no great matter there.</LINE>
7671 </SPEECH>
7672
7673 <SPEECH>
7674 <SPEAKER>HAMLET</SPEAKER>
7675 <LINE>Why?</LINE>
7676 </SPEECH>
7677
7678 <SPEECH>
7679 <SPEAKER>First Clown</SPEAKER>
7680 <LINE>'Twill, a not be seen in him there; there the men</LINE>
7681 <LINE>are as mad as he.</LINE>
7682 </SPEECH>
7683
7684 <SPEECH>
7685 <SPEAKER>HAMLET</SPEAKER>
7686 <LINE>How came he mad?</LINE>
7687 </SPEECH>
7688
7689 <SPEECH>
7690 <SPEAKER>First Clown</SPEAKER>
7691 <LINE>Very strangely, they say.</LINE>
7692 </SPEECH>
7693
7694 <SPEECH>
7695 <SPEAKER>HAMLET</SPEAKER>
7696 <LINE>How strangely?</LINE>
7697 </SPEECH>
7698
7699 <SPEECH>
7700 <SPEAKER>First Clown</SPEAKER>
7701 <LINE>Faith, e'en with losing his wits.</LINE>
7702 </SPEECH>
7703
7704 <SPEECH>
7705 <SPEAKER>HAMLET</SPEAKER>
7706 <LINE>Upon what ground?</LINE>
7707 </SPEECH>
7708
7709 <SPEECH>
7710 <SPEAKER>First Clown</SPEAKER>
7711 <LINE>Why, here in Denmark: I have been sexton here, man</LINE>
7712 <LINE>and boy, thirty years.</LINE>
7713 </SPEECH>
7714
7715 <SPEECH>
7716 <SPEAKER>HAMLET</SPEAKER>
7717 <LINE>How long will a man lie i' the earth ere he rot?</LINE>
7718 </SPEECH>
7719
7720 <SPEECH>
7721 <SPEAKER>First Clown</SPEAKER>
7722 <LINE>I' faith, if he be not rotten before he die--as we</LINE>
7723 <LINE>have many pocky corses now-a-days, that will scarce</LINE>
7724 <LINE>hold the laying in--he will last you some eight year</LINE>
7725 <LINE>or nine year: a tanner will last you nine year.</LINE>
7726 </SPEECH>
7727
7728 <SPEECH>
7729 <SPEAKER>HAMLET</SPEAKER>
7730 <LINE>Why he more than another?</LINE>
7731 </SPEECH>
7732
7733 <SPEECH>
7734 <SPEAKER>First Clown</SPEAKER>
7735 <LINE>Why, sir, his hide is so tanned with his trade, that</LINE>
7736 <LINE>he will keep out water a great while; and your water</LINE>
7737 <LINE>is a sore decayer of your whoreson dead body.</LINE>
7738 <LINE>Here's a skull now; this skull has lain in the earth</LINE>
7739 <LINE>three and twenty years.</LINE>
7740 </SPEECH>
7741
7742 <SPEECH>
7743 <SPEAKER>HAMLET</SPEAKER>
7744 <LINE>Whose was it?</LINE>
7745 </SPEECH>
7746
7747 <SPEECH>
7748 <SPEAKER>First Clown</SPEAKER>
7749 <LINE>A whoreson mad fellow's it was: whose do you think it was?</LINE>
7750 </SPEECH>
7751
7752 <SPEECH>
7753 <SPEAKER>HAMLET</SPEAKER>
7754 <LINE>Nay, I know not.</LINE>
7755 </SPEECH>
7756
7757 <SPEECH>
7758 <SPEAKER>First Clown</SPEAKER>
7759 <LINE>A pestilence on him for a mad rogue! a' poured a</LINE>
7760 <LINE>flagon of Rhenish on my head once. This same skull,</LINE>
7761 <LINE>sir, was Yorick's skull, the king's jester.</LINE>
7762 </SPEECH>
7763
7764 <SPEECH>
7765 <SPEAKER>HAMLET</SPEAKER>
7766 <LINE>This?</LINE>
7767 </SPEECH>
7768
7769 <SPEECH>
7770 <SPEAKER>First Clown</SPEAKER>
7771 <LINE>E'en that.</LINE>
7772 </SPEECH>
7773
7774 <SPEECH>
7775 <SPEAKER>HAMLET</SPEAKER>
7776 <LINE>Let me see.</LINE>
7777 <STAGEDIR>Takes the skull</STAGEDIR>
7778 <LINE>Alas, poor Yorick! I knew him, Horatio: a fellow</LINE>
7779 <LINE>of infinite jest, of most excellent fancy: he hath</LINE>
7780 <LINE>borne me on his back a thousand times; and now, how</LINE>
7781 <LINE>abhorred in my imagination it is! my gorge rims at</LINE>
7782 <LINE>it. Here hung those lips that I have kissed I know</LINE>
7783 <LINE>not how oft. Where be your gibes now? your</LINE>
7784 <LINE>gambols? your songs? your flashes of merriment,</LINE>
7785 <LINE>that were wont to set the table on a roar? Not one</LINE>
7786 <LINE>now, to mock your own grinning? quite chap-fallen?</LINE>
7787 <LINE>Now get you to my lady's chamber, and tell her, let</LINE>
7788 <LINE>her paint an inch thick, to this favour she must</LINE>
7789 <LINE>come; make her laugh at that. Prithee, Horatio, tell</LINE>
7790 <LINE>me one thing.</LINE>
7791 </SPEECH>
7792
7793 <SPEECH>
7794 <SPEAKER>HORATIO</SPEAKER>
7795 <LINE>What's that, my lord?</LINE>
7796 </SPEECH>
7797
7798 <SPEECH>
7799 <SPEAKER>HAMLET</SPEAKER>
7800 <LINE>Dost thou think Alexander looked o' this fashion i'</LINE>
7801 <LINE>the earth?</LINE>
7802 </SPEECH>
7803
7804 <SPEECH>
7805 <SPEAKER>HORATIO</SPEAKER>
7806 <LINE>E'en so.</LINE>
7807 </SPEECH>
7808
7809 <SPEECH>
7810 <SPEAKER>HAMLET</SPEAKER>
7811 <LINE>And smelt so? pah!</LINE>
7812 </SPEECH>
7813
7814
7815 <STAGEDIR>Puts down the skull</STAGEDIR>
7816
7817 <SPEECH>
7818 <SPEAKER>HORATIO</SPEAKER>
7819 <LINE>E'en so, my lord.</LINE>
7820 </SPEECH>
7821
7822 <SPEECH>
7823 <SPEAKER>HAMLET</SPEAKER>
7824 <LINE>To what base uses we may return, Horatio! Why may</LINE>
7825 <LINE>not imagination trace the noble dust of Alexander,</LINE>
7826 <LINE>till he find it stopping a bung-hole?</LINE>
7827 </SPEECH>
7828
7829 <SPEECH>
7830 <SPEAKER>HORATIO</SPEAKER>
7831 <LINE>'Twere to consider too curiously, to consider so.</LINE>
7832 </SPEECH>
7833
7834 <SPEECH>
7835 <SPEAKER>HAMLET</SPEAKER>
7836 <LINE>No, faith, not a jot; but to follow him thither with</LINE>
7837 <LINE>modesty enough, and likelihood to lead it: as</LINE>
7838 <LINE>thus: Alexander died, Alexander was buried,</LINE>
7839 <LINE>Alexander returneth into dust; the dust is earth; of</LINE>
7840 <LINE>earth we make loam; and why of that loam, whereto he</LINE>
7841 <LINE>was converted, might they not stop a beer-barrel?</LINE>
7842 <LINE>Imperious Caesar, dead and turn'd to clay,</LINE>
7843 <LINE>Might stop a hole to keep the wind away:</LINE>
7844 <LINE>O, that that earth, which kept the world in awe,</LINE>
7845 <LINE>Should patch a wall to expel the winter flaw!</LINE>
7846 <LINE>But soft! but soft! aside: here comes the king.</LINE>
7847 <STAGEDIR>Enter Priest, &amp;c. in procession; the Corpse of
7848 OPHELIA, LAERTES and Mourners following; KING
7849 CLAUDIUS, QUEEN GERTRUDE, their trains, &amp;c</STAGEDIR>
7850 <LINE>The queen, the courtiers: who is this they follow?</LINE>
7851 <LINE>And with such maimed rites? This doth betoken</LINE>
7852 <LINE>The corse they follow did with desperate hand</LINE>
7853 <LINE>Fordo its own life: 'twas of some estate.</LINE>
7854 <LINE>Couch we awhile, and mark.</LINE>
7855 </SPEECH>
7856
7857
7858 <STAGEDIR>Retiring with HORATIO</STAGEDIR>
7859
7860 <SPEECH>
7861 <SPEAKER>LAERTES</SPEAKER>
7862 <LINE>What ceremony else?</LINE>
7863 </SPEECH>
7864
7865 <SPEECH>
7866 <SPEAKER>HAMLET</SPEAKER>
7867 <LINE>That is Laertes,</LINE>
7868 <LINE>A very noble youth: mark.</LINE>
7869 </SPEECH>
7870
7871 <SPEECH>
7872 <SPEAKER>LAERTES</SPEAKER>
7873 <LINE>What ceremony else?</LINE>
7874 </SPEECH>
7875
7876 <SPEECH>
7877 <SPEAKER>First Priest</SPEAKER>
7878 <LINE>Her obsequies have been as far enlarged</LINE>
7879 <LINE>As we have warrantise: her death was doubtful;</LINE>
7880 <LINE>And, but that great command o'ersways the order,</LINE>
7881 <LINE>She should in ground unsanctified have lodged</LINE>
7882 <LINE>Till the last trumpet: for charitable prayers,</LINE>
7883 <LINE>Shards, flints and pebbles should be thrown on her;</LINE>
7884 <LINE>Yet here she is allow'd her virgin crants,</LINE>
7885 <LINE>Her maiden strewments and the bringing home</LINE>
7886 <LINE>Of bell and burial.</LINE>
7887 </SPEECH>
7888
7889 <SPEECH>
7890 <SPEAKER>LAERTES</SPEAKER>
7891 <LINE>Must there no more be done?</LINE>
7892 </SPEECH>
7893
7894 <SPEECH>
7895 <SPEAKER>First Priest</SPEAKER>
7896 <LINE>No more be done:</LINE>
7897 <LINE>We should profane the service of the dead</LINE>
7898 <LINE>To sing a requiem and such rest to her</LINE>
7899 <LINE>As to peace-parted souls.</LINE>
7900 </SPEECH>
7901
7902 <SPEECH>
7903 <SPEAKER>LAERTES</SPEAKER>
7904 <LINE>Lay her i' the earth:</LINE>
7905 <LINE>And from her fair and unpolluted flesh</LINE>
7906 <LINE>May violets spring! I tell thee, churlish priest,</LINE>
7907 <LINE>A ministering angel shall my sister be,</LINE>
7908 <LINE>When thou liest howling.</LINE>
7909 </SPEECH>
7910
7911 <SPEECH>
7912 <SPEAKER>HAMLET</SPEAKER>
7913 <LINE>What, the fair Ophelia!</LINE>
7914 </SPEECH>
7915
7916 <SPEECH>
7917 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
7918 <LINE>Sweets to the sweet: farewell!</LINE>
7919 <STAGEDIR>Scattering flowers</STAGEDIR>
7920 <LINE>I hoped thou shouldst have been my Hamlet's wife;</LINE>
7921 <LINE>I thought thy bride-bed to have deck'd, sweet maid,</LINE>
7922 <LINE>And not have strew'd thy grave.</LINE>
7923 </SPEECH>
7924
7925 <SPEECH>
7926 <SPEAKER>LAERTES</SPEAKER>
7927 <LINE>O, treble woe</LINE>
7928 <LINE>Fall ten times treble on that cursed head,</LINE>
7929 <LINE>Whose wicked deed thy most ingenious sense</LINE>
7930 <LINE>Deprived thee of! Hold off the earth awhile,</LINE>
7931 <LINE>Till I have caught her once more in mine arms:</LINE>
7932 <STAGEDIR>Leaps into the grave</STAGEDIR>
7933 <LINE>Now pile your dust upon the quick and dead,</LINE>
7934 <LINE>Till of this flat a mountain you have made,</LINE>
7935 <LINE>To o'ertop old Pelion, or the skyish head</LINE>
7936 <LINE>Of blue Olympus.</LINE>
7937 </SPEECH>
7938
7939 <SPEECH>
7940 <SPEAKER>HAMLET</SPEAKER>
7941 <LINE><STAGEDIR>Advancing</STAGEDIR> What is he whose grief</LINE>
7942 <LINE>Bears such an emphasis? whose phrase of sorrow</LINE>
7943 <LINE>Conjures the wandering stars, and makes them stand</LINE>
7944 <LINE>Like wonder-wounded hearers? This is I,</LINE>
7945 <LINE>Hamlet the Dane.</LINE>
7946 </SPEECH>
7947
7948
7949 <STAGEDIR>Leaps into the grave</STAGEDIR>
7950
7951 <SPEECH>
7952 <SPEAKER>LAERTES</SPEAKER>
7953 <LINE>The devil take thy soul!</LINE>
7954 </SPEECH>
7955
7956
7957 <STAGEDIR>Grappling with him</STAGEDIR>
7958
7959 <SPEECH>
7960 <SPEAKER>HAMLET</SPEAKER>
7961 <LINE>Thou pray'st not well.</LINE>
7962 <LINE>I prithee, take thy fingers from my throat;</LINE>
7963 <LINE>For, though I am not splenitive and rash,</LINE>
7964 <LINE>Yet have I something in me dangerous,</LINE>
7965 <LINE>Which let thy wiseness fear: hold off thy hand.</LINE>
7966 </SPEECH>
7967
7968 <SPEECH>
7969 <SPEAKER>KING CLAUDIUS</SPEAKER>
7970 <LINE>Pluck them asunder.</LINE>
7971 </SPEECH>
7972
7973 <SPEECH>
7974 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
7975 <LINE>Hamlet, Hamlet!</LINE>
7976 </SPEECH>
7977
7978 <SPEECH>
7979 <SPEAKER>All</SPEAKER>
7980 <LINE>Gentlemen,--</LINE>
7981 </SPEECH>
7982
7983 <SPEECH>
7984 <SPEAKER>HORATIO</SPEAKER>
7985 <LINE>Good my lord, be quiet.</LINE>
7986 </SPEECH>
7987
7988
7989 <STAGEDIR>The Attendants part them, and they come out of the grave</STAGEDIR>
7990
7991 <SPEECH>
7992 <SPEAKER>HAMLET</SPEAKER>
7993 <LINE>Why I will fight with him upon this theme</LINE>
7994 <LINE>Until my eyelids will no longer wag.</LINE>
7995 </SPEECH>
7996
7997 <SPEECH>
7998 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
7999 <LINE>O my son, what theme?</LINE>
8000 </SPEECH>
8001
8002 <SPEECH>
8003 <SPEAKER>HAMLET</SPEAKER>
8004 <LINE>I loved Ophelia: forty thousand brothers</LINE>
8005 <LINE>Could not, with all their quantity of love,</LINE>
8006 <LINE>Make up my sum. What wilt thou do for her?</LINE>
8007 </SPEECH>
8008
8009 <SPEECH>
8010 <SPEAKER>KING CLAUDIUS</SPEAKER>
8011 <LINE>O, he is mad, Laertes.</LINE>
8012 </SPEECH>
8013
8014 <SPEECH>
8015 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
8016 <LINE>For love of God, forbear him.</LINE>
8017 </SPEECH>
8018
8019 <SPEECH>
8020 <SPEAKER>HAMLET</SPEAKER>
8021 <LINE>'Swounds, show me what thou'lt do:</LINE>
8022 <LINE>Woo't weep? woo't fight? woo't fast? woo't tear thyself?</LINE>
8023 <LINE>Woo't drink up eisel? eat a crocodile?</LINE>
8024 <LINE>I'll do't. Dost thou come here to whine?</LINE>
8025 <LINE>To outface me with leaping in her grave?</LINE>
8026 <LINE>Be buried quick with her, and so will I:</LINE>
8027 <LINE>And, if thou prate of mountains, let them throw</LINE>
8028 <LINE>Millions of acres on us, till our ground,</LINE>
8029 <LINE>Singeing his pate against the burning zone,</LINE>
8030 <LINE>Make Ossa like a wart! Nay, an thou'lt mouth,</LINE>
8031 <LINE>I'll rant as well as thou.</LINE>
8032 </SPEECH>
8033
8034 <SPEECH>
8035 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
8036 <LINE>This is mere madness:</LINE>
8037 <LINE>And thus awhile the fit will work on him;</LINE>
8038 <LINE>Anon, as patient as the female dove,</LINE>
8039 <LINE>When that her golden couplets are disclosed,</LINE>
8040 <LINE>His silence will sit drooping.</LINE>
8041 </SPEECH>
8042
8043 <SPEECH>
8044 <SPEAKER>HAMLET</SPEAKER>
8045 <LINE>Hear you, sir;</LINE>
8046 <LINE>What is the reason that you use me thus?</LINE>
8047 <LINE>I loved you ever: but it is no matter;</LINE>
8048 <LINE>Let Hercules himself do what he may,</LINE>
8049 <LINE>The cat will mew and dog will have his day.</LINE>
8050 </SPEECH>
8051
8052
8053 <STAGEDIR>Exit</STAGEDIR>
8054
8055 <SPEECH>
8056 <SPEAKER>KING CLAUDIUS</SPEAKER>
8057 <LINE>I pray you, good Horatio, wait upon him.</LINE>
8058 <STAGEDIR>Exit HORATIO</STAGEDIR>
8059 <STAGEDIR>To LAERTES</STAGEDIR>
8060 <LINE>Strengthen your patience in our last night's speech;</LINE>
8061 <LINE>We'll put the matter to the present push.</LINE>
8062 <LINE>Good Gertrude, set some watch over your son.</LINE>
8063 <LINE>This grave shall have a living monument:</LINE>
8064 <LINE>An hour of quiet shortly shall we see;</LINE>
8065 <LINE>Till then, in patience our proceeding be.</LINE>
8066 </SPEECH>
8067
8068
8069 <STAGEDIR>Exeunt</STAGEDIR>
8070 </SCENE>
8071
8072 <SCENE><TITLE>SCENE II. A hall in the castle.</TITLE>
8073 <STAGEDIR>Enter HAMLET and HORATIO</STAGEDIR>
8074
8075 <SPEECH>
8076 <SPEAKER>HAMLET</SPEAKER>
8077 <LINE>So much for this, sir: now shall you see the other;</LINE>
8078 <LINE>You do remember all the circumstance?</LINE>
8079 </SPEECH>
8080
8081 <SPEECH>
8082 <SPEAKER>HORATIO</SPEAKER>
8083 <LINE>Remember it, my lord?</LINE>
8084 </SPEECH>
8085
8086 <SPEECH>
8087 <SPEAKER>HAMLET</SPEAKER>
8088 <LINE>Sir, in my heart there was a kind of fighting,</LINE>
8089 <LINE>That would not let me sleep: methought I lay</LINE>
8090 <LINE>Worse than the mutines in the bilboes. Rashly,</LINE>
8091 <LINE>And praised be rashness for it, let us know,</LINE>
8092 <LINE>Our indiscretion sometimes serves us well,</LINE>
8093 <LINE>When our deep plots do pall: and that should teach us</LINE>
8094 <LINE>There's a divinity that shapes our ends,</LINE>
8095 <LINE>Rough-hew them how we will,--</LINE>
8096 </SPEECH>
8097
8098 <SPEECH>
8099 <SPEAKER>HORATIO</SPEAKER>
8100 <LINE>That is most certain.</LINE>
8101 </SPEECH>
8102
8103 <SPEECH>
8104 <SPEAKER>HAMLET</SPEAKER>
8105 <LINE>Up from my cabin,</LINE>
8106 <LINE>My sea-gown scarf'd about me, in the dark</LINE>
8107 <LINE>Groped I to find out them; had my desire.</LINE>
8108 <LINE>Finger'd their packet, and in fine withdrew</LINE>
8109 <LINE>To mine own room again; making so bold,</LINE>
8110 <LINE>My fears forgetting manners, to unseal</LINE>
8111 <LINE>Their grand commission; where I found, Horatio,--</LINE>
8112 <LINE>O royal knavery!--an exact command,</LINE>
8113 <LINE>Larded with many several sorts of reasons</LINE>
8114 <LINE>Importing Denmark's health and England's too,</LINE>
8115 <LINE>With, ho! such bugs and goblins in my life,</LINE>
8116 <LINE>That, on the supervise, no leisure bated,</LINE>
8117 <LINE>No, not to stay the grinding of the axe,</LINE>
8118 <LINE>My head should be struck off.</LINE>
8119 </SPEECH>
8120
8121 <SPEECH>
8122 <SPEAKER>HORATIO</SPEAKER>
8123 <LINE>Is't possible?</LINE>
8124 </SPEECH>
8125
8126 <SPEECH>
8127 <SPEAKER>HAMLET</SPEAKER>
8128 <LINE>Here's the commission: read it at more leisure.</LINE>
8129 <LINE>But wilt thou hear me how I did proceed?</LINE>
8130 </SPEECH>
8131
8132 <SPEECH>
8133 <SPEAKER>HORATIO</SPEAKER>
8134 <LINE>I beseech you.</LINE>
8135 </SPEECH>
8136
8137 <SPEECH>
8138 <SPEAKER>HAMLET</SPEAKER>
8139 <LINE>Being thus be-netted round with villanies,--</LINE>
8140 <LINE>Ere I could make a prologue to my brains,</LINE>
8141 <LINE>They had begun the play--I sat me down,</LINE>
8142 <LINE>Devised a new commission, wrote it fair:</LINE>
8143 <LINE>I once did hold it, as our statists do,</LINE>
8144 <LINE>A baseness to write fair and labour'd much</LINE>
8145 <LINE>How to forget that learning, but, sir, now</LINE>
8146 <LINE>It did me yeoman's service: wilt thou know</LINE>
8147 <LINE>The effect of what I wrote?</LINE>
8148 </SPEECH>
8149
8150 <SPEECH>
8151 <SPEAKER>HORATIO</SPEAKER>
8152 <LINE>Ay, good my lord.</LINE>
8153 </SPEECH>
8154
8155 <SPEECH>
8156 <SPEAKER>HAMLET</SPEAKER>
8157 <LINE>An earnest conjuration from the king,</LINE>
8158 <LINE>As England was his faithful tributary,</LINE>
8159 <LINE>As love between them like the palm might flourish,</LINE>
8160 <LINE>As peace should stiff her wheaten garland wear</LINE>
8161 <LINE>And stand a comma 'tween their amities,</LINE>
8162 <LINE>And many such-like 'As'es of great charge,</LINE>
8163 <LINE>That, on the view and knowing of these contents,</LINE>
8164 <LINE>Without debatement further, more or less,</LINE>
8165 <LINE>He should the bearers put to sudden death,</LINE>
8166 <LINE>Not shriving-time allow'd.</LINE>
8167 </SPEECH>
8168
8169 <SPEECH>
8170 <SPEAKER>HORATIO</SPEAKER>
8171 <LINE>How was this seal'd?</LINE>
8172 </SPEECH>
8173
8174 <SPEECH>
8175 <SPEAKER>HAMLET</SPEAKER>
8176 <LINE>Why, even in that was heaven ordinant.</LINE>
8177 <LINE>I had my father's signet in my purse,</LINE>
8178 <LINE>Which was the model of that Danish seal;</LINE>
8179 <LINE>Folded the writ up in form of the other,</LINE>
8180 <LINE>Subscribed it, gave't the impression, placed it safely,</LINE>
8181 <LINE>The changeling never known. Now, the next day</LINE>
8182 <LINE>Was our sea-fight; and what to this was sequent</LINE>
8183 <LINE>Thou know'st already.</LINE>
8184 </SPEECH>
8185
8186 <SPEECH>
8187 <SPEAKER>HORATIO</SPEAKER>
8188 <LINE>So Guildenstern and Rosencrantz go to't.</LINE>
8189 </SPEECH>
8190
8191 <SPEECH>
8192 <SPEAKER>HAMLET</SPEAKER>
8193 <LINE>Why, man, they did make love to this employment;</LINE>
8194 <LINE>They are not near my conscience; their defeat</LINE>
8195 <LINE>Does by their own insinuation grow:</LINE>
8196 <LINE>'Tis dangerous when the baser nature comes</LINE>
8197 <LINE>Between the pass and fell incensed points</LINE>
8198 <LINE>Of mighty opposites.</LINE>
8199 </SPEECH>
8200
8201 <SPEECH>
8202 <SPEAKER>HORATIO</SPEAKER>
8203 <LINE>Why, what a king is this!</LINE>
8204 </SPEECH>
8205
8206 <SPEECH>
8207 <SPEAKER>HAMLET</SPEAKER>
8208 <LINE>Does it not, think'st thee, stand me now upon--</LINE>
8209 <LINE>He that hath kill'd my king and whored my mother,</LINE>
8210 <LINE>Popp'd in between the election and my hopes,</LINE>
8211 <LINE>Thrown out his angle for my proper life,</LINE>
8212 <LINE>And with such cozenage--is't not perfect conscience,</LINE>
8213 <LINE>To quit him with this arm? and is't not to be damn'd,</LINE>
8214 <LINE>To let this canker of our nature come</LINE>
8215 <LINE>In further evil?</LINE>
8216 </SPEECH>
8217
8218 <SPEECH>
8219 <SPEAKER>HORATIO</SPEAKER>
8220 <LINE>It must be shortly known to him from England</LINE>
8221 <LINE>What is the issue of the business there.</LINE>
8222 </SPEECH>
8223
8224 <SPEECH>
8225 <SPEAKER>HAMLET</SPEAKER>
8226 <LINE>It will be short: the interim is mine;</LINE>
8227 <LINE>And a man's life's no more than to say 'One.'</LINE>
8228 <LINE>But I am very sorry, good Horatio,</LINE>
8229 <LINE>That to Laertes I forgot myself;</LINE>
8230 <LINE>For, by the image of my cause, I see</LINE>
8231 <LINE>The portraiture of his: I'll court his favours.</LINE>
8232 <LINE>But, sure, the bravery of his grief did put me</LINE>
8233 <LINE>Into a towering passion.</LINE>
8234 </SPEECH>
8235
8236 <SPEECH>
8237 <SPEAKER>HORATIO</SPEAKER>
8238 <LINE>Peace! who comes here?</LINE>
8239 </SPEECH>
8240
8241
8242 <STAGEDIR>Enter OSRIC</STAGEDIR>
8243
8244 <SPEECH>
8245 <SPEAKER>OSRIC</SPEAKER>
8246 <LINE>Your lordship is right welcome back to Denmark.</LINE>
8247 </SPEECH>
8248
8249 <SPEECH>
8250 <SPEAKER>HAMLET</SPEAKER>
8251 <LINE>I humbly thank you, sir. Dost know this water-fly?</LINE>
8252 </SPEECH>
8253
8254 <SPEECH>
8255 <SPEAKER>HORATIO</SPEAKER>
8256 <LINE>No, my good lord.</LINE>
8257 </SPEECH>
8258
8259 <SPEECH>
8260 <SPEAKER>HAMLET</SPEAKER>
8261 <LINE>Thy state is the more gracious; for 'tis a vice to</LINE>
8262 <LINE>know him. He hath much land, and fertile: let a</LINE>
8263 <LINE>beast be lord of beasts, and his crib shall stand at</LINE>
8264 <LINE>the king's mess: 'tis a chough; but, as I say,</LINE>
8265 <LINE>spacious in the possession of dirt.</LINE>
8266 </SPEECH>
8267
8268 <SPEECH>
8269 <SPEAKER>OSRIC</SPEAKER>
8270 <LINE>Sweet lord, if your lordship were at leisure, I</LINE>
8271 <LINE>should impart a thing to you from his majesty.</LINE>
8272 </SPEECH>
8273
8274 <SPEECH>
8275 <SPEAKER>HAMLET</SPEAKER>
8276 <LINE>I will receive it, sir, with all diligence of</LINE>
8277 <LINE>spirit. Put your bonnet to his right use; 'tis for the head.</LINE>
8278 </SPEECH>
8279
8280 <SPEECH>
8281 <SPEAKER>OSRIC</SPEAKER>
8282 <LINE>I thank your lordship, it is very hot.</LINE>
8283 </SPEECH>
8284
8285 <SPEECH>
8286 <SPEAKER>HAMLET</SPEAKER>
8287 <LINE>No, believe me, 'tis very cold; the wind is</LINE>
8288 <LINE>northerly.</LINE>
8289 </SPEECH>
8290
8291 <SPEECH>
8292 <SPEAKER>OSRIC</SPEAKER>
8293 <LINE>It is indifferent cold, my lord, indeed.</LINE>
8294 </SPEECH>
8295
8296 <SPEECH>
8297 <SPEAKER>HAMLET</SPEAKER>
8298 <LINE>But yet methinks it is very sultry and hot for my</LINE>
8299 <LINE>complexion.</LINE>
8300 </SPEECH>
8301
8302 <SPEECH>
8303 <SPEAKER>OSRIC</SPEAKER>
8304 <LINE>Exceedingly, my lord; it is very sultry,--as</LINE>
8305 <LINE>'twere,--I cannot tell how. But, my lord, his</LINE>
8306 <LINE>majesty bade me signify to you that he has laid a</LINE>
8307 <LINE>great wager on your head: sir, this is the matter,--</LINE>
8308 </SPEECH>
8309
8310 <SPEECH>
8311 <SPEAKER>HAMLET</SPEAKER>
8312 <LINE>I beseech you, remember--</LINE>
8313 </SPEECH>
8314
8315
8316 <STAGEDIR>HAMLET moves him to put on his hat</STAGEDIR>
8317
8318 <SPEECH>
8319 <SPEAKER>OSRIC</SPEAKER>
8320 <LINE>Nay, good my lord; for mine ease, in good faith.</LINE>
8321 <LINE>Sir, here is newly come to court Laertes; believe</LINE>
8322 <LINE>me, an absolute gentleman, full of most excellent</LINE>
8323 <LINE>differences, of very soft society and great showing:</LINE>
8324 <LINE>indeed, to speak feelingly of him, he is the card or</LINE>
8325 <LINE>calendar of gentry, for you shall find in him the</LINE>
8326 <LINE>continent of what part a gentleman would see.</LINE>
8327 </SPEECH>
8328
8329 <SPEECH>
8330 <SPEAKER>HAMLET</SPEAKER>
8331 <LINE>Sir, his definement suffers no perdition in you;</LINE>
8332 <LINE>though, I know, to divide him inventorially would</LINE>
8333 <LINE>dizzy the arithmetic of memory, and yet but yaw</LINE>
8334 <LINE>neither, in respect of his quick sail. But, in the</LINE>
8335 <LINE>verity of extolment, I take him to be a soul of</LINE>
8336 <LINE>great article; and his infusion of such dearth and</LINE>
8337 <LINE>rareness, as, to make true diction of him, his</LINE>
8338 <LINE>semblable is his mirror; and who else would trace</LINE>
8339 <LINE>him, his umbrage, nothing more.</LINE>
8340 </SPEECH>
8341
8342 <SPEECH>
8343 <SPEAKER>OSRIC</SPEAKER>
8344 <LINE>Your lordship speaks most infallibly of him.</LINE>
8345 </SPEECH>
8346
8347 <SPEECH>
8348 <SPEAKER>HAMLET</SPEAKER>
8349 <LINE>The concernancy, sir? why do we wrap the gentleman</LINE>
8350 <LINE>in our more rawer breath?</LINE>
8351 </SPEECH>
8352
8353 <SPEECH>
8354 <SPEAKER>OSRIC</SPEAKER>
8355 <LINE>Sir?</LINE>
8356 </SPEECH>
8357
8358 <SPEECH>
8359 <SPEAKER>HORATIO</SPEAKER>
8360 <LINE>Is't not possible to understand in another tongue?</LINE>
8361 <LINE>You will do't, sir, really.</LINE>
8362 </SPEECH>
8363
8364 <SPEECH>
8365 <SPEAKER>HAMLET</SPEAKER>
8366 <LINE>What imports the nomination of this gentleman?</LINE>
8367 </SPEECH>
8368
8369 <SPEECH>
8370 <SPEAKER>OSRIC</SPEAKER>
8371 <LINE>Of Laertes?</LINE>
8372 </SPEECH>
8373
8374 <SPEECH>
8375 <SPEAKER>HORATIO</SPEAKER>
8376 <LINE>His purse is empty already; all's golden words are spent.</LINE>
8377 </SPEECH>
8378
8379 <SPEECH>
8380 <SPEAKER>HAMLET</SPEAKER>
8381 <LINE>Of him, sir.</LINE>
8382 </SPEECH>
8383
8384 <SPEECH>
8385 <SPEAKER>OSRIC</SPEAKER>
8386 <LINE>I know you are not ignorant--</LINE>
8387 </SPEECH>
8388
8389 <SPEECH>
8390 <SPEAKER>HAMLET</SPEAKER>
8391 <LINE>I would you did, sir; yet, in faith, if you did,</LINE>
8392 <LINE>it would not much approve me. Well, sir?</LINE>
8393 </SPEECH>
8394
8395 <SPEECH>
8396 <SPEAKER>OSRIC</SPEAKER>
8397 <LINE>You are not ignorant of what excellence Laertes is--</LINE>
8398 </SPEECH>
8399
8400 <SPEECH>
8401 <SPEAKER>HAMLET</SPEAKER>
8402 <LINE>I dare not confess that, lest I should compare with</LINE>
8403 <LINE>him in excellence; but, to know a man well, were to</LINE>
8404 <LINE>know himself.</LINE>
8405 </SPEECH>
8406
8407 <SPEECH>
8408 <SPEAKER>OSRIC</SPEAKER>
8409 <LINE>I mean, sir, for his weapon; but in the imputation</LINE>
8410 <LINE>laid on him by them, in his meed he's unfellowed.</LINE>
8411 </SPEECH>
8412
8413 <SPEECH>
8414 <SPEAKER>HAMLET</SPEAKER>
8415 <LINE>What's his weapon?</LINE>
8416 </SPEECH>
8417
8418 <SPEECH>
8419 <SPEAKER>OSRIC</SPEAKER>
8420 <LINE>Rapier and dagger.</LINE>
8421 </SPEECH>
8422
8423 <SPEECH>
8424 <SPEAKER>HAMLET</SPEAKER>
8425 <LINE>That's two of his weapons: but, well.</LINE>
8426 </SPEECH>
8427
8428 <SPEECH>
8429 <SPEAKER>OSRIC</SPEAKER>
8430 <LINE>The king, sir, hath wagered with him six Barbary</LINE>
8431 <LINE>horses: against the which he has imponed, as I take</LINE>
8432 <LINE>it, six French rapiers and poniards, with their</LINE>
8433 <LINE>assigns, as girdle, hangers, and so: three of the</LINE>
8434 <LINE>carriages, in faith, are very dear to fancy, very</LINE>
8435 <LINE>responsive to the hilts, most delicate carriages,</LINE>
8436 <LINE>and of very liberal conceit.</LINE>
8437 </SPEECH>
8438
8439 <SPEECH>
8440 <SPEAKER>HAMLET</SPEAKER>
8441 <LINE>What call you the carriages?</LINE>
8442 </SPEECH>
8443
8444 <SPEECH>
8445 <SPEAKER>HORATIO</SPEAKER>
8446 <LINE>I knew you must be edified by the margent ere you had done.</LINE>
8447 </SPEECH>
8448
8449 <SPEECH>
8450 <SPEAKER>OSRIC</SPEAKER>
8451 <LINE>The carriages, sir, are the hangers.</LINE>
8452 </SPEECH>
8453
8454 <SPEECH>
8455 <SPEAKER>HAMLET</SPEAKER>
8456 <LINE>The phrase would be more german to the matter, if we</LINE>
8457 <LINE>could carry cannon by our sides: I would it might</LINE>
8458 <LINE>be hangers till then. But, on: six Barbary horses</LINE>
8459 <LINE>against six French swords, their assigns, and three</LINE>
8460 <LINE>liberal-conceited carriages; that's the French bet</LINE>
8461 <LINE>against the Danish. Why is this 'imponed,' as you call it?</LINE>
8462 </SPEECH>
8463
8464 <SPEECH>
8465 <SPEAKER>OSRIC</SPEAKER>
8466 <LINE>The king, sir, hath laid, that in a dozen passes</LINE>
8467 <LINE>between yourself and him, he shall not exceed you</LINE>
8468 <LINE>three hits: he hath laid on twelve for nine; and it</LINE>
8469 <LINE>would come to immediate trial, if your lordship</LINE>
8470 <LINE>would vouchsafe the answer.</LINE>
8471 </SPEECH>
8472
8473 <SPEECH>
8474 <SPEAKER>HAMLET</SPEAKER>
8475 <LINE>How if I answer 'no'?</LINE>
8476 </SPEECH>
8477
8478 <SPEECH>
8479 <SPEAKER>OSRIC</SPEAKER>
8480 <LINE>I mean, my lord, the opposition of your person in trial.</LINE>
8481 </SPEECH>
8482
8483 <SPEECH>
8484 <SPEAKER>HAMLET</SPEAKER>
8485 <LINE>Sir, I will walk here in the hall: if it please his</LINE>
8486 <LINE>majesty, 'tis the breathing time of day with me; let</LINE>
8487 <LINE>the foils be brought, the gentleman willing, and the</LINE>
8488 <LINE>king hold his purpose, I will win for him an I can;</LINE>
8489 <LINE>if not, I will gain nothing but my shame and the odd hits.</LINE>
8490 </SPEECH>
8491
8492 <SPEECH>
8493 <SPEAKER>OSRIC</SPEAKER>
8494 <LINE>Shall I re-deliver you e'en so?</LINE>
8495 </SPEECH>
8496
8497 <SPEECH>
8498 <SPEAKER>HAMLET</SPEAKER>
8499 <LINE>To this effect, sir; after what flourish your nature will.</LINE>
8500 </SPEECH>
8501
8502 <SPEECH>
8503 <SPEAKER>OSRIC</SPEAKER>
8504 <LINE>I commend my duty to your lordship.</LINE>
8505 </SPEECH>
8506
8507 <SPEECH>
8508 <SPEAKER>HAMLET</SPEAKER>
8509 <LINE>Yours, yours.</LINE>
8510 <STAGEDIR>Exit OSRIC</STAGEDIR>
8511 <LINE>He does well to commend it himself; there are no</LINE>
8512 <LINE>tongues else for's turn.</LINE>
8513 </SPEECH>
8514
8515 <SPEECH>
8516 <SPEAKER>HORATIO</SPEAKER>
8517 <LINE>This lapwing runs away with the shell on his head.</LINE>
8518 </SPEECH>
8519
8520 <SPEECH>
8521 <SPEAKER>HAMLET</SPEAKER>
8522 <LINE>He did comply with his dug, before he sucked it.</LINE>
8523 <LINE>Thus has he--and many more of the same bevy that I</LINE>
8524 <LINE>know the dressy age dotes on--only got the tune of</LINE>
8525 <LINE>the time and outward habit of encounter; a kind of</LINE>
8526 <LINE>yesty collection, which carries them through and</LINE>
8527 <LINE>through the most fond and winnowed opinions; and do</LINE>
8528 <LINE>but blow them to their trial, the bubbles are out.</LINE>
8529 </SPEECH>
8530
8531
8532 <STAGEDIR>Enter a Lord</STAGEDIR>
8533
8534 <SPEECH>
8535 <SPEAKER>Lord</SPEAKER>
8536 <LINE>My lord, his majesty commended him to you by young</LINE>
8537 <LINE>Osric, who brings back to him that you attend him in</LINE>
8538 <LINE>the hall: he sends to know if your pleasure hold to</LINE>
8539 <LINE>play with Laertes, or that you will take longer time.</LINE>
8540 </SPEECH>
8541
8542 <SPEECH>
8543 <SPEAKER>HAMLET</SPEAKER>
8544 <LINE>I am constant to my purpose; they follow the king's</LINE>
8545 <LINE>pleasure: if his fitness speaks, mine is ready; now</LINE>
8546 <LINE>or whensoever, provided I be so able as now.</LINE>
8547 </SPEECH>
8548
8549 <SPEECH>
8550 <SPEAKER>Lord</SPEAKER>
8551 <LINE>The king and queen and all are coming down.</LINE>
8552 </SPEECH>
8553
8554 <SPEECH>
8555 <SPEAKER>HAMLET</SPEAKER>
8556 <LINE>In happy time.</LINE>
8557 </SPEECH>
8558
8559 <SPEECH>
8560 <SPEAKER>Lord</SPEAKER>
8561 <LINE>The queen desires you to use some gentle</LINE>
8562 <LINE>entertainment to Laertes before you fall to play.</LINE>
8563 </SPEECH>
8564
8565 <SPEECH>
8566 <SPEAKER>HAMLET</SPEAKER>
8567 <LINE>She well instructs me.</LINE>
8568 </SPEECH>
8569
8570
8571 <STAGEDIR>Exit Lord</STAGEDIR>
8572
8573 <SPEECH>
8574 <SPEAKER>HORATIO</SPEAKER>
8575 <LINE>You will lose this wager, my lord.</LINE>
8576 </SPEECH>
8577
8578 <SPEECH>
8579 <SPEAKER>HAMLET</SPEAKER>
8580 <LINE>I do not think so: since he went into France, I</LINE>
8581 <LINE>have been in continual practise: I shall win at the</LINE>
8582 <LINE>odds. But thou wouldst not think how ill all's here</LINE>
8583 <LINE>about my heart: but it is no matter.</LINE>
8584 </SPEECH>
8585
8586 <SPEECH>
8587 <SPEAKER>HORATIO</SPEAKER>
8588 <LINE>Nay, good my lord,--</LINE>
8589 </SPEECH>
8590
8591 <SPEECH>
8592 <SPEAKER>HAMLET</SPEAKER>
8593 <LINE>It is but foolery; but it is such a kind of</LINE>
8594 <LINE>gain-giving, as would perhaps trouble a woman.</LINE>
8595 </SPEECH>
8596
8597 <SPEECH>
8598 <SPEAKER>HORATIO</SPEAKER>
8599 <LINE>If your mind dislike any thing, obey it: I will</LINE>
8600 <LINE>forestall their repair hither, and say you are not</LINE>
8601 <LINE>fit.</LINE>
8602 </SPEECH>
8603
8604 <SPEECH>
8605 <SPEAKER>HAMLET</SPEAKER>
8606 <LINE>Not a whit, we defy augury: there's a special</LINE>
8607 <LINE>providence in the fall of a sparrow. If it be now,</LINE>
8608 <LINE>'tis not to come; if it be not to come, it will be</LINE>
8609 <LINE>now; if it be not now, yet it will come: the</LINE>
8610 <LINE>readiness is all: since no man has aught of what he</LINE>
8611 <LINE>leaves, what is't to leave betimes?</LINE>
8612 </SPEECH>
8613
8614
8615 <STAGEDIR>Enter KING CLAUDIUS, QUEEN GERTRUDE, LAERTES,
8616 Lords, OSRIC, and Attendants with foils, &amp;c</STAGEDIR>
8617
8618 <SPEECH>
8619 <SPEAKER>KING CLAUDIUS</SPEAKER>
8620 <LINE>Come, Hamlet, come, and take this hand from me.</LINE>
8621 </SPEECH>
8622
8623
8624 <STAGEDIR>KING CLAUDIUS puts LAERTES' hand into HAMLET's</STAGEDIR>
8625
8626 <SPEECH>
8627 <SPEAKER>HAMLET</SPEAKER>
8628 <LINE>Give me your pardon, sir: I've done you wrong;</LINE>
8629 <LINE>But pardon't, as you are a gentleman.</LINE>
8630 <LINE>This presence knows,</LINE>
8631 <LINE>And you must needs have heard, how I am punish'd</LINE>
8632 <LINE>With sore distraction. What I have done,</LINE>
8633 <LINE>That might your nature, honour and exception</LINE>
8634 <LINE>Roughly awake, I here proclaim was madness.</LINE>
8635 <LINE>Was't Hamlet wrong'd Laertes? Never Hamlet:</LINE>
8636 <LINE>If Hamlet from himself be ta'en away,</LINE>
8637 <LINE>And when he's not himself does wrong Laertes,</LINE>
8638 <LINE>Then Hamlet does it not, Hamlet denies it.</LINE>
8639 <LINE>Who does it, then? His madness: if't be so,</LINE>
8640 <LINE>Hamlet is of the faction that is wrong'd;</LINE>
8641 <LINE>His madness is poor Hamlet's enemy.</LINE>
8642 <LINE>Sir, in this audience,</LINE>
8643 <LINE>Let my disclaiming from a purposed evil</LINE>
8644 <LINE>Free me so far in your most generous thoughts,</LINE>
8645 <LINE>That I have shot mine arrow o'er the house,</LINE>
8646 <LINE>And hurt my brother.</LINE>
8647 </SPEECH>
8648
8649 <SPEECH>
8650 <SPEAKER>LAERTES</SPEAKER>
8651 <LINE>I am satisfied in nature,</LINE>
8652 <LINE>Whose motive, in this case, should stir me most</LINE>
8653 <LINE>To my revenge: but in my terms of honour</LINE>
8654 <LINE>I stand aloof; and will no reconcilement,</LINE>
8655 <LINE>Till by some elder masters, of known honour,</LINE>
8656 <LINE>I have a voice and precedent of peace,</LINE>
8657 <LINE>To keep my name ungored. But till that time,</LINE>
8658 <LINE>I do receive your offer'd love like love,</LINE>
8659 <LINE>And will not wrong it.</LINE>
8660 </SPEECH>
8661
8662 <SPEECH>
8663 <SPEAKER>HAMLET</SPEAKER>
8664 <LINE>I embrace it freely;</LINE>
8665 <LINE>And will this brother's wager frankly play.</LINE>
8666 <LINE>Give us the foils. Come on.</LINE>
8667 </SPEECH>
8668
8669 <SPEECH>
8670 <SPEAKER>LAERTES</SPEAKER>
8671 <LINE>Come, one for me.</LINE>
8672 </SPEECH>
8673
8674 <SPEECH>
8675 <SPEAKER>HAMLET</SPEAKER>
8676 <LINE>I'll be your foil, Laertes: in mine ignorance</LINE>
8677 <LINE>Your skill shall, like a star i' the darkest night,</LINE>
8678 <LINE>Stick fiery off indeed.</LINE>
8679 </SPEECH>
8680
8681 <SPEECH>
8682 <SPEAKER>LAERTES</SPEAKER>
8683 <LINE>You mock me, sir.</LINE>
8684 </SPEECH>
8685
8686 <SPEECH>
8687 <SPEAKER>HAMLET</SPEAKER>
8688 <LINE>No, by this hand.</LINE>
8689 </SPEECH>
8690
8691 <SPEECH>
8692 <SPEAKER>KING CLAUDIUS</SPEAKER>
8693 <LINE>Give them the foils, young Osric. Cousin Hamlet,</LINE>
8694 <LINE>You know the wager?</LINE>
8695 </SPEECH>
8696
8697 <SPEECH>
8698 <SPEAKER>HAMLET</SPEAKER>
8699 <LINE>Very well, my lord</LINE>
8700 <LINE>Your grace hath laid the odds o' the weaker side.</LINE>
8701 </SPEECH>
8702
8703 <SPEECH>
8704 <SPEAKER>KING CLAUDIUS</SPEAKER>
8705 <LINE>I do not fear it; I have seen you both:</LINE>
8706 <LINE>But since he is better'd, we have therefore odds.</LINE>
8707 </SPEECH>
8708
8709 <SPEECH>
8710 <SPEAKER>LAERTES</SPEAKER>
8711 <LINE>This is too heavy, let me see another.</LINE>
8712 </SPEECH>
8713
8714 <SPEECH>
8715 <SPEAKER>HAMLET</SPEAKER>
8716 <LINE>This likes me well. These foils have all a length?</LINE>
8717 </SPEECH>
8718
8719
8720 <STAGEDIR>They prepare to play</STAGEDIR>
8721
8722 <SPEECH>
8723 <SPEAKER>OSRIC</SPEAKER>
8724 <LINE>Ay, my good lord.</LINE>
8725 </SPEECH>
8726
8727 <SPEECH>
8728 <SPEAKER>KING CLAUDIUS</SPEAKER>
8729 <LINE>Set me the stoops of wine upon that table.</LINE>
8730 <LINE>If Hamlet give the first or second hit,</LINE>
8731 <LINE>Or quit in answer of the third exchange,</LINE>
8732 <LINE>Let all the battlements their ordnance fire:</LINE>
8733 <LINE>The king shall drink to Hamlet's better breath;</LINE>
8734 <LINE>And in the cup an union shall he throw,</LINE>
8735 <LINE>Richer than that which four successive kings</LINE>
8736 <LINE>In Denmark's crown have worn. Give me the cups;</LINE>
8737 <LINE>And let the kettle to the trumpet speak,</LINE>
8738 <LINE>The trumpet to the cannoneer without,</LINE>
8739 <LINE>The cannons to the heavens, the heavens to earth,</LINE>
8740 <LINE>'Now the king dunks to Hamlet.' Come, begin:</LINE>
8741 <LINE>And you, the judges, bear a wary eye.</LINE>
8742 </SPEECH>
8743
8744 <SPEECH>
8745 <SPEAKER>HAMLET</SPEAKER>
8746 <LINE>Come on, sir.</LINE>
8747 </SPEECH>
8748
8749 <SPEECH>
8750 <SPEAKER>LAERTES</SPEAKER>
8751 <LINE>Come, my lord.</LINE>
8752 </SPEECH>
8753
8754
8755 <STAGEDIR>They play</STAGEDIR>
8756
8757 <SPEECH>
8758 <SPEAKER>HAMLET</SPEAKER>
8759 <LINE>One.</LINE>
8760 </SPEECH>
8761
8762 <SPEECH>
8763 <SPEAKER>LAERTES</SPEAKER>
8764 <LINE>No.</LINE>
8765 </SPEECH>
8766
8767 <SPEECH>
8768 <SPEAKER>HAMLET</SPEAKER>
8769 <LINE>Judgment.</LINE>
8770 </SPEECH>
8771
8772 <SPEECH>
8773 <SPEAKER>OSRIC</SPEAKER>
8774 <LINE>A hit, a very palpable hit.</LINE>
8775 </SPEECH>
8776
8777 <SPEECH>
8778 <SPEAKER>LAERTES</SPEAKER>
8779 <LINE>Well; again.</LINE>
8780 </SPEECH>
8781
8782 <SPEECH>
8783 <SPEAKER>KING CLAUDIUS</SPEAKER>
8784 <LINE>Stay; give me drink. Hamlet, this pearl is thine;</LINE>
8785 <LINE>Here's to thy health.</LINE>
8786 <STAGEDIR>Trumpets sound, and cannon shot off within</STAGEDIR>
8787 <LINE>Give him the cup.</LINE>
8788 </SPEECH>
8789
8790 <SPEECH>
8791 <SPEAKER>HAMLET</SPEAKER>
8792 <LINE>I'll play this bout first; set it by awhile. Come.</LINE>
8793 <STAGEDIR>They play</STAGEDIR>
8794 <LINE>Another hit; what say you?</LINE>
8795 </SPEECH>
8796
8797 <SPEECH>
8798 <SPEAKER>LAERTES</SPEAKER>
8799 <LINE>A touch, a touch, I do confess.</LINE>
8800 </SPEECH>
8801
8802 <SPEECH>
8803 <SPEAKER>KING CLAUDIUS</SPEAKER>
8804 <LINE>Our son shall win.</LINE>
8805 </SPEECH>
8806
8807 <SPEECH>
8808 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
8809 <LINE>He's fat, and scant of breath.</LINE>
8810 <LINE>Here, Hamlet, take my napkin, rub thy brows;</LINE>
8811 <LINE>The queen carouses to thy fortune, Hamlet.</LINE>
8812 </SPEECH>
8813
8814 <SPEECH>
8815 <SPEAKER>HAMLET</SPEAKER>
8816 <LINE>Good madam!</LINE>
8817 </SPEECH>
8818
8819 <SPEECH>
8820 <SPEAKER>KING CLAUDIUS</SPEAKER>
8821 <LINE>Gertrude, do not drink.</LINE>
8822 </SPEECH>
8823
8824 <SPEECH>
8825 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
8826 <LINE>I will, my lord; I pray you, pardon me.</LINE>
8827 </SPEECH>
8828
8829 <SPEECH>
8830 <SPEAKER>KING CLAUDIUS</SPEAKER>
8831 <LINE><STAGEDIR>Aside</STAGEDIR> It is the poison'd cup: it is too late.</LINE>
8832 </SPEECH>
8833
8834 <SPEECH>
8835 <SPEAKER>HAMLET</SPEAKER>
8836 <LINE>I dare not drink yet, madam; by and by.</LINE>
8837 </SPEECH>
8838
8839 <SPEECH>
8840 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
8841 <LINE>Come, let me wipe thy face.</LINE>
8842 </SPEECH>
8843
8844 <SPEECH>
8845 <SPEAKER>LAERTES</SPEAKER>
8846 <LINE>My lord, I'll hit him now.</LINE>
8847 </SPEECH>
8848
8849 <SPEECH>
8850 <SPEAKER>KING CLAUDIUS</SPEAKER>
8851 <LINE>I do not think't.</LINE>
8852 </SPEECH>
8853
8854 <SPEECH>
8855 <SPEAKER>LAERTES</SPEAKER>
8856 <LINE><STAGEDIR>Aside</STAGEDIR> And yet 'tis almost 'gainst my conscience.</LINE>
8857 </SPEECH>
8858
8859 <SPEECH>
8860 <SPEAKER>HAMLET</SPEAKER>
8861 <LINE>Come, for the third, Laertes: you but dally;</LINE>
8862 <LINE>I pray you, pass with your best violence;</LINE>
8863 <LINE>I am afeard you make a wanton of me.</LINE>
8864 </SPEECH>
8865
8866 <SPEECH>
8867 <SPEAKER>LAERTES</SPEAKER>
8868 <LINE>Say you so? come on.</LINE>
8869 </SPEECH>
8870
8871
8872 <STAGEDIR>They play</STAGEDIR>
8873
8874 <SPEECH>
8875 <SPEAKER>OSRIC</SPEAKER>
8876 <LINE>Nothing, neither way.</LINE>
8877 </SPEECH>
8878
8879 <SPEECH>
8880 <SPEAKER>LAERTES</SPEAKER>
8881 <LINE>Have at you now!</LINE>
8882 </SPEECH>
8883
8884
8885 <STAGEDIR>LAERTES wounds HAMLET; then in scuffling, they
8886 change rapiers, and HAMLET wounds LAERTES</STAGEDIR>
8887
8888 <SPEECH>
8889 <SPEAKER>KING CLAUDIUS</SPEAKER>
8890 <LINE>Part them; they are incensed.</LINE>
8891 </SPEECH>
8892
8893 <SPEECH>
8894 <SPEAKER>HAMLET</SPEAKER>
8895 <LINE>Nay, come, again.</LINE>
8896 </SPEECH>
8897
8898
8899 <STAGEDIR>QUEEN GERTRUDE falls</STAGEDIR>
8900
8901 <SPEECH>
8902 <SPEAKER>OSRIC</SPEAKER>
8903 <LINE>Look to the queen there, ho!</LINE>
8904 </SPEECH>
8905
8906 <SPEECH>
8907 <SPEAKER>HORATIO</SPEAKER>
8908 <LINE>They bleed on both sides. How is it, my lord?</LINE>
8909 </SPEECH>
8910
8911 <SPEECH>
8912 <SPEAKER>OSRIC</SPEAKER>
8913 <LINE>How is't, Laertes?</LINE>
8914 </SPEECH>
8915
8916 <SPEECH>
8917 <SPEAKER>LAERTES</SPEAKER>
8918 <LINE>Why, as a woodcock to mine own springe, Osric;</LINE>
8919 <LINE>I am justly kill'd with mine own treachery.</LINE>
8920 </SPEECH>
8921
8922 <SPEECH>
8923 <SPEAKER>HAMLET</SPEAKER>
8924 <LINE>How does the queen?</LINE>
8925 </SPEECH>
8926
8927 <SPEECH>
8928 <SPEAKER>KING CLAUDIUS</SPEAKER>
8929 <LINE>She swounds to see them bleed.</LINE>
8930 </SPEECH>
8931
8932 <SPEECH>
8933 <SPEAKER>QUEEN GERTRUDE</SPEAKER>
8934 <LINE>No, no, the drink, the drink,--O my dear Hamlet,--</LINE>
8935 <LINE>The drink, the drink! I am poison'd.</LINE>
8936 </SPEECH>
8937
8938
8939 <STAGEDIR>Dies</STAGEDIR>
8940
8941 <SPEECH>
8942 <SPEAKER>HAMLET</SPEAKER>
8943 <LINE>O villany! Ho! let the door be lock'd:</LINE>
8944 <LINE>Treachery! Seek it out.</LINE>
8945 </SPEECH>
8946
8947 <SPEECH>
8948 <SPEAKER>LAERTES</SPEAKER>
8949 <LINE>It is here, Hamlet: Hamlet, thou art slain;</LINE>
8950 <LINE>No medicine in the world can do thee good;</LINE>
8951 <LINE>In thee there is not half an hour of life;</LINE>
8952 <LINE>The treacherous instrument is in thy hand,</LINE>
8953 <LINE>Unbated and envenom'd: the foul practise</LINE>
8954 <LINE>Hath turn'd itself on me lo, here I lie,</LINE>
8955 <LINE>Never to rise again: thy mother's poison'd:</LINE>
8956 <LINE>I can no more: the king, the king's to blame.</LINE>
8957 </SPEECH>
8958
8959 <SPEECH>
8960 <SPEAKER>HAMLET</SPEAKER>
8961 <LINE>The point!--envenom'd too!</LINE>
8962 <LINE>Then, venom, to thy work.</LINE>
8963 </SPEECH>
8964
8965
8966 <STAGEDIR>Stabs KING CLAUDIUS</STAGEDIR>
8967
8968 <SPEECH>
8969 <SPEAKER>All</SPEAKER>
8970 <LINE>Treason! treason!</LINE>
8971 </SPEECH>
8972
8973 <SPEECH>
8974 <SPEAKER>KING CLAUDIUS</SPEAKER>
8975 <LINE>O, yet defend me, friends; I am but hurt.</LINE>
8976 </SPEECH>
8977
8978 <SPEECH>
8979 <SPEAKER>HAMLET</SPEAKER>
8980 <LINE>Here, thou incestuous, murderous, damned Dane,</LINE>
8981 <LINE>Drink off this potion. Is thy union here?</LINE>
8982 <LINE>Follow my mother.</LINE>
8983 </SPEECH>
8984
8985
8986 <STAGEDIR>KING CLAUDIUS dies</STAGEDIR>
8987
8988 <SPEECH>
8989 <SPEAKER>LAERTES</SPEAKER>
8990 <LINE>He is justly served;</LINE>
8991 <LINE>It is a poison temper'd by himself.</LINE>
8992 <LINE>Exchange forgiveness with me, noble Hamlet:</LINE>
8993 <LINE>Mine and my father's death come not upon thee,</LINE>
8994 <LINE>Nor thine on me.</LINE>
8995 </SPEECH>
8996
8997
8998 <STAGEDIR>Dies</STAGEDIR>
8999
9000 <SPEECH>
9001 <SPEAKER>HAMLET</SPEAKER>
9002 <LINE>Heaven make thee free of it! I follow thee.</LINE>
9003 <LINE>I am dead, Horatio. Wretched queen, adieu!</LINE>
9004 <LINE>You that look pale and tremble at this chance,</LINE>
9005 <LINE>That are but mutes or audience to this act,</LINE>
9006 <LINE>Had I but time--as this fell sergeant, death,</LINE>
9007 <LINE>Is strict in his arrest--O, I could tell you--</LINE>
9008 <LINE>But let it be. Horatio, I am dead;</LINE>
9009 <LINE>Thou livest; report me and my cause aright</LINE>
9010 <LINE>To the unsatisfied.</LINE>
9011 </SPEECH>
9012
9013 <SPEECH>
9014 <SPEAKER>HORATIO</SPEAKER>
9015 <LINE>Never believe it:</LINE>
9016 <LINE>I am more an antique Roman than a Dane:</LINE>
9017 <LINE>Here's yet some liquor left.</LINE>
9018 </SPEECH>
9019
9020 <SPEECH>
9021 <SPEAKER>HAMLET</SPEAKER>
9022 <LINE>As thou'rt a man,</LINE>
9023 <LINE>Give me the cup: let go; by heaven, I'll have't.</LINE>
9024 <LINE>O good Horatio, what a wounded name,</LINE>
9025 <LINE>Things standing thus unknown, shall live behind me!</LINE>
9026 <LINE>If thou didst ever hold me in thy heart</LINE>
9027 <LINE>Absent thee from felicity awhile,</LINE>
9028 <LINE>And in this harsh world draw thy breath in pain,</LINE>
9029 <LINE>To tell my story.</LINE>
9030 <STAGEDIR>March afar off, and shot within</STAGEDIR>
9031 <LINE>What warlike noise is this?</LINE>
9032 </SPEECH>
9033
9034 <SPEECH>
9035 <SPEAKER>OSRIC</SPEAKER>
9036 <LINE>Young Fortinbras, with conquest come from Poland,</LINE>
9037 <LINE>To the ambassadors of England gives</LINE>
9038 <LINE>This warlike volley.</LINE>
9039 </SPEECH>
9040
9041 <SPEECH>
9042 <SPEAKER>HAMLET</SPEAKER>
9043 <LINE>O, I die, Horatio;</LINE>
9044 <LINE>The potent poison quite o'er-crows my spirit:</LINE>
9045 <LINE>I cannot live to hear the news from England;</LINE>
9046 <LINE>But I do prophesy the election lights</LINE>
9047 <LINE>On Fortinbras: he has my dying voice;</LINE>
9048 <LINE>So tell him, with the occurrents, more and less,</LINE>
9049 <LINE>Which have solicited. The rest is silence.</LINE>
9050 </SPEECH>
9051
9052
9053 <STAGEDIR>Dies</STAGEDIR>
9054
9055 <SPEECH>
9056 <SPEAKER>HORATIO</SPEAKER>
9057 <LINE>Now cracks a noble heart. Good night sweet prince:</LINE>
9058 <LINE>And flights of angels sing thee to thy rest!</LINE>
9059 <LINE>Why does the drum come hither?</LINE>
9060 </SPEECH>
9061
9062 <STAGEDIR>March within</STAGEDIR>
9063 <STAGEDIR>Enter FORTINBRAS, the English Ambassadors,
9064 and others</STAGEDIR>
9065
9066 <SPEECH>
9067 <SPEAKER>PRINCE FORTINBRAS</SPEAKER>
9068 <LINE>Where is this sight?</LINE>
9069 </SPEECH>
9070
9071 <SPEECH>
9072 <SPEAKER>HORATIO</SPEAKER>
9073 <LINE>What is it ye would see?</LINE>
9074 <LINE>If aught of woe or wonder, cease your search.</LINE>
9075 </SPEECH>
9076
9077 <SPEECH>
9078 <SPEAKER>PRINCE FORTINBRAS</SPEAKER>
9079 <LINE>This quarry cries on havoc. O proud death,</LINE>
9080 <LINE>What feast is toward in thine eternal cell,</LINE>
9081 <LINE>That thou so many princes at a shot</LINE>
9082 <LINE>So bloodily hast struck?</LINE>
9083 </SPEECH>
9084
9085 <SPEECH>
9086 <SPEAKER>First Ambassador</SPEAKER>
9087 <LINE>The sight is dismal;</LINE>
9088 <LINE>And our affairs from England come too late:</LINE>
9089 <LINE>The ears are senseless that should give us hearing,</LINE>
9090 <LINE>To tell him his commandment is fulfill'd,</LINE>
9091 <LINE>That Rosencrantz and Guildenstern are dead:</LINE>
9092 <LINE>Where should we have our thanks?</LINE>
9093 </SPEECH>
9094
9095 <SPEECH>
9096 <SPEAKER>HORATIO</SPEAKER>
9097 <LINE>Not from his mouth,</LINE>
9098 <LINE>Had it the ability of life to thank you:</LINE>
9099 <LINE>He never gave commandment for their death.</LINE>
9100 <LINE>But since, so jump upon this bloody question,</LINE>
9101 <LINE>You from the Polack wars, and you from England,</LINE>
9102 <LINE>Are here arrived give order that these bodies</LINE>
9103 <LINE>High on a stage be placed to the view;</LINE>
9104 <LINE>And let me speak to the yet unknowing world</LINE>
9105 <LINE>How these things came about: so shall you hear</LINE>
9106 <LINE>Of carnal, bloody, and unnatural acts,</LINE>
9107 <LINE>Of accidental judgments, casual slaughters,</LINE>
9108 <LINE>Of deaths put on by cunning and forced cause,</LINE>
9109 <LINE>And, in this upshot, purposes mistook</LINE>
9110 <LINE>Fall'n on the inventors' reads: all this can I</LINE>
9111 <LINE>Truly deliver.</LINE>
9112 </SPEECH>
9113
9114 <SPEECH>
9115 <SPEAKER>PRINCE FORTINBRAS</SPEAKER>
9116 <LINE>Let us haste to hear it,</LINE>
9117 <LINE>And call the noblest to the audience.</LINE>
9118 <LINE>For me, with sorrow I embrace my fortune:</LINE>
9119 <LINE>I have some rights of memory in this kingdom,</LINE>
9120 <LINE>Which now to claim my vantage doth invite me.</LINE>
9121 </SPEECH>
9122
9123 <SPEECH>
9124 <SPEAKER>HORATIO</SPEAKER>
9125 <LINE>Of that I shall have also cause to speak,</LINE>
9126 <LINE>And from his mouth whose voice will draw on more;</LINE>
9127 <LINE>But let this same be presently perform'd,</LINE>
9128 <LINE>Even while men's minds are wild; lest more mischance</LINE>
9129 <LINE>On plots and errors, happen.</LINE>
9130 </SPEECH>
9131
9132 <SPEECH>
9133 <SPEAKER>PRINCE FORTINBRAS</SPEAKER>
9134 <LINE>Let four captains</LINE>
9135 <LINE>Bear Hamlet, like a soldier, to the stage;</LINE>
9136 <LINE>For he was likely, had he been put on,</LINE>
9137 <LINE>To have proved most royally: and, for his passage,</LINE>
9138 <LINE>The soldiers' music and the rites of war</LINE>
9139 <LINE>Speak loudly for him.</LINE>
9140 <LINE>Take up the bodies: such a sight as this</LINE>
9141 <LINE>Becomes the field, but here shows much amiss.</LINE>
9142 <LINE>Go, bid the soldiers shoot.</LINE>
9143 </SPEECH>
9144
9145
9146 <STAGEDIR>A dead march. Exeunt, bearing off the dead
9147 bodies; after which a peal of ordnance is shot off</STAGEDIR>
9148 </SCENE>
9149 </ACT>
9150 </PLAY>
0 /build
1 /out
0 sourceSets {
1 main {
2 java {
3 srcDir 'src/java'
4 }
5 }
6 }
7
8 sourceCompatibility = '1.6'
9 targetCompatibility = '1.6'
10
11 dependencies {
12 compileOnly 'jaxen:jaxen:1.1.6'
13 }
14
15 archivesBaseName = 'jdom'
16
17 task sourceJar(type: Jar) {
18 classifier 'sources'
19 from sourceSets.main.java
20 }
21
22 artifacts {
23 archives sourceJar
24 }
0 Manifest-Version: 1.0
1
2 Name: org/jdom2/
3 Specification-Title: JDOM Classes
4 Specification-Version: @version.spec@
5 Specification-Vendor: jdom.org
6 Implementation-Title: org.jdom
7 Implementation-Version: @version.impl@
8 Implementation-Vendor: jdom.org
9
10 Name: org/jdom2/input/
11 Specification-Title: JDOM Input Classes
12 Specification-Version: @version.spec@
13 Specification-Vendor: jdom.org2
14 Implementation-Title: org.jdom.input
15 Implementation-Version: @version.impl@
16 Implementation-Vendor: jdom.org
17
18 Name: org/jdom2/output/
19 Specification-Title: JDOM Output Classes
20 Specification-Version: @version.spec@
21 Specification-Vendor: jdom.org
22 Implementation-Title: org.jdom.output
23 Implementation-Version: @version.impl@
24 Implementation-Vendor: jdom.org
25
26 Name: org/jdom2/adapters/
27 Specification-Title: JDOM Adapter Classes
28 Specification-Version: @version.spec@
29 Specification-Vendor: jdom.org
30 Implementation-Title: org.jdom.adapters
31 Implementation-Version: @version.impl@
32 Implementation-Vendor: jdom.org
33
34 Name: org/jdom2/filter/
35 Specification-Title: JDOM Filter Classes
36 Specification-Version: @version.spec@
37 Specification-Vendor: jdom.org
38 Implementation-Title: org.jdom.filter
39 Implementation-Version: @version.impl@
40 Implementation-Vendor: jdom.org
41
42 Name: org/jdom2/transform/
43 Specification-Title: JDOM Transformation Classes
44 Specification-Version: @version.spec@
45 Specification-Vendor: jdom.org
46 Implementation-Title: org.jdom.transform
47 Implementation-Version: @version.impl@
48 Implementation-Vendor: jdom.org
49
50 Name: org/jdom2/xpath/
51 Specification-Title: JDOM XPath Classes
52 Specification-Version: @version.spec@
53 Specification-Vendor: jdom.org
54 Implementation-Title: org.jdom.xpath
55 Implementation-Version: @version.impl@
56 Implementation-Vendor: jdom.org
0 <?xml version="1.0"?>
1 <info>
2 <title>JDOM</title>
3 <version>@version@, built @date@</version>
4 <description>
5 JDOM is a Java-oriented object model which models XML documents.
6 It provides a Java-centric means of generating and manipulating
7 XML documents. While JDOM interoperates well with existing
8 standards such as the Simple API for XML (SAX) and the Document
9 Object Model (DOM), it is not an abstraction layer or
10 enhancement to those APIs. Rather, it seeks to provide a robust,
11 light-weight means of reading and writing XML data without the
12 complex and memory-consumptive options that current API
13 offerings provide.
14 </description>
15 <copyright>2000-@year@, Jason Hunter</copyright>
16 <license>BSD/Apache style, see LICENSE.txt</license>
17 <support>See the jdom-interest mailing list at jdom.org,
18 searchable at http://jdom.markmail.org</support>
19 <web-site>http://www.jdom.org/</web-site>
20 <!--
21 The following list of authors was initially extracted from @author
22 comments in the code. Apologies if anyone has been left out.
23 -->
24 <author>
25 <name>Jason Hunter (primary, co-creator)</name>
26 </author>
27 <author>
28 <name>Brett McLaughlin (co-creator)</name>
29 </author>
30 <author>
31 <name>Rolf Lear (primary, maintainer)</name>
32 </author>
33 <author>
34 <name>Steven Gould</name>
35 </author>
36 <author>
37 <name>Alex Chaffee</name>
38 </author>
39 <author>
40 <name>Jon Baer</name>
41 </author>
42 <author>
43 <name>Elliotte Rusty Harold</name>
44 </author>
45 <author>
46 <name>Dan Schaffer</name>
47 </author>
48 <author>
49 <name>Fred Trimble</name>
50 </author>
51 <author>
52 <name>Jason Reid</name>
53 </author>
54 <author>
55 <name>Kevin Regan</name>
56 </author>
57 <author>
58 <name>Lucas Gonze</name>
59 </author>
60 <author>
61 <name>Matthew Merlo</name>
62 </author>
63 <author>
64 <name>Philip Nelson</name>
65 </author>
66 <author>
67 <name>Wesley Biggs</name>
68 </author>
69 <author>
70 <name>Wolfgang Werner</name>
71 </author>
72 <author>
73 <name>Yusuf Goolamabbas</name>
74 </author>
75 <author>
76 <name>Brad Huffman</name>
77 </author>
78 <author>
79 <name>Victor Toni</name>
80 </author>
81 </info>
82
83 <!--
84
85 The following would go in MANIFEST.MF, if only the file supported comments.
86
87 For more information on package versioning, see http://java.sun.com/
88 products/jdk/1.2/docs/guide/versioning/spec/VersioningSpecification.html
89 Also http://java.sun.com/products/jdk/1.2/docs/guide/jar/manifest.html
90 and http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html
91
92 FYI- Spec version 0.6 means beta6, 0.7 means beta7, and so on. Perhaps
93 surprisingly, 0.10 means beta10. It's ugly, but is in line with the
94 Dewey Decimal system used by package versioning.
95
96 -->
97
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55
56 import java.util.*;
57
58 import org.jdom.*;
59 import org.jdom.filter2.ElementFilter;
60 import org.jdom.filter2.Filters;
61 import org.jdom.input.*;
62 import org.jdom.output.*;
63
64 /**
65 * Demonstrates the use of {@link Parent#getDescendants}.
66 */
67 @SuppressWarnings("javadoc")
68 public class DescendantDemo {
69
70 public static void main(String[] args) throws Exception {
71 if (args.length == 0) {
72 System.err.println(
73 "Usage: java DescendantDemo file1.xml [file2.xml ... ]");
74 return;
75 }
76
77 final SAXBuilder builder = new SAXBuilder();
78 for (final String fname : args) {
79 System.out.println("Processing file " + fname);
80 // The String argument is considered to be a SystemID which can
81 // be a URL, File name, a relative file path, etc.
82 final Document doc = builder.build(fname);
83
84 System.out.println("All content:");
85 Iterator<? extends Content> itr = doc.getDescendants();
86 while (itr.hasNext()) {
87 Content c = itr.next();
88 // c.toString() gives a very brief output.
89 System.out.println(c.toString());
90 }
91
92 System.out.println();
93 System.out.println("Only elements:");
94 itr = doc.getDescendants(new ElementFilter());
95 while (itr.hasNext()) {
96 Content c = itr.next();
97 System.out.println(c);
98 }
99
100 System.out.println();
101 System.out.println("Everything that's not an element:");
102 itr = doc.getDescendants(new ElementFilter().negate().refine(Filters.content()));
103 while (itr.hasNext()) {
104 Content c = itr.next();
105 System.out.println(c);
106 }
107
108 System.out.println();
109 System.out.println("Only elements with localname of 'servlet':");
110 itr = doc.getDescendants(new ElementFilter("servlet"));
111 while (itr.hasNext()) {
112 Content c = itr.next();
113 System.out.println(c);
114 }
115
116 System.out.println();
117 System.out.println(
118 "Only elements with localname of servlet-name or servlet-class:");
119 itr = doc.getDescendants(new ElementFilter("servlet-name")
120 .or(new ElementFilter("servlet-class")));
121 while (itr.hasNext()) {
122 Content c = itr.next();
123 System.out.println(c);
124 }
125
126 System.out.println();
127 System.out.println("Remove elements with localname of servlet:");
128 Iterator<Element>ite = doc.getDescendants(new ElementFilter("servlet"));
129 while (ite.hasNext()) {
130 Element e = ite.next();
131 System.out.println(e);
132 ite.remove();
133 }
134
135 System.out.println();
136 System.out.println("Dump the remaining document to console:");
137 XMLOutputter outp = new XMLOutputter();
138 outp.output(doc, System.out);
139 System.out.println();
140 System.out.println();
141 }
142 }
143 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55
56 import java.io.IOException;
57
58 import org.jdom.Document;
59 import org.jdom.JDOMException;
60 import org.jdom.input.SAXBuilder;
61 import org.jdom.output.Format;
62 import org.jdom.output.XMLOutputter;
63
64 /**
65 * <p><code>SAXBuilderDemo</code> demonstrates how to
66 * build a JDOM <code>Document</code> using a SAX parser.
67 * </p>
68 *
69 * @author Brett McLaughlin
70 * @author Jason Hunter
71 * @version 1.0
72 */
73 public class SAXBuilderDemo {
74
75 /**
76 * <p>
77 * This provides a static entry point for creating a JDOM
78 * <code>{@link Document}</code> object using a SAX 2.0
79 * parser (an <code>XMLReader</code> implementation).
80 * </p>
81 *
82 * @param args <code>String[]</code> list of files to parse
83 */
84 public static void main(String[] args) {
85 if (args.length < 1) {
86 System.err.println(
87 "Usage: java SAXBuilderDemo file1.xml [ file2.xml [ ... ] ]");
88 return;
89 }
90
91 // Used to parse documents
92 final SAXBuilder builder = new SAXBuilder();
93 // used to output documents as String-based XML.
94 // in this case the output will be 'pretty' formatted.
95 final XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
96
97 for (String filename : args) {
98 // Create an instance of the tester and test
99 try {
100
101 final Document doc = builder.build(filename);
102
103 outputter.output(doc, System.out);
104 } catch (JDOMException e) {
105 e.printStackTrace();
106 } catch (IOException e) {
107 e.printStackTrace();
108 }
109 }
110 }
111 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55
56 import java.io.File;
57 import java.io.IOException;
58 import java.io.PrintStream;
59 import java.util.List;
60
61 import org.jdom.Document;
62 import org.jdom.Element;
63 import org.jdom.JDOMException;
64 import org.jdom.input.SAXBuilder;
65
66 /**
67 * <p><code>WarReader</code> demonstrates how to
68 * read a Servlet 2.2 Web Archive file with JDOM.
69 * </p>
70 *
71 * @author Brett McLaughlin, Jason Hunter
72 * @version 1.0
73 */
74 @SuppressWarnings("javadoc")
75 public class WarReader {
76
77 public static void main(String[] args) throws IOException, JDOMException {
78 if (args.length != 1) {
79 System.err.println("Usage: java WarReader [web.xml]");
80 return;
81 }
82 String filename = args[0];
83 PrintStream out = System.out;
84
85 SAXBuilder builder = new SAXBuilder();
86 Document doc = builder.build(new File(filename));
87
88 // Get the root element
89 Element root = doc.getRootElement();
90
91 // Print servlet information
92 List<Element> servlets = root.getChildren("servlet");
93 out.println("This WAR has "+ servlets.size() +" registered servlets:");
94 for (Element servlet : servlets) {
95 out.print("\t" + servlet.getChild("servlet-name")
96 .getTextTrim() +
97 " for " + servlet.getChild("servlet-class")
98 .getTextTrim());
99 List<Element> initParams = servlet.getChildren("init-param");
100 out.println(" (it has " + initParams.size() + " init params)");
101 }
102
103 // Print security role information
104 List<Element> securityRoles = root.getChildren("security-role");
105 if (securityRoles.size() == 0) {
106 out.println("This WAR contains no roles");
107 } else {
108 Element securityRole = securityRoles.get(0);
109 List<Element> roleNames = securityRole.getChildren("role-name");
110 out.println("This WAR contains " + roleNames.size() + " roles:");
111 for (Element e : roleNames) {
112 out.println("\t" + e.getTextTrim());
113 }
114 }
115
116 // Print distributed information (notice this is out of order)
117 if (root.getChildren("distributed").isEmpty()) {
118 out.println("This WAR is not distributed");
119 } else {
120 out.println("This WAR is distributed");
121 }
122 }
123 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55
56 import java.io.*;
57 import java.util.*;
58 import org.jdom.*;
59 import org.jdom.filter2.Filters;
60 import org.jdom.input.*;
61 import org.jdom.xpath.*;
62
63 /**
64 * <p><code>XPathReader</code> demonstrates how to
65 * read a Servlet 2.2 Web Archive file using XPath.
66 * </p>
67 *
68 * @author Jason Hunter
69 * @version 1.0
70 */
71 @SuppressWarnings("javadoc")
72 public class XPathReader {
73
74 public static void main(String[] args) throws IOException, JDOMException {
75 if (args.length != 1) {
76 System.err.println("Usage: java XPathReader [web.xml]");
77 return;
78 }
79 String filename = args[0];
80 PrintStream out = System.out;
81
82 SAXBuilder builder = new SAXBuilder();
83 Document doc = builder.build(new File(filename));
84
85 // Print servlet information
86 XPathExpression<Element> servletPath =
87 XPathFactory.instance().compile("//servlet", Filters.element());
88 List<Element> servlets = servletPath.evaluate(doc);
89
90 out.println("This WAR has "+ servlets.size() +" registered servlets:");
91 for (Element servlet : servlets) {
92 out.print("\t" + servlet.getChild("servlet-name")
93 .getTextTrim() +
94 " for " + servlet.getChild("servlet-class")
95 .getTextTrim());
96 List<Element> initParams = servlet.getChildren("init-param");
97 out.println(" (it has " + initParams.size() + " init params)");
98 }
99
100 // Print security role information
101 XPathExpression<Text> rolePath = XPathFactory.instance().compile(
102 "//security-role/role-name/text()", Filters.text());
103 List<Text> roleNames = rolePath.evaluate(doc);
104
105 if (roleNames.isEmpty()) {
106 out.println("This WAR contains no roles");
107 } else {
108 out.println("This WAR contains " + roleNames.size() + " roles:");
109 for (Text t : roleNames) {
110 out.println("\t" + t.getTextTrim());
111 }
112 }
113 }
114 }
0
1
2 import org.jdom.*;
3 import org.jdom.input.*;
4 import org.jdom.output.*;
5 import org.jdom.transform.*;
6
7 @SuppressWarnings("javadoc")
8 public class XSLTransform {
9
10 public static void main(String[] args) throws Exception {
11 if (args.length != 2) {
12 System.err.println("Usage: java XSLTransformer [some.xml] [some.xsl]");
13 return;
14 }
15
16 String docname = args[0];
17 String sheetname = args[1];
18 SAXBuilder builder = new SAXBuilder();
19 Document doc = builder.build(docname);
20
21 XSLTransformer transformer = new XSLTransformer(sheetname);
22 Document doc2 = transformer.transform(doc);
23
24 Format f = Format.getPrettyFormat();
25 f.setLineSeparator(LineSeparator.DOS);
26 XMLOutputter outp = new XMLOutputter(f);
27 outp.output(doc2, System.out);
28 }
29 }
0 <?xml version="1.0"?>
1
2 <cdataTest>
3 test &lt; one <![CDATA[&&<<>>]]> test two
4 </cdataTest>
0 <?xml version="1.0"?>
1
2 <?xml-stylesheet href="XSL\JavaXML.html.xsl" type="text/xsl"?>
3 <?xml-stylesheet href="XSL\JavaXML.wml.xsl" type="text/xsl"
4 media="wap"?>
5 <?cocoon-process type="xslt"?>
6
7 <!-- Java and XML -->
8 <JavaXML:Book xmlns:JavaXML="http://www.oreilly.com/catalog/javaxml/"
9 ora:category="Java"
10 xmlns:ora="http://www.oreilly.com"
11 xmlns:unused="http://www.unused.com"
12 >
13 <JavaXML:Title>Java and XML</JavaXML:Title>
14 <JavaXML:Contents xmlns:topic="http://www.oreilly.com/topics">
15 <JavaXML:Chapter topic:focus="XML">
16 <JavaXML:Heading>Introduction</JavaXML:Heading>
17 <JavaXML:Topic subSections="7">
18 What Is It?
19 </JavaXML:Topic>
20 <JavaXML:Topic subSections="3">
21 How Do I Use It?
22 </JavaXML:Topic>
23 <JavaXML:Topic subSections="4">
24 Why Should I Use It?
25 </JavaXML:Topic>
26 <JavaXML:Topic subSections="0">
27 What's Next?
28 </JavaXML:Topic>
29 </JavaXML:Chapter>
30
31 <JavaXML:Chapter topic:focus="XML">
32 <JavaXML:Heading>Creating XML</JavaXML:Heading>
33 <JavaXML:Topic subSections="0">An XML Document</JavaXML:Topic>
34 <JavaXML:Topic subSections="2">The Header</JavaXML:Topic>
35 <JavaXML:Topic subSections="6">The Content</JavaXML:Topic>
36 <JavaXML:Topic subSections="1">What's Next?</JavaXML:Topic>
37 </JavaXML:Chapter>
38
39 <JavaXML:Chapter topic:focus="Java">
40 <JavaXML:Heading>Parsing XML</JavaXML:Heading>
41 <JavaXML:Topic subSections="3">Getting Prepared</JavaXML:Topic>
42 <JavaXML:Topic subSections="3">SAX Readers</JavaXML:Topic>
43 <JavaXML:Topic subSections="9">Content Handlers</JavaXML:Topic>
44 <JavaXML:Topic subSections="4">Error Handlers</JavaXML:Topic>
45 <JavaXML:Topic subSections="0">
46 A Better Way to Load a Parser
47 </JavaXML:Topic>
48 <JavaXML:Topic subSections="4">"Gotcha!"</JavaXML:Topic>
49 <JavaXML:Topic subSections="0">What's Next?</JavaXML:Topic>
50 </JavaXML:Chapter>
51
52 <JavaXML:SectionBreak/>
53
54 <JavaXML:Chapter topic:focus="Java">
55 <JavaXML:Heading>Web Publishing Frameworks</JavaXML:Heading>
56 <JavaXML:Topic subSections="4">Selecting a Framework</JavaXML:Topic>
57 <JavaXML:Topic subSections="4">Installation</JavaXML:Topic>
58 <JavaXML:Topic subSections="3">
59 Using a Publishing Framework
60 </JavaXML:Topic>
61 <JavaXML:Topic subSections="2">XSP</JavaXML:Topic>
62 <JavaXML:Topic subSections="3">Cocoon 2.0 and Beyond</JavaXML:Topic>
63 <JavaXML:Topic subSections="0">What's Next?</JavaXML:Topic>
64 </JavaXML:Chapter>
65 </JavaXML:Contents>
66 </JavaXML:Book>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Fibonacci_Numbers>
2 <fibonacci index="0">0</fibonacci>
3 <fibonacci index="1">1</fibonacci>
4 <fibonacci index="2">1</fibonacci>
5 <fibonacci index="3">2</fibonacci>
6 <fibonacci index="4">3</fibonacci>
7 <fibonacci index="5">5</fibonacci>
8 <fibonacci index="6">8</fibonacci>
9 <fibonacci index="7">13</fibonacci>
10 <fibonacci index="8">21</fibonacci>
11 <fibonacci index="9">34</fibonacci>
12 <fibonacci index="10">55</fibonacci>
13 <fibonacci index="11">89</fibonacci>
14 <fibonacci index="12">144</fibonacci>
15 <fibonacci index="13">233</fibonacci>
16 <fibonacci index="14">377</fibonacci>
17 <fibonacci index="15">610</fibonacci>
18 <fibonacci index="16">987</fibonacci>
19 <fibonacci index="17">1597</fibonacci>
20 <fibonacci index="18">2584</fibonacci>
21 <fibonacci index="19">4181</fibonacci>
22 <fibonacci index="20">6765</fibonacci>
23 <fibonacci index="21">10946</fibonacci>
24 <fibonacci index="22">17711</fibonacci>
25 <fibonacci index="23">28657</fibonacci>
26 <fibonacci index="24">46368</fibonacci>
27 <fibonacci index="25">75025</fibonacci>
28 </Fibonacci_Numbers>
0 <?xml version='1.0'?>
1
2 <!DOCTYPE DOCUMENT [
3 <!ELEMENT DOCUMENT (#PCDATA)>
4 <!ENTITY nbsp '&#160;'>
5 <!ENTITY aring '&#229;'>
6 <!ENTITY auml '&#228;'>
7 <!ENTITY ouml '&#246;'>
8 <!ENTITY Aring '&#197;'>
9 <!ENTITY Auml '&#196;'>
10 <!ENTITY Ouml '&#214;'>
11 ]>
12
13 <DOCUMENT>
14 God forts&auml;ttning p&aring; det nya millenniet!
15 </DOCUMENT>
0 <?xml version="1.0"?>
1
2 <xsl:stylesheet
3 xmlns:JavaXML="http://www.oreilly.com/catalog/javaxml/"
4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5 xmlns:foo="http://www.foo.com/bar"
6 version="1.0">
7
8 <xsl:template match="JavaXML:Book">
9 <head>
10 <title><xsl:value-of select="JavaXML:Title" /></title>
11 </head>
12 <body>
13 <xsl:apply-templates select="*[not(self::JavaXML:Title)]" />
14 </body>
15 </xsl:template>
16
17 </xsl:stylesheet>
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53 package sax;
54
55 import java.util.Stack;
56
57 import org.xml.sax.Attributes;
58 import org.xml.sax.SAXException;
59 import org.xml.sax.XMLReader;
60
61
62 /**
63 * Filter for data- or field-oriented XML.
64 *
65 * <i>Code and comments adapted from DataWriter-0.2, written
66 * by David Megginson and released into the public domain,
67 * without warranty.</i>
68 *
69 * <p>This filter adds indentation and newlines to field-oriented
70 * XML without mixed content. All added indentation and newlines
71 * will be passed on down the filter chain.</p>
72 *
73 * <p>In general, all whitespace in an XML document is potentially
74 * significant. There is, however, a large class of XML documents
75 * where information is strictly fielded: each element contains either
76 * character data or other elements, but not both. For this special
77 * case, it is possible for a filter to provide automatic indentation
78 * and newlines. Note that this class will likely not yield appropriate
79 * results for document-oriented XML like XHTML pages, which mix character
80 * data and elements together.</p>
81 *
82 * <p>This filter will automatically place each start tag on a new line,
83 * optionally indented if an indent step is provided (by default, there
84 * is no indentation). If an element contains other elements, the end
85 * tag will also appear on a new line with leading indentation. Consider,
86 * for example, the following code:</p>
87 *
88 * <pre>
89 * DataFormatFilter df = new DataFormatFilter();
90 * df.setContentHandler(new XMLWriter());
91 *
92 * df.setIndentStep(2);
93 * df.startDocument();
94 * df.startElement("Person");
95 * df.dataElement("name", "Jane Smith");
96 * df.dataElement("date-of-birth", "1965-05-23");
97 * df.dataElement("citizenship", "US");
98 * df.endElement("Person");
99 * df.endDocument();
100 * </pre>
101 *
102 * <p>This code will produce the following document:</p>
103 *
104 * <pre>
105 * &lt;?xml version="1.0"?>
106 *
107 * &lt;Person>
108 * &lt;name>Jane Smith&lt;/name>
109 * &lt;date-of-birth>1965-05-23&lt;/date-of-birth>
110 * &lt;citizenship>US&lt;/citizenship>
111 * &lt;/Person>
112 * </pre>
113 *
114 * @see DataUnformatFilter
115 */
116 public class DataFormatFilter extends XMLFilterBase
117 {
118
119
120
121 ////////////////////////////////////////////////////////////////////
122 // Constructors.
123 ////////////////////////////////////////////////////////////////////
124
125
126 /**
127 * Create a new filter.
128 */
129 public DataFormatFilter()
130 {
131 }
132
133
134 /**
135 * Create a new filter.
136 *
137 * <p>Use the XMLReader provided as the source of events.</p>
138 *
139 * @param xmlreader The parent in the filter chain.
140 */
141 public DataFormatFilter(XMLReader xmlreader)
142 {
143 super(xmlreader);
144 }
145
146
147 ////////////////////////////////////////////////////////////////////
148 // Accessors and setters.
149 ////////////////////////////////////////////////////////////////////
150
151
152 /**
153 * Return the current indent step.
154 *
155 * <p>Return the current indent step: each start tag will be
156 * indented by this number of spaces times the number of
157 * ancestors that the element has.</p>
158 *
159 * @return The number of spaces in each indentation step,
160 * or 0 or less for no indentation.
161 * @see #setIndentStep
162 */
163 public int getIndentStep ()
164 {
165 return indentStep;
166 }
167
168
169 /**
170 * Set the current indent step.
171 *
172 * @param indentStep The new indent step (0 or less for no
173 * indentation).
174 * @see #getIndentStep
175 */
176 public void setIndentStep (int indentStep)
177 {
178 this.indentStep = indentStep;
179 }
180
181
182
183 ////////////////////////////////////////////////////////////////////
184 // Public methods.
185 ////////////////////////////////////////////////////////////////////
186
187
188 /**
189 * Reset the filter so that it can be reused.
190 *
191 * <p>This method is especially useful if the filter failed
192 * with an exception the last time through.</p>
193 */
194 public void reset ()
195 {
196 state = SEEN_NOTHING;
197 stateStack = new Stack<Object>();
198 }
199
200
201
202 ////////////////////////////////////////////////////////////////////
203 // Methods from org.xml.sax.ContentHandler.
204 ////////////////////////////////////////////////////////////////////
205
206
207 /**
208 * Filter a start document event.
209 *
210 * <p>Reset state and pass the event on for further processing.</p>
211 *
212 * @exception org.xml.sax.SAXException If a filter
213 * further down the chain raises an exception.
214 * @see org.xml.sax.ContentHandler#startDocument
215 */
216 @Override
217 public void startDocument ()
218 throws SAXException
219 {
220 reset();
221 super.startDocument();
222 }
223
224
225 /**
226 * Add newline and indentation prior to start tag.
227 *
228 * <p>Each tag will begin on a new line, and will be
229 * indented by the current indent step times the number
230 * of ancestors that the element has.</p>
231 *
232 * <p>The newline and indentation will be passed on down
233 * the filter chain through regular characters events.</p>
234 *
235 * @param uri The element's Namespace URI.
236 * @param localName The element's local name.
237 * @param qName The element's qualified (prefixed) name.
238 * @param atts The element's attribute list.
239 * @exception org.xml.sax.SAXException If a filter
240 * further down the chain raises an exception.
241 * @see org.xml.sax.ContentHandler#startElement
242 */
243 @Override
244 public void startElement (String uri, String localName,
245 String qName, Attributes atts)
246 throws SAXException
247 {
248 if (!stateStack.empty()) {
249 doNewline();
250 doIndent();
251 }
252 stateStack.push(SEEN_ELEMENT);
253 state = SEEN_NOTHING;
254 super.startElement(uri, localName, qName, atts);
255 }
256
257
258 /**
259 * Add newline and indentation prior to end tag.
260 *
261 * <p>If the element has contained other elements, the tag
262 * will appear indented on a new line; otherwise, it will
263 * appear immediately following whatever came before.</p>
264 *
265 * <p>The newline and indentation will be passed on down
266 * the filter chain through regular characters events.</p>
267 *
268 * @param uri The element's Namespace URI.
269 * @param localName The element's local name.
270 * @param qName The element's qualified (prefixed) name.
271 * @exception org.xml.sax.SAXException If a filter
272 * further down the chain raises an exception.
273 * @see org.xml.sax.ContentHandler#endElement
274 */
275 @Override
276 public void endElement (String uri, String localName, String qName)
277 throws SAXException
278 {
279 boolean seenElement = (state == SEEN_ELEMENT);
280 state = stateStack.pop();
281 if (seenElement) {
282 doNewline();
283 doIndent();
284 }
285 super.endElement(uri, localName, qName);
286 }
287
288
289 /**
290 * Filter a character data event.
291 *
292 * @param ch The characters to write.
293 * @param start The starting position in the array.
294 * @param length The number of characters to use.
295 * @exception org.xml.sax.SAXException If a filter
296 * further down the chain raises an exception.
297 * @see org.xml.sax.ContentHandler#characters
298 */
299 @Override
300 public void characters (char ch[], int start, int length)
301 throws SAXException
302 {
303 state = SEEN_DATA;
304 super.characters(ch, start, length);
305 }
306
307
308
309 ////////////////////////////////////////////////////////////////////
310 // Internal methods.
311 ////////////////////////////////////////////////////////////////////
312
313
314 /**
315 * Add newline.
316 *
317 * @exception org.xml.sax.SAXException If a filter
318 * further down the chain raises an exception.
319 */
320 private void doNewline ()
321 throws SAXException
322 {
323 super.characters(NEWLINE, 0, NEWLINE.length);
324 }
325
326
327 /**
328 * Add indentation for the current level.
329 *
330 * @exception org.xml.sax.SAXException If a filter
331 * further down the chain raises an exception.
332 */
333 private void doIndent ()
334 throws SAXException
335 {
336 int n = indentStep * stateStack.size();
337 if (n > 0) {
338 char ch[] = new char[n];
339 for (int i = 0; i < n; i++) {
340 ch[i] = INDENT_CHAR;
341 }
342 super.characters(ch, 0, n);
343 }
344 }
345
346
347
348
349 ////////////////////////////////////////////////////////////////////
350 // Constants.
351 ////////////////////////////////////////////////////////////////////
352
353 private static final Object SEEN_NOTHING = new Object();
354 private static final Object SEEN_ELEMENT = new Object();
355 private static final Object SEEN_DATA = new Object();
356
357 private static final char[] NEWLINE = new char[] {'\n'};
358 private static final char INDENT_CHAR = ' ';
359
360
361 ////////////////////////////////////////////////////////////////////
362 // Internal state.
363 ////////////////////////////////////////////////////////////////////
364
365 private Object state = SEEN_NOTHING;
366 private Stack<Object> stateStack = new Stack<Object>();
367
368 private int indentStep = 0;
369
370 }
371
372 // end of DataFormatFilter.java
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53 package sax;
54
55 import java.util.Stack;
56
57 import org.xml.sax.Attributes;
58 import org.xml.sax.SAXException;
59 import org.xml.sax.XMLReader;
60
61
62 /**
63 * Filter for removing formatting from data- or field-oriented XML.
64 *
65 * <i>Code and comments adapted from DataWriter-0.2, written
66 * by David Megginson and released into the public domain,
67 * without warranty.</i>
68 *
69 * <p>This filter removes leading and trailing whitespace from
70 * field-oriented XML without mixed content. Note that this class will
71 * likely not yield appropriate results for document-oriented XML like
72 * XHTML pages, which mix character data and elements together.</p>
73 *
74 * @see DataFormatFilter
75 */
76 @SuppressWarnings("javadoc")
77 public class DataUnformatFilter extends XMLFilterBase
78 {
79
80
81
82 ////////////////////////////////////////////////////////////////////
83 // Constructors.
84 ////////////////////////////////////////////////////////////////////
85
86
87 /**
88 * Create a new filter.
89 */
90 public DataUnformatFilter()
91 {
92 }
93
94
95 /**
96 * Create a new filter.
97 *
98 * <p>Use the XMLReader provided as the source of events.</p>
99 *
100 * @param xmlreader The parent in the filter chain.
101 */
102 public DataUnformatFilter(XMLReader xmlreader)
103 {
104 super(xmlreader);
105 }
106
107
108
109 ////////////////////////////////////////////////////////////////////
110 // Public methods.
111 ////////////////////////////////////////////////////////////////////
112
113
114 /**
115 * Reset the filter so that it can be reused.
116 *
117 * <p>This method is especially useful if the filter failed
118 * with an exception the last time through.</p>
119 */
120 public void reset ()
121 {
122 state = SEEN_NOTHING;
123 stateStack = new Stack<Object>();
124 whitespace = new StringBuffer();
125 }
126
127
128
129 ////////////////////////////////////////////////////////////////////
130 // Methods from org.xml.sax.ContentHandler.
131 ////////////////////////////////////////////////////////////////////
132
133
134 /**
135 * Filter a start document event.
136 *
137 * <p>Reset state and pass the event on for further processing.</p>
138 *
139 * @exception org.xml.sax.SAXException If a filter
140 * further down the chain raises an exception.
141 * @see org.xml.sax.ContentHandler#startDocument
142 */
143 @Override
144 public void startDocument ()
145 throws SAXException
146 {
147 reset();
148 super.startDocument();
149 }
150
151
152 /**
153 * Filter a start element event.
154 *
155 * @param uri The element's Namespace URI.
156 * @param localName The element's local name.
157 * @param qName The element's qualified (prefixed) name.
158 * @param atts The element's attribute list.
159 * @exception org.xml.sax.SAXException If a filter
160 * further down the chain raises an exception.
161 * @see org.xml.sax.ContentHandler#startElement
162 */
163 @Override
164 public void startElement (String uri, String localName,
165 String qName, Attributes atts)
166 throws SAXException
167 {
168 clearWhitespace();
169 stateStack.push(SEEN_ELEMENT);
170 state = SEEN_NOTHING;
171 super.startElement(uri, localName, qName, atts);
172 }
173
174
175 /**
176 * Filter an end element event.
177 *
178 * @param uri The element's Namespace URI.
179 * @param localName The element's local name.
180 * @param qName The element's qualified (prefixed) name.
181 * @exception org.xml.sax.SAXException If a filter
182 * further down the chain raises an exception.
183 * @see org.xml.sax.ContentHandler#endElement
184 */
185 @Override
186 public void endElement (String uri, String localName, String qName)
187 throws SAXException
188 {
189 if (state == SEEN_ELEMENT) {
190 clearWhitespace();
191 } else {
192 emitWhitespace();
193 }
194 state = stateStack.pop();
195 super.endElement(uri, localName, qName);
196 }
197
198
199 /**
200 * Filter a character data event.
201 *
202 * @param ch The characters to write.
203 * @param start The starting position in the array.
204 * @param length The number of characters to use.
205 * @exception org.xml.sax.SAXException If a filter
206 * further down the chain raises an exception.
207 * @see org.xml.sax.ContentHandler#characters
208 */
209 @Override
210 public void characters (char ch[], int start, int length)
211 throws SAXException
212 {
213 if (state != SEEN_DATA) {
214
215 /* Look for non-whitespace. */
216
217 int end = start + length;
218 while (end-- > start) {
219 if (!isXMLWhitespace(ch[end]))
220 break;
221 }
222
223 /*
224 * If all the characters are whitespace, save them for later.
225 * If we've got some data, emit any saved whitespace and update
226 * our state to show we've seen data.
227 */
228
229 if (end < start) {
230 saveWhitespace(ch, start, length);
231 } else {
232 state = SEEN_DATA;
233 emitWhitespace();
234 }
235 }
236
237 /* Pass on everything inside a data field. */
238
239 if (state == SEEN_DATA) {
240 super.characters(ch, start, length);
241 }
242 }
243
244
245 /**
246 * Filter an ignorable whitespace event.
247 *
248 * @param ch The array of characters to write.
249 * @param start The starting position in the array.
250 * @param length The number of characters to write.
251 * @exception org.xml.sax.SAXException If a filter
252 * further down the chain raises an exception.
253 * @see org.xml.sax.ContentHandler#ignorableWhitespace
254 */
255 @Override
256 public void ignorableWhitespace (char ch[], int start, int length)
257 throws SAXException
258 {
259 emitWhitespace();
260 // ignore
261 }
262
263
264 /**
265 * Filter a processing instruction event.
266 *
267 * @param target The PI target.
268 * @param data The PI data.
269 * @exception org.xml.sax.SAXException If a filter
270 * further down the chain raises an exception.
271 * @see org.xml.sax.ContentHandler#processingInstruction
272 */
273 @Override
274 public void processingInstruction (String target, String data)
275 throws SAXException
276 {
277 emitWhitespace();
278 super.processingInstruction(target, data);
279 }
280
281
282
283 ////////////////////////////////////////////////////////////////////
284 // Internal methods.
285 ////////////////////////////////////////////////////////////////////
286
287
288 /**
289 * Saves trailing whitespace.
290 */
291 protected void saveWhitespace (char[] ch, int start, int length) {
292 whitespace.append(ch, start, length);
293 }
294
295
296 /**
297 * Passes saved whitespace down the filter chain.
298 */
299 protected void emitWhitespace ()
300 throws SAXException
301 {
302 char[] data = new char[whitespace.length()];
303 whitespace.getChars(0, data.length, data, 0);
304 whitespace.setLength(0);
305 super.characters(data, 0, data.length);
306 }
307
308
309 /**
310 * Discards saved whitespace.
311 */
312 protected void clearWhitespace () {
313 whitespace.setLength(0);
314 }
315
316
317 /**
318 * Returns <var>true</var> if character is XML whitespace.
319 */
320 private boolean isXMLWhitespace (char c)
321 {
322 return c == ' ' || c == '\t' || c == '\r' || c == '\n';
323 }
324
325
326
327
328 ////////////////////////////////////////////////////////////////////
329 // Constants.
330 ////////////////////////////////////////////////////////////////////
331
332 private static final Object SEEN_NOTHING = new Object();
333 private static final Object SEEN_ELEMENT = new Object();
334 private static final Object SEEN_DATA = new Object();
335
336
337 ////////////////////////////////////////////////////////////////////
338 // Internal state.
339 ////////////////////////////////////////////////////////////////////
340
341 private Object state = SEEN_NOTHING;
342 private Stack<Object> stateStack = new Stack<Object>();
343
344 private StringBuffer whitespace = new StringBuffer();
345
346 }
347
348 // end of DataUnformatFilter.java
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53 package sax;
54
55 import java.io.IOException;
56
57 import org.xml.sax.InputSource;
58 import org.xml.sax.SAXException;
59
60 import org.jdom.Document;
61 import org.jdom.JDOMException;
62 import org.jdom.output.SAXOutputter;
63
64 /**
65 * An XMLReader wrapper for JDOM documents.
66 */
67 @SuppressWarnings("javadoc")
68 public class DocumentReader extends XMLReaderBase {
69
70 private final Document doc;
71
72 /** Creates new DocumentReader */
73 public DocumentReader(Document doc) {
74 this.doc = doc;
75 }
76
77 @Override
78 public void parse(InputSource input) throws SAXException, IOException {
79 SAXOutputter outputter = new SAXOutputter(this, this, this, this, this);
80 try {
81 outputter.output(doc);
82 }
83 catch (JDOMException ex) {
84 throw new SAXException(ex);
85 }
86 }
87 }
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53 package sax;
54
55 import java.io.InputStream;
56
57 import org.jdom.Document;
58 import org.jdom.input.SAXBuilder;
59 import org.jdom.output.XMLOutputter;
60
61 /**
62 * Tests SAXBuilder's XMLFilter feature
63 *
64 * @author joe.bowbeer
65 */
66 @SuppressWarnings("javadoc")
67 public class FilterTest {
68
69 /** Creates new FilterTest */
70 public FilterTest() {
71 }
72
73 /**
74 * @param args the command line arguments
75 */
76 public static void main (String args[]) throws Exception {
77
78 /* XMLWriter for viewing unfiltered input. */
79
80 XMLWriter echo = new XMLWriter();
81
82 /* Add pretty formatting to unformatted xml file. */
83
84 SAXBuilder builder = new SAXBuilder();
85 DataFormatFilter format = new DataFormatFilter(echo);
86 format.setIndentStep(4);
87 builder.setXMLFilter(format);
88 InputStream in = FilterTest.class.getResourceAsStream("test1.xml");
89
90 System.out.println(" -- test1.xml unfiltered -- \n");
91 Document doc = builder.build(in);
92
93 System.out.println(" -- test1.xml filtered by DataFormatFilter --\n");
94 XMLOutputter outputter = new XMLOutputter();
95 outputter.output(doc, System.out);
96
97 System.out.println("\n");
98
99 /* Remove pretty formatting from formatted xml file. */
100
101 builder = new SAXBuilder();
102 builder.setXMLFilter( new DataUnformatFilter(echo) );
103 in = FilterTest.class.getResourceAsStream("test2.xml");
104
105 System.out.println(" -- test2.xml unfiltered --\n");
106 doc = builder.build(in);
107
108 System.out.println(" -- test2.xml filtered by DataUnformatFilter --\n");
109 outputter = new XMLOutputter();
110 outputter.output(doc, System.out);
111
112 System.out.println("\n");
113 }
114
115 }
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53 package sax;
54
55 import java.io.InputStream;
56 import java.io.StringReader;
57 import java.io.StringWriter;
58
59 import org.xml.sax.InputSource;
60 import org.xml.sax.XMLReader;
61
62 import org.jdom.Document;
63 import org.jdom.input.SAXBuilder;
64 import org.jdom.output.XMLOutputter;
65
66 /**
67 * Tests DocumentReader
68 *
69 * @author joe.bowbeer
70 */
71 @SuppressWarnings("javadoc")
72 public class ReaderTest {
73
74 /** Creates new ReaderTest */
75 public ReaderTest() {
76 }
77
78 /**
79 * @param args the command line arguments
80 */
81 public static void main (String args[]) throws Exception {
82
83 /* XMLWriter for viewing SAX events. */
84
85 XMLWriter echo = new XMLWriter();
86
87 /* Build document from xml file. */
88
89 SAXBuilder builder = new SAXBuilder();
90 builder.setXMLFilter(echo);
91 InputStream in = FilterTest.class.getResourceAsStream("test2.xml");
92
93 System.out.println(" -- SAXBuilder(test2.xml), echo by XMLWriter -- \n");
94 Document doc = builder.build(in);
95
96 System.out.println(" -- DocumentReader(doc) output by XMLWriter --\n");
97 XMLReader parser = new DocumentReader(doc);
98 echo.setParent(parser);
99 StringWriter writer = new StringWriter();
100 parser = new XMLWriter(echo, writer);
101 parser.parse((InputSource)null);
102
103 /* Reconstitute document from regurgitated string. */
104
105 builder = new SAXBuilder();
106 builder.setXMLFilter(echo);
107 String xml = writer.toString();
108
109 System.out.println(" -- xml string--\n");
110 doc = builder.build(new StringReader(xml));
111
112 System.out.println(" -- SAXBuilder(xml) output by XMLOutputter --\n");
113 XMLOutputter outputter = new XMLOutputter();
114 outputter.output(doc, System.out);
115
116 System.out.println("\n");
117 }
118
119 }
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53 package sax;
54
55 import java.io.IOException;
56
57 import org.xml.sax.Attributes;
58 import org.xml.sax.InputSource;
59 import org.xml.sax.SAXException;
60 import org.xml.sax.SAXNotRecognizedException;
61 import org.xml.sax.SAXNotSupportedException;
62 import org.xml.sax.XMLReader;
63 import org.xml.sax.ext.LexicalHandler;
64 import org.xml.sax.helpers.AttributesImpl;
65 import org.xml.sax.helpers.XMLFilterImpl;
66
67 /**
68 * Adds convenience methods and lexical event filtering to base
69 * SAX2 Filter implementation.
70 *
71 * <i>Code and comments adapted from XMLWriter-0.2, written
72 * by David Megginson and released into the public domain,
73 * without warranty.</i>
74 *
75 * <p>The convenience methods are provided so that clients do not have to
76 * create empty attribute lists or provide empty strings as parameters;
77 * for example, the method invocation</p>
78 *
79 * <pre>
80 * w.startElement("foo");
81 * </pre>
82 *
83 * <p>is equivalent to the regular SAX2 ContentHandler method</p>
84 *
85 * <pre>
86 * w.startElement("", "foo", "", new AttributesImpl());
87 * </pre>
88 *
89 * <p>Except that it is more efficient because it does not allocate
90 * a new empty attribute list each time.</p>
91 *
92 * <p>In fact, there is an even simpler convenience method,
93 * <var>dataElement</var>, designed for writing elements that
94 * contain only character data.</p>
95 *
96 * <pre>
97 * w.dataElement("greeting", "Hello, world!");
98 * </pre>
99 *
100 * <p>is equivalent to</p>
101 *
102 * <pre>
103 * w.startElement("greeting");
104 * w.characters("Hello, world!");
105 * w.endElement("greeting");
106 * </pre>
107 *
108 * @see org.xml.sax.helpers.XMLFilterImpl
109 */
110 @SuppressWarnings("javadoc")
111 public class XMLFilterBase extends XMLFilterImpl implements LexicalHandler
112 {
113
114
115 ////////////////////////////////////////////////////////////////////
116 // Constructors.
117 ////////////////////////////////////////////////////////////////////
118
119
120 /**
121 * Construct an XML filter with no parent.
122 *
123 * <p>This filter will have no parent: you must assign a parent
124 * before you start a parse or do any configuration with
125 * setFeature or setProperty.</p>
126 *
127 * @see org.xml.sax.XMLReader#setFeature
128 * @see org.xml.sax.XMLReader#setProperty
129 */
130 public XMLFilterBase()
131 {
132 }
133
134
135 /**
136 * Create an XML filter with the specified parent.
137 *
138 * <p>Use the XMLReader provided as the source of events.</p>
139 *
140 * @param xmlreader The parent in the filter chain.
141 */
142 public XMLFilterBase(XMLReader parent)
143 {
144 super(parent);
145 }
146
147
148
149 ////////////////////////////////////////////////////////////////////
150 // Convenience methods.
151 ////////////////////////////////////////////////////////////////////
152
153
154 /**
155 * Start a new element without a qname or attributes.
156 *
157 * <p>This method will provide a default empty attribute
158 * list and an empty string for the qualified name. It invokes
159 * {@link #startElement(String, String, String, Attributes)}
160 * directly.</p>
161 *
162 * @param uri The element's Namespace URI.
163 * @param localName The element's local name.
164 * @exception org.xml.sax.SAXException If a filter
165 * further down the chain raises an exception.
166 * @see org.xml.sax.ContentHandler#startElement
167 */
168 public void startElement (String uri, String localName)
169 throws SAXException
170 {
171 startElement(uri, localName, "", EMPTY_ATTS);
172 }
173
174
175 /**
176 * Start a new element without a Namespace URI or qname.
177 *
178 * <p>This method will provide an empty string for the
179 * Namespace URI, and empty string for the qualified name.
180 * It invokes
181 * {@link #startElement(String, String, String, Attributes)}
182 * directly.</p>
183 *
184 * @param localName The element's local name.
185 * @param atts The element's attribute list.
186 * @exception org.xml.sax.SAXException If a filter
187 * further down the chain raises an exception.
188 * @see org.xml.sax.ContentHandler#startElement
189 */
190 public void startElement (String localName, Attributes atts)
191 throws SAXException
192 {
193 startElement("", localName, "", atts);
194 }
195
196
197 /**
198 * Start a new element without a Namespace URI, qname, or attributes.
199 *
200 * <p>This method will provide an empty string for the
201 * Namespace URI, and empty string for the qualified name,
202 * and a default empty attribute list. It invokes
203 * {@link #startElement(String, String, String, Attributes)}
204 * directly.</p>
205 *
206 * @param localName The element's local name.
207 * @exception org.xml.sax.SAXException If a filter
208 * further down the chain raises an exception.
209 * @see org.xml.sax.ContentHandler#startElement
210 */
211 public void startElement (String localName)
212 throws SAXException
213 {
214 startElement("", localName, "", EMPTY_ATTS);
215 }
216
217
218 /**
219 * End an element without a qname.
220 *
221 * <p>This method will supply an empty string for the qName.
222 * It invokes {@link #endElement(String, String, String)}
223 * directly.</p>
224 *
225 * @param uri The element's Namespace URI.
226 * @param localName The element's local name.
227 * @exception org.xml.sax.SAXException If a filter
228 * further down the chain raises an exception.
229 * @see org.xml.sax.ContentHandler#endElement
230 */
231 public void endElement (String uri, String localName)
232 throws SAXException
233 {
234 endElement(uri, localName, "");
235 }
236
237
238 /**
239 * End an element without a Namespace URI or qname.
240 *
241 * <p>This method will supply an empty string for the qName
242 * and an empty string for the Namespace URI.
243 * It invokes {@link #endElement(String, String, String)}
244 * directly.</p>
245 *
246 * @param localName The element's local name.
247 * @exception org.xml.sax.SAXException If a filter
248 * further down the chain raises an exception.
249 * @see org.xml.sax.ContentHandler#endElement
250 */
251 public void endElement (String localName)
252 throws SAXException
253 {
254 endElement("", localName, "");
255 }
256
257
258 /**
259 * Add an empty element.
260 *
261 * Both a {@link #startElement startElement} and an
262 * {@link #endElement endElement} event will be passed on down
263 * the filter chain.
264 *
265 * @param uri The element's Namespace URI, or the empty string
266 * if the element has no Namespace or if Namespace
267 * processing is not being performed.
268 * @param localName The element's local name (without prefix). This
269 * parameter must be provided.
270 * @param qName The element's qualified name (with prefix), or
271 * the empty string if none is available. This parameter
272 * is strictly advisory: the writer may or may not use
273 * the prefix attached.
274 * @param atts The element's attribute list.
275 * @exception org.xml.sax.SAXException If a filter
276 * further down the chain raises an exception.
277 * @see org.xml.sax.ContentHandler#startElement
278 * @see org.xml.sax.ContentHandler#endElement
279 */
280 public void emptyElement (String uri, String localName,
281 String qName, Attributes atts)
282 throws SAXException
283 {
284 startElement(uri, localName, qName, atts);
285 endElement(uri, localName, qName);
286 }
287
288
289 /**
290 * Add an empty element without a qname or attributes.
291 *
292 * <p>This method will supply an empty string for the qname
293 * and an empty attribute list. It invokes
294 * {@link #emptyElement(String, String, String, Attributes)}
295 * directly.</p>
296 *
297 * @param uri The element's Namespace URI.
298 * @param localName The element's local name.
299 * @exception org.xml.sax.SAXException If a filter
300 * further down the chain raises an exception.
301 * @see #emptyElement(String, String, String, Attributes)
302 */
303 public void emptyElement (String uri, String localName)
304 throws SAXException
305 {
306 emptyElement(uri, localName, "", EMPTY_ATTS);
307 }
308
309
310 /**
311 * Add an empty element without a Namespace URI or qname.
312 *
313 * <p>This method will provide an empty string for the
314 * Namespace URI, and empty string for the qualified name.
315 * It invokes
316 * {@link #emptyElement(String, String, String, Attributes)}
317 * directly.</p>
318 *
319 * @param localName The element's local name.
320 * @param atts The element's attribute list.
321 * @exception org.xml.sax.SAXException If a filter
322 * further down the chain raises an exception.
323 * @see org.xml.sax.ContentHandler#startElement
324 */
325 public void emptyElement (String localName, Attributes atts)
326 throws SAXException
327 {
328 emptyElement("", localName, "", atts);
329 }
330
331
332 /**
333 * Add an empty element without a Namespace URI, qname or attributes.
334 *
335 * <p>This method will supply an empty string for the qname,
336 * and empty string for the Namespace URI, and an empty
337 * attribute list. It invokes
338 * {@link #emptyElement(String, String, String, Attributes)}
339 * directly.</p>
340 *
341 * @param localName The element's local name.
342 * @exception org.xml.sax.SAXException If a filter
343 * further down the chain raises an exception.
344 * @see #emptyElement(String, String, String, Attributes)
345 */
346 public void emptyElement (String localName)
347 throws SAXException
348 {
349 emptyElement("", localName, "", EMPTY_ATTS);
350 }
351
352
353 /**
354 * Add an element with character data content.
355 *
356 * <p>This is a convenience method to add a complete element
357 * with character data content, including the start tag
358 * and end tag.</p>
359 *
360 * <p>This method invokes
361 * {@link @see org.xml.sax.ContentHandler#startElement},
362 * followed by
363 * {@link #characters(String)}, followed by
364 * {@link @see org.xml.sax.ContentHandler#endElement}.</p>
365 *
366 * @param uri The element's Namespace URI.
367 * @param localName The element's local name.
368 * @param qName The element's default qualified name.
369 * @param atts The element's attributes.
370 * @param content The character data content.
371 * @exception org.xml.sax.SAXException If a filter
372 * further down the chain raises an exception.
373 * @see org.xml.sax.ContentHandler#startElement
374 * @see #characters(String)
375 * @see org.xml.sax.ContentHandler#endElement
376 */
377 public void dataElement (String uri, String localName,
378 String qName, Attributes atts,
379 String content)
380 throws SAXException
381 {
382 startElement(uri, localName, qName, atts);
383 characters(content);
384 endElement(uri, localName, qName);
385 }
386
387
388 /**
389 * Add an element with character data content but no qname or attributes.
390 *
391 * <p>This is a convenience method to add a complete element
392 * with character data content, including the start tag
393 * and end tag. This method provides an empty string
394 * for the qname and an empty attribute list. It invokes
395 * {@link #dataElement(String, String, String, Attributes, String)}}
396 * directly.</p>
397 *
398 * @param uri The element's Namespace URI.
399 * @param localName The element's local name.
400 * @param content The character data content.
401 * @exception org.xml.sax.SAXException If a filter
402 * further down the chain raises an exception.
403 * @see org.xml.sax.ContentHandler#startElement
404 * @see #characters(String)
405 * @see org.xml.sax.ContentHandler#endElement
406 */
407 public void dataElement (String uri, String localName, String content)
408 throws SAXException
409 {
410 dataElement(uri, localName, "", EMPTY_ATTS, content);
411 }
412
413
414 /**
415 * Add an element with character data content but no Namespace URI or qname.
416 *
417 * <p>This is a convenience method to add a complete element
418 * with character data content, including the start tag
419 * and end tag. The method provides an empty string for the
420 * Namespace URI, and empty string for the qualified name. It invokes
421 * {@link #dataElement(String, String, String, Attributes, String)}}
422 * directly.</p>
423 *
424 * @param localName The element's local name.
425 * @param atts The element's attributes.
426 * @param content The character data content.
427 * @exception org.xml.sax.SAXException If a filter
428 * further down the chain raises an exception.
429 * @see org.xml.sax.ContentHandler#startElement
430 * @see #characters(String)
431 * @see org.xml.sax.ContentHandler#endElement
432 */
433 public void dataElement (String localName, Attributes atts, String content)
434 throws SAXException
435 {
436 dataElement("", localName, "", atts, content);
437 }
438
439
440 /**
441 * Add an element with character data content but no attributes
442 * or Namespace URI.
443 *
444 * <p>This is a convenience method to add a complete element
445 * with character data content, including the start tag
446 * and end tag. The method provides an empty string for the
447 * Namespace URI, and empty string for the qualified name,
448 * and an empty attribute list. It invokes
449 * {@link #dataElement(String, String, String, Attributes, String)}}
450 * directly.</p>
451 *
452 * @param localName The element's local name.
453 * @param content The character data content.
454 * @exception org.xml.sax.SAXException If a filter
455 * further down the chain raises an exception.
456 * @see org.xml.sax.ContentHandler#startElement
457 * @see #characters(String)
458 * @see org.xml.sax.ContentHandler#endElement
459 */
460 public void dataElement (String localName, String content)
461 throws SAXException
462 {
463 dataElement("", localName, "", EMPTY_ATTS, content);
464 }
465
466
467 /**
468 * Add a string of character data, with XML escaping.
469 *
470 * <p>This is a convenience method that takes an XML
471 * String, converts it to a character array, then invokes
472 * {@link @see org.xml.sax.ContentHandler#characters}.</p>
473 *
474 * @param data The character data.
475 * @exception org.xml.sax.SAXException If a filter
476 * further down the chain raises an exception.
477 * @see @see org.xml.sax.ContentHandler#characters
478 */
479 public void characters (String data)
480 throws SAXException
481 {
482 char ch[] = data.toCharArray();
483 characters(ch, 0, ch.length);
484 }
485
486
487
488 ////////////////////////////////////////////////////////////////////
489 // Override org.xml.sax.helpers.XMLFilterImpl methods.
490 ////////////////////////////////////////////////////////////////////
491
492
493 /**
494 * Set the value of a property.
495 *
496 * <p>This will always fail if the parent is null.</p>
497 *
498 * @param name The property name.
499 * @param state The requested property value.
500 * @exception org.xml.sax.SAXNotRecognizedException When the
501 * XMLReader does not recognize the property name.
502 * @exception org.xml.sax.SAXNotSupportedException When the
503 * XMLReader recognizes the property name but
504 * cannot set the requested value.
505 * @see org.xml.sax.XMLReader#setProperty
506 */
507 @Override
508 public void setProperty (String name, Object value)
509 throws SAXNotRecognizedException, SAXNotSupportedException
510 {
511 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) {
512 if (LEXICAL_HANDLER_NAMES[i].equals(name)) {
513 setLexicalHandler((LexicalHandler) value);
514 return;
515 }
516 }
517 super.setProperty(name, value);
518 }
519
520
521 /**
522 * Look up the value of a property.
523 *
524 * @param name The property name.
525 * @return The current value of the property.
526 * @exception org.xml.sax.SAXNotRecognizedException When the
527 * XMLReader does not recognize the feature name.
528 * @exception org.xml.sax.SAXNotSupportedException When the
529 * XMLReader recognizes the property name but
530 * cannot determine its value at this time.
531 * @see org.xml.sax.XMLReader#setFeature
532 */
533 @Override
534 public Object getProperty (String name)
535 throws SAXNotRecognizedException, SAXNotSupportedException
536 {
537 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) {
538 if (LEXICAL_HANDLER_NAMES[i].equals(name)) {
539 return getLexicalHandler();
540 }
541 }
542 return super.getProperty(name);
543 }
544
545
546 /**
547 * Parse a document.
548 *
549 * @param input The input source for the document entity.
550 * @exception org.xml.sax.SAXException Any SAX exception, possibly
551 * wrapping another exception.
552 * @exception java.io.IOException An IO exception from the parser,
553 * possibly from a byte stream or character stream
554 * supplied by the application.
555 * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource)
556 */
557 @Override
558 public void parse (InputSource input)
559 throws SAXException, IOException
560 {
561 installLexicalHandler();
562 super.parse(input);
563 }
564
565
566
567 ////////////////////////////////////////////////////////////////////
568 // Registration of org.xml.sax.ext.LexicalHandler.
569 ////////////////////////////////////////////////////////////////////
570
571
572 /**
573 * Set the lexical handler.
574 *
575 * @param handler The new lexical handler.
576 * @exception java.lang.NullPointerException If the handler
577 * is null.
578 */
579 public void setLexicalHandler (LexicalHandler handler)
580 {
581 if (handler == null) {
582 throw new NullPointerException("Null lexical handler");
583 }
584 lexicalHandler = handler;
585 }
586
587
588 /**
589 * Get the current lexical handler.
590 *
591 * @return The current lexical handler, or null if none was set.
592 */
593 public LexicalHandler getLexicalHandler ()
594 {
595 return lexicalHandler;
596 }
597
598
599
600 ////////////////////////////////////////////////////////////////////
601 // Implementation of org.xml.sax.ext.LexicalHandler.
602 ////////////////////////////////////////////////////////////////////
603
604
605 /**
606 * Filter a start DTD event.
607 *
608 * @param name The document type name.
609 * @param publicId The declared public identifier for the
610 * external DTD subset, or null if none was declared.
611 * @param systemId The declared system identifier for the
612 * external DTD subset, or null if none was declared.
613 * @exception org.xml.sax.SAXException If a filter
614 * further down the chain raises an exception.
615 * @see org.xml.sax.ext.LexicalHandler#startDTD
616 */
617 @Override
618 public void startDTD(String name, String publicId, String systemId)
619 throws SAXException {
620 if (lexicalHandler != null) {
621 lexicalHandler.startDTD(name, publicId, systemId);
622 }
623 }
624
625
626 /**
627 * Filter a end DTD event.
628 *
629 * @exception org.xml.sax.SAXException If a filter
630 * further down the chain raises an exception.
631 * @see org.xml.sax.ext.LexicalHandler#endDTD
632 */
633 @Override
634 public void endDTD()
635 throws SAXException {
636 if (lexicalHandler != null) {
637 lexicalHandler.endDTD();
638 }
639 }
640
641
642 /*
643 * Filter a start entity event.
644 *
645 * @param name The name of the entity. If it is a parameter
646 * entity, the name will begin with '%', and if it is the
647 * external DTD subset, it will be "[dtd]".
648 * @exception org.xml.sax.SAXException If a filter
649 * further down the chain raises an exception.
650 * @see org.xml.sax.ext.LexicalHandler#startEntity
651 */
652 @Override
653 public void startEntity(String name)
654 throws SAXException {
655 if (lexicalHandler != null) {
656 lexicalHandler.startEntity(name);
657 }
658 }
659
660
661 /*
662 * Filter a end entity event.
663 *
664 * @param name The name of the entity that is ending.
665 * @exception org.xml.sax.SAXException If a filter
666 * further down the chain raises an exception.
667 * @see org.xml.sax.ext.LexicalHandler#endEntity
668 */
669 @Override
670 public void endEntity(String name)
671 throws SAXException {
672 if (lexicalHandler != null) {
673 lexicalHandler.endEntity(name);
674 }
675 }
676
677
678 /*
679 * Filter a start CDATA event.
680 *
681 * @exception org.xml.sax.SAXException If a filter
682 * further down the chain raises an exception.
683 * @see org.xml.sax.ext.LexicalHandler#startCDATA
684 */
685 @Override
686 public void startCDATA()
687 throws SAXException {
688 if (lexicalHandler != null) {
689 lexicalHandler.startCDATA();
690 }
691 }
692
693
694 /*
695 * Filter a end CDATA event.
696 *
697 * @exception org.xml.sax.SAXException If a filter
698 * further down the chain raises an exception.
699 * @see org.xml.sax.ext.LexicalHandler#endCDATA
700 */
701 @Override
702 public void endCDATA()
703 throws SAXException {
704 if (lexicalHandler != null) {
705 lexicalHandler.endCDATA();
706 }
707 }
708
709
710 /*
711 * Filter a comment event.
712 *
713 * @param ch An array holding the characters in the comment.
714 * @param start The starting position in the array.
715 * @param length The number of characters to use from the array.
716 * @exception org.xml.sax.SAXException If a filter
717 * further down the chain raises an exception.
718 * @see org.xml.sax.ext.LexicalHandler#comment
719 */
720 @Override
721 public void comment(char[] ch, int start, int length)
722 throws SAXException {
723 if (lexicalHandler != null) {
724 lexicalHandler.comment(ch, start, length);
725 }
726 }
727
728
729
730 ////////////////////////////////////////////////////////////////////
731 // Internal methods.
732 ////////////////////////////////////////////////////////////////////
733
734
735 /**
736 * Installs lexical handler before a parse.
737 *
738 * <p>Before every parse, check whether the parent is
739 * non-null, and re-register the filter for the lexical
740 * events.</p>
741 */
742 private void installLexicalHandler ()
743 {
744 XMLReader parent = getParent();
745 if (parent == null) {
746 throw new NullPointerException("No parent for filter");
747 }
748 // try to register for lexical events
749 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) {
750 try {
751 parent.setProperty(LEXICAL_HANDLER_NAMES[i], this);
752 break;
753 }
754 catch (SAXNotRecognizedException ex) {
755 // ignore
756 }
757 catch (SAXNotSupportedException ex) {
758 // ignore
759 }
760 }
761 }
762
763
764
765 ////////////////////////////////////////////////////////////////////
766 // Internal state.
767 ////////////////////////////////////////////////////////////////////
768
769
770 private LexicalHandler lexicalHandler = null;
771
772
773
774 ////////////////////////////////////////////////////////////////////
775 // Constants.
776 ////////////////////////////////////////////////////////////////////
777
778
779 protected static final Attributes EMPTY_ATTS = new AttributesImpl();
780
781 protected static final String[] LEXICAL_HANDLER_NAMES = {
782 "http://xml.org/sax/properties/lexical-handler",
783 "http://xml.org/sax/handlers/LexicalHandler"
784 };
785
786
787 }
788
789 // end of XMLFilterBase.java
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53 package sax;
54
55 import java.io.IOException;
56
57 import org.xml.sax.Attributes;
58 import org.xml.sax.ContentHandler;
59 import org.xml.sax.DTDHandler;
60 import org.xml.sax.EntityResolver;
61 import org.xml.sax.ErrorHandler;
62 import org.xml.sax.InputSource;
63 import org.xml.sax.Locator;
64 import org.xml.sax.SAXException;
65 import org.xml.sax.SAXParseException;
66 import org.xml.sax.SAXNotSupportedException;
67 import org.xml.sax.SAXNotRecognizedException;
68 import org.xml.sax.XMLReader;
69 import org.xml.sax.ext.LexicalHandler;
70 import org.xml.sax.helpers.AttributesImpl;
71 import org.xml.sax.helpers.DefaultHandler;
72
73
74 /**
75 * Base class for implementing an XML reader.
76 *
77 * Adapted from David Megginson's XMLFilterImpl and XMLFilterBase.
78 */
79 @SuppressWarnings("javadoc")
80 public abstract class XMLReaderBase extends DefaultHandler
81 implements LexicalHandler, XMLReader
82 {
83
84 ////////////////////////////////////////////////////////////////////
85 // Constructors.
86 ////////////////////////////////////////////////////////////////////
87
88
89 /**
90 * Creates new XMLReaderBase.
91 */
92 public XMLReaderBase ()
93 {
94 }
95
96
97 ////////////////////////////////////////////////////////////////////
98 // Convenience methods.
99 ////////////////////////////////////////////////////////////////////
100
101
102 /**
103 * Start a new element without a qname or attributes.
104 *
105 * <p>This method will provide a default empty attribute
106 * list and an empty string for the qualified name. It invokes
107 * {@link #startElement(String, String, String, Attributes)}
108 * directly.</p>
109 *
110 * @param uri The element's Namespace URI.
111 * @param localName The element's local name.
112 * @exception org.xml.sax.SAXException If a filter
113 * further down the chain raises an exception.
114 * @see org.xml.sax.ContentHandler#startElement
115 */
116 public void startElement (String uri, String localName)
117 throws SAXException
118 {
119 startElement(uri, localName, "", EMPTY_ATTS);
120 }
121
122
123 /**
124 * Start a new element without a Namespace URI or qname.
125 *
126 * <p>This method will provide an empty string for the
127 * Namespace URI, and empty string for the qualified name.
128 * It invokes
129 * {@link #startElement(String, String, String, Attributes)}
130 * directly.</p>
131 *
132 * @param localName The element's local name.
133 * @param atts The element's attribute list.
134 * @exception org.xml.sax.SAXException If a filter
135 * further down the chain raises an exception.
136 * @see org.xml.sax.ContentHandler#startElement
137 */
138 public void startElement (String localName, Attributes atts)
139 throws SAXException
140 {
141 startElement("", localName, "", atts);
142 }
143
144
145 /**
146 * Start a new element without a Namespace URI, qname, or attributes.
147 *
148 * <p>This method will provide an empty string for the
149 * Namespace URI, and empty string for the qualified name,
150 * and a default empty attribute list. It invokes
151 * {@link #startElement(String, String, String, Attributes)}
152 * directly.</p>
153 *
154 * @param localName The element's local name.
155 * @exception org.xml.sax.SAXException If a filter
156 * further down the chain raises an exception.
157 * @see org.xml.sax.ContentHandler#startElement
158 */
159 public void startElement (String localName)
160 throws SAXException
161 {
162 startElement("", localName, "", EMPTY_ATTS);
163 }
164
165
166 /**
167 * End an element without a qname.
168 *
169 * <p>This method will supply an empty string for the qName.
170 * It invokes {@link #endElement(String, String, String)}
171 * directly.</p>
172 *
173 * @param uri The element's Namespace URI.
174 * @param localName The element's local name.
175 * @exception org.xml.sax.SAXException If a filter
176 * further down the chain raises an exception.
177 * @see org.xml.sax.ContentHandler#endElement
178 */
179 public void endElement (String uri, String localName)
180 throws SAXException
181 {
182 endElement(uri, localName, "");
183 }
184
185
186 /**
187 * End an element without a Namespace URI or qname.
188 *
189 * <p>This method will supply an empty string for the qName
190 * and an empty string for the Namespace URI.
191 * It invokes {@link #endElement(String, String, String)}
192 * directly.</p>
193 *
194 * @param localName The element's local name.
195 * @exception org.xml.sax.SAXException If a filter
196 * further down the chain raises an exception.
197 * @see org.xml.sax.ContentHandler#endElement
198 */
199 public void endElement (String localName)
200 throws SAXException
201 {
202 endElement("", localName, "");
203 }
204
205
206 /**
207 * Add an empty element.
208 *
209 * Both a {@link #startElement startElement} and an
210 * {@link #endElement endElement} event will be passed on down
211 * the filter chain.
212 *
213 * @param uri The element's Namespace URI, or the empty string
214 * if the element has no Namespace or if Namespace
215 * processing is not being performed.
216 * @param localName The element's local name (without prefix). This
217 * parameter must be provided.
218 * @param qName The element's qualified name (with prefix), or
219 * the empty string if none is available. This parameter
220 * is strictly advisory: the writer may or may not use
221 * the prefix attached.
222 * @param atts The element's attribute list.
223 * @exception org.xml.sax.SAXException If a filter
224 * further down the chain raises an exception.
225 * @see org.xml.sax.ContentHandler#startElement
226 * @see org.xml.sax.ContentHandler#endElement
227 */
228 public void emptyElement (String uri, String localName,
229 String qName, Attributes atts)
230 throws SAXException
231 {
232 startElement(uri, localName, qName, atts);
233 endElement(uri, localName, qName);
234 }
235
236
237 /**
238 * Add an empty element without a qname or attributes.
239 *
240 * <p>This method will supply an empty string for the qname
241 * and an empty attribute list. It invokes
242 * {@link #emptyElement(String, String, String, Attributes)}
243 * directly.</p>
244 *
245 * @param uri The element's Namespace URI.
246 * @param localName The element's local name.
247 * @exception org.xml.sax.SAXException If a filter
248 * further down the chain raises an exception.
249 * @see #emptyElement(String, String, String, Attributes)
250 */
251 public void emptyElement (String uri, String localName)
252 throws SAXException
253 {
254 emptyElement(uri, localName, "", EMPTY_ATTS);
255 }
256
257
258 /**
259 * Add an empty element without a Namespace URI or qname.
260 *
261 * <p>This method will provide an empty string for the
262 * Namespace URI, and empty string for the qualified name.
263 * It invokes
264 * {@link #emptyElement(String, String, String, Attributes)}
265 * directly.</p>
266 *
267 * @param localName The element's local name.
268 * @param atts The element's attribute list.
269 * @exception org.xml.sax.SAXException If a filter
270 * further down the chain raises an exception.
271 * @see org.xml.sax.ContentHandler#startElement
272 */
273 public void emptyElement (String localName, Attributes atts)
274 throws SAXException
275 {
276 emptyElement("", localName, "", atts);
277 }
278
279
280 /**
281 * Add an empty element without a Namespace URI, qname or attributes.
282 *
283 * <p>This method will supply an empty string for the qname,
284 * and empty string for the Namespace URI, and an empty
285 * attribute list. It invokes
286 * {@link #emptyElement(String, String, String, Attributes)}
287 * directly.</p>
288 *
289 * @param localName The element's local name.
290 * @exception org.xml.sax.SAXException If a filter
291 * further down the chain raises an exception.
292 * @see #emptyElement(String, String, String, Attributes)
293 */
294 public void emptyElement (String localName)
295 throws SAXException
296 {
297 emptyElement("", localName, "", EMPTY_ATTS);
298 }
299
300
301 /**
302 * Add an element with character data content.
303 *
304 * <p>This is a convenience method to add a complete element
305 * with character data content, including the start tag
306 * and end tag.</p>
307 *
308 * <p>This method invokes
309 * {@link @see org.xml.sax.ContentHandler#startElement},
310 * followed by
311 * {@link #characters(String)}, followed by
312 * {@link @see org.xml.sax.ContentHandler#endElement}.</p>
313 *
314 * @param uri The element's Namespace URI.
315 * @param localName The element's local name.
316 * @param qName The element's default qualified name.
317 * @param atts The element's attributes.
318 * @param content The character data content.
319 * @exception org.xml.sax.SAXException If a filter
320 * further down the chain raises an exception.
321 * @see org.xml.sax.ContentHandler#startElement
322 * @see #characters(String)
323 * @see org.xml.sax.ContentHandler#endElement
324 */
325 public void dataElement (String uri, String localName,
326 String qName, Attributes atts,
327 String content)
328 throws SAXException
329 {
330 startElement(uri, localName, qName, atts);
331 characters(content);
332 endElement(uri, localName, qName);
333 }
334
335
336 /**
337 * Add an element with character data content but no qname or attributes.
338 *
339 * <p>This is a convenience method to add a complete element
340 * with character data content, including the start tag
341 * and end tag. This method provides an empty string
342 * for the qname and an empty attribute list. It invokes
343 * {@link #dataElement(String, String, String, Attributes, String)}}
344 * directly.</p>
345 *
346 * @param uri The element's Namespace URI.
347 * @param localName The element's local name.
348 * @param content The character data content.
349 * @exception org.xml.sax.SAXException If a filter
350 * further down the chain raises an exception.
351 * @see org.xml.sax.ContentHandler#startElement
352 * @see #characters(String)
353 * @see org.xml.sax.ContentHandler#endElement
354 */
355 public void dataElement (String uri, String localName, String content)
356 throws SAXException
357 {
358 dataElement(uri, localName, "", EMPTY_ATTS, content);
359 }
360
361
362 /**
363 * Add an element with character data content but no Namespace URI or qname.
364 *
365 * <p>This is a convenience method to add a complete element
366 * with character data content, including the start tag
367 * and end tag. The method provides an empty string for the
368 * Namespace URI, and empty string for the qualified name. It invokes
369 * {@link #dataElement(String, String, String, Attributes, String)}}
370 * directly.</p>
371 *
372 * @param localName The element's local name.
373 * @param atts The element's attributes.
374 * @param content The character data content.
375 * @exception org.xml.sax.SAXException If a filter
376 * further down the chain raises an exception.
377 * @see org.xml.sax.ContentHandler#startElement
378 * @see #characters(String)
379 * @see org.xml.sax.ContentHandler#endElement
380 */
381 public void dataElement (String localName, Attributes atts, String content)
382 throws SAXException
383 {
384 dataElement("", localName, "", atts, content);
385 }
386
387
388 /**
389 * Add an element with character data content but no attributes
390 * or Namespace URI.
391 *
392 * <p>This is a convenience method to add a complete element
393 * with character data content, including the start tag
394 * and end tag. The method provides an empty string for the
395 * Namespace URI, and empty string for the qualified name,
396 * and an empty attribute list. It invokes
397 * {@link #dataElement(String, String, String, Attributes, String)}}
398 * directly.</p>
399 *
400 * @param localName The element's local name.
401 * @param content The character data content.
402 * @exception org.xml.sax.SAXException If a filter
403 * further down the chain raises an exception.
404 * @see org.xml.sax.ContentHandler#startElement
405 * @see #characters(String)
406 * @see org.xml.sax.ContentHandler#endElement
407 */
408 public void dataElement (String localName, String content)
409 throws SAXException
410 {
411 dataElement("", localName, "", EMPTY_ATTS, content);
412 }
413
414
415 /**
416 * Add a string of character data, with XML escaping.
417 *
418 * <p>This is a convenience method that takes an XML
419 * String, converts it to a character array, then invokes
420 * {@link @see org.xml.sax.ContentHandler#characters}.</p>
421 *
422 * @param data The character data.
423 * @exception org.xml.sax.SAXException If a filter
424 * further down the chain raises an exception.
425 * @see @see org.xml.sax.ContentHandler#characters
426 */
427 public void characters (String data)
428 throws SAXException
429 {
430 char ch[] = data.toCharArray();
431 characters(ch, 0, ch.length);
432 }
433
434
435
436 ////////////////////////////////////////////////////////////////////
437 // Implementation of org.xml.sax.XMLReader.
438 ////////////////////////////////////////////////////////////////////
439
440
441 /**
442 * Set the state of a feature.
443 *
444 * <p>This will always fail.</p>
445 *
446 * @param name The feature name.
447 * @param state The requested feature state.
448 * @exception org.xml.sax.SAXNotRecognizedException When the
449 * XMLReader does not recognize the feature name.
450 * @exception org.xml.sax.SAXNotSupportedException When the
451 * XMLReader recognizes the feature name but
452 * cannot set the requested value.
453 * @see org.xml.sax.XMLReader#setFeature
454 */
455 @Override
456 public void setFeature (String name, boolean state)
457 throws SAXNotRecognizedException, SAXNotSupportedException
458 {
459 throw new SAXNotRecognizedException("Feature: " + name);
460 }
461
462
463 /**
464 * Look up the state of a feature.
465 *
466 * <p>This will always fail.</p>
467 *
468 * @param name The feature name.
469 * @return The current state of the feature.
470 * @exception org.xml.sax.SAXNotRecognizedException When the
471 * XMLReader does not recognize the feature name.
472 * @exception org.xml.sax.SAXNotSupportedException When the
473 * XMLReader recognizes the feature name but
474 * cannot determine its state at this time.
475 * @see org.xml.sax.XMLReader#getFeature
476 */
477 @Override
478 public boolean getFeature (String name)
479 throws SAXNotRecognizedException, SAXNotSupportedException
480 {
481 throw new SAXNotRecognizedException("Feature: " + name);
482 }
483
484
485 /**
486 * Set the value of a property.
487 *
488 * <p>Only lexical-handler properties are recognized.</p>
489 *
490 * @param name The property name.
491 * @param state The requested property value.
492 * @exception org.xml.sax.SAXNotRecognizedException When the
493 * XMLReader does not recognize the property name.
494 * @exception org.xml.sax.SAXNotSupportedException When the
495 * XMLReader recognizes the property name but
496 * cannot set the requested value.
497 * @see org.xml.sax.XMLReader#setProperty
498 */
499 @Override
500 public void setProperty (String name, Object value)
501 throws SAXNotRecognizedException, SAXNotSupportedException
502 {
503 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) {
504 if (LEXICAL_HANDLER_NAMES[i].equals(name)) {
505 setLexicalHandler((LexicalHandler) value);
506 return;
507 }
508 }
509 throw new SAXNotRecognizedException("Property: " + name);
510 }
511
512
513 /**
514 * Look up the value of a property.
515 *
516 * <p>Only lexical-handler properties are recognized.</p>
517 *
518 * @param name The property name.
519 * @return The current value of the property.
520 * @exception org.xml.sax.SAXNotRecognizedException When the
521 * XMLReader does not recognize the feature name.
522 * @exception org.xml.sax.SAXNotSupportedException When the
523 * XMLReader recognizes the property name but
524 * cannot determine its value at this time.
525 * @see org.xml.sax.XMLReader#setFeature
526 */
527 @Override
528 public Object getProperty (String name)
529 throws SAXNotRecognizedException, SAXNotSupportedException
530 {
531 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) {
532 if (LEXICAL_HANDLER_NAMES[i].equals(name)) {
533 return getLexicalHandler();
534 }
535 }
536 throw new SAXNotRecognizedException("Property: " + name);
537 }
538
539
540 /**
541 * Parse a document. Subclass must implement.
542 *
543 * @param input The input source for the document entity.
544 * @exception org.xml.sax.SAXException Any SAX exception, possibly
545 * wrapping another exception.
546 * @exception java.io.IOException An IO exception from the parser,
547 * possibly from a byte stream or character stream
548 * supplied by the application.
549 * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource)
550 */
551 @Override
552 public abstract void parse (InputSource input)
553 throws SAXException, IOException;
554
555
556 /**
557 * Parse a document.
558 *
559 * @param systemId The system identifier as a fully-qualified URI.
560 * @exception org.xml.sax.SAXException Any SAX exception, possibly
561 * wrapping another exception.
562 * @exception java.io.IOException An IO exception from the parser,
563 * possibly from a byte stream or character stream
564 * supplied by the application.
565 * @see org.xml.sax.XMLReader#parse(java.lang.String)
566 */
567 @Override
568 public void parse (String systemId)
569 throws SAXException, IOException
570 {
571 parse(new InputSource(systemId));
572 }
573
574
575 /**
576 * Set the entity resolver.
577 *
578 * @param resolver The new entity resolver.
579 * @exception java.lang.NullPointerException If the resolver
580 * is null.
581 * @see org.xml.sax.XMLReader#setEntityResolver
582 */
583 @Override
584 public void setEntityResolver (EntityResolver resolver)
585 {
586 if (resolver == null) {
587 throw new NullPointerException("Null entity resolver");
588 }
589 entityResolver = resolver;
590 }
591
592
593 /**
594 * Get the current entity resolver.
595 *
596 * @return The current entity resolver, or null if none was set.
597 * @see org.xml.sax.XMLReader#getEntityResolver
598 */
599 @Override
600 public EntityResolver getEntityResolver ()
601 {
602 return entityResolver;
603 }
604
605
606 /**
607 * Set the DTD event handler.
608 *
609 * @param resolver The new DTD handler.
610 * @exception java.lang.NullPointerException If the handler
611 * is null.
612 * @see org.xml.sax.XMLReader#setDTDHandler
613 */
614 @Override
615 public void setDTDHandler (DTDHandler handler)
616 {
617 if (handler == null) {
618 throw new NullPointerException("Null DTD handler");
619 }
620 dtdHandler = handler;
621 }
622
623
624 /**
625 * Get the current DTD event handler.
626 *
627 * @return The current DTD handler, or null if none was set.
628 * @see org.xml.sax.XMLReader#getDTDHandler
629 */
630 @Override
631 public DTDHandler getDTDHandler ()
632 {
633 return dtdHandler;
634 }
635
636
637 /**
638 * Set the content event handler.
639 *
640 * @param resolver The new content handler.
641 * @exception java.lang.NullPointerException If the handler
642 * is null.
643 * @see org.xml.sax.XMLReader#setContentHandler
644 */
645 @Override
646 public void setContentHandler (ContentHandler handler)
647 {
648 if (handler == null) {
649 throw new NullPointerException("Null content handler");
650 }
651 contentHandler = handler;
652 }
653
654
655 /**
656 * Get the content event handler.
657 *
658 * @return The current content handler, or null if none was set.
659 * @see org.xml.sax.XMLReader#getContentHandler
660 */
661 @Override
662 public ContentHandler getContentHandler ()
663 {
664 return contentHandler;
665 }
666
667
668 /**
669 * Set the error event handler.
670 *
671 * @param handle The new error handler.
672 * @exception java.lang.NullPointerException If the handler
673 * is null.
674 * @see org.xml.sax.XMLReader#setErrorHandler
675 */
676 @Override
677 public void setErrorHandler (ErrorHandler handler)
678 {
679 if (handler == null) {
680 throw new NullPointerException("Null error handler");
681 }
682 errorHandler = handler;
683 }
684
685
686 /**
687 * Get the current error event handler.
688 *
689 * @return The current error handler, or null if none was set.
690 * @see org.xml.sax.XMLReader#getErrorHandler
691 */
692 @Override
693 public ErrorHandler getErrorHandler ()
694 {
695 return errorHandler;
696 }
697
698
699
700 ////////////////////////////////////////////////////////////////////
701 // Registration of org.xml.sax.ext.LexicalHandler.
702 ////////////////////////////////////////////////////////////////////
703
704
705 /**
706 * Set the lexical handler.
707 *
708 * @param handler The new lexical handler.
709 * @exception java.lang.NullPointerException If the handler
710 * is null.
711 */
712 public void setLexicalHandler (LexicalHandler handler)
713 {
714 if (handler == null) {
715 throw new NullPointerException("Null lexical handler");
716 }
717 lexicalHandler = handler;
718 }
719
720
721 /**
722 * Get the current lexical handler.
723 *
724 * @return The current lexical handler, or null if none was set.
725 */
726 public LexicalHandler getLexicalHandler ()
727 {
728 return lexicalHandler;
729 }
730
731
732
733 ////////////////////////////////////////////////////////////////////
734 // Implementation of org.xml.sax.EntityResolver.
735 ////////////////////////////////////////////////////////////////////
736
737
738 /**
739 * Resolves an external entity.
740 *
741 * @param publicId The entity's public identifier, or null.
742 * @param systemId The entity's system identifier.
743 * @return A new InputSource or null for the default.
744 * @exception org.xml.sax.SAXException The client may throw
745 * an exception during processing.
746 * @exception java.io.IOException The client may throw an
747 * I/O-related exception while obtaining the
748 * new InputSource.
749 * @see org.xml.sax.EntityResolver#resolveEntity
750 */
751 @Override
752 public InputSource resolveEntity (String publicId, String systemId)
753 throws SAXException /* IOException added in SAX2.01 bugfix release */
754 {
755 if (entityResolver != null) {
756 try {
757 return entityResolver.resolveEntity(publicId, systemId);
758 }
759 catch (IOException ex) {
760 throw new SAXException(ex);
761 }
762 }
763 return null;
764 }
765
766
767
768 ////////////////////////////////////////////////////////////////////
769 // Implementation of org.xml.sax.DTDHandler.
770 ////////////////////////////////////////////////////////////////////
771
772
773 /**
774 * Add notation declaration.
775 *
776 * @param name The notation name.
777 * @param publicId The notation's public identifier, or null.
778 * @param systemId The notation's system identifier, or null.
779 * @exception org.xml.sax.SAXException The client may throw
780 * an exception during processing.
781 * @see org.xml.sax.DTDHandler#notationDecl
782 */
783 @Override
784 public void notationDecl (String name, String publicId, String systemId)
785 throws SAXException
786 {
787 if (dtdHandler != null) {
788 dtdHandler.notationDecl(name, publicId, systemId);
789 }
790 }
791
792
793 /**
794 * Add unparsed entity declaration.
795 *
796 * @param name The entity name.
797 * @param publicId The entity's public identifier, or null.
798 * @param systemId The entity's system identifier, or null.
799 * @param notationName The name of the associated notation.
800 * @exception org.xml.sax.SAXException The client may throw
801 * an exception during processing.
802 * @see org.xml.sax.DTDHandler#unparsedEntityDecl
803 */
804 @Override
805 public void unparsedEntityDecl (String name, String publicId,
806 String systemId, String notationName)
807 throws SAXException
808 {
809 if (dtdHandler != null) {
810 dtdHandler.unparsedEntityDecl(name, publicId, systemId,
811 notationName);
812 }
813 }
814
815
816
817 ////////////////////////////////////////////////////////////////////
818 // Implementation of org.xml.sax.ContentHandler.
819 ////////////////////////////////////////////////////////////////////
820
821
822 /**
823 * Assigns the document locator.
824 *
825 * @param locator The document locator.
826 * @see org.xml.sax.ContentHandler#setDocumentLocator
827 */
828 @Override
829 public void setDocumentLocator (Locator locator)
830 {
831 //this.locator = locator;
832 if (contentHandler != null) {
833 contentHandler.setDocumentLocator(locator);
834 }
835 }
836
837
838 /**
839 * Send start of document.
840 *
841 * @exception org.xml.sax.SAXException The client may throw
842 * an exception during processing.
843 * @see org.xml.sax.ContentHandler#startDocument
844 */
845 @Override
846 public void startDocument ()
847 throws SAXException
848 {
849 if (contentHandler != null) {
850 contentHandler.startDocument();
851 }
852 }
853
854
855 /**
856 * Send end of document.
857 *
858 * @exception org.xml.sax.SAXException The client may throw
859 * an exception during processing.
860 * @see org.xml.sax.ContentHandler#endDocument
861 */
862 @Override
863 public void endDocument ()
864 throws SAXException
865 {
866 if (contentHandler != null) {
867 contentHandler.endDocument();
868 }
869 }
870
871
872 /**
873 * Sends start of namespace prefix mapping.
874 *
875 * @param prefix The Namespace prefix.
876 * @param uri The Namespace URI.
877 * @exception org.xml.sax.SAXException The client may throw
878 * an exception during processing.
879 * @see org.xml.sax.ContentHandler#startPrefixMapping
880 */
881 @Override
882 public void startPrefixMapping (String prefix, String uri)
883 throws SAXException
884 {
885 if (contentHandler != null) {
886 contentHandler.startPrefixMapping(prefix, uri);
887 }
888 }
889
890
891 /**
892 * Sends end of namespace prefix mapping.
893 *
894 * @param prefix The Namespace prefix.
895 * @exception org.xml.sax.SAXException The client may throw
896 * an exception during processing.
897 * @see org.xml.sax.ContentHandler#endPrefixMapping
898 */
899 @Override
900 public void endPrefixMapping (String prefix)
901 throws SAXException
902 {
903 if (contentHandler != null) {
904 contentHandler.endPrefixMapping(prefix);
905 }
906 }
907
908
909 /**
910 * Sends start of element.
911 *
912 * @param uri The element's Namespace URI, or the empty string.
913 * @param localName The element's local name, or the empty string.
914 * @param qName The element's qualified (prefixed) name, or the empty
915 * string.
916 * @param atts The element's attributes.
917 * @exception org.xml.sax.SAXException The client may throw
918 * an exception during processing.
919 * @see org.xml.sax.ContentHandler#startElement
920 */
921 @Override
922 public void startElement (String uri, String localName, String qName,
923 Attributes atts)
924 throws SAXException
925 {
926 if (contentHandler != null) {
927 contentHandler.startElement(uri, localName, qName, atts);
928 }
929 }
930
931
932 /**
933 * Sends end of element.
934 *
935 * @param uri The element's Namespace URI, or the empty string.
936 * @param localName The element's local name, or the empty string.
937 * @param qName The element's qualified (prefixed) name, or the empty
938 * string.
939 * @exception org.xml.sax.SAXException The client may throw
940 * an exception during processing.
941 * @see org.xml.sax.ContentHandler#endElement
942 */
943 @Override
944 public void endElement (String uri, String localName, String qName)
945 throws SAXException
946 {
947 if (contentHandler != null) {
948 contentHandler.endElement(uri, localName, qName);
949 }
950 }
951
952
953 /**
954 * Sends character data.
955 *
956 * @param ch An array of characters.
957 * @param start The starting position in the array.
958 * @param length The number of characters to use from the array.
959 * @exception org.xml.sax.SAXException The client may throw
960 * an exception during processing.
961 * @see org.xml.sax.ContentHandler#characters
962 */
963 @Override
964 public void characters (char ch[], int start, int length)
965 throws SAXException
966 {
967 if (contentHandler != null) {
968 contentHandler.characters(ch, start, length);
969 }
970 }
971
972
973 /**
974 * Sends ignorable whitespace.
975 *
976 * @param ch An array of characters.
977 * @param start The starting position in the array.
978 * @param length The number of characters to use from the array.
979 * @exception org.xml.sax.SAXException The client may throw
980 * an exception during processing.
981 * @see org.xml.sax.ContentHandler#ignorableWhitespace
982 */
983 @Override
984 public void ignorableWhitespace (char ch[], int start, int length)
985 throws SAXException
986 {
987 if (contentHandler != null) {
988 contentHandler.ignorableWhitespace(ch, start, length);
989 }
990 }
991
992
993 /**
994 * Sends processing instruction.
995 *
996 * @param target The processing instruction target.
997 * @param data The text following the target.
998 * @exception org.xml.sax.SAXException The client may throw
999 * an exception during processing.
1000 * @see org.xml.sax.ContentHandler#processingInstruction
1001 */
1002 @Override
1003 public void processingInstruction (String target, String data)
1004 throws SAXException
1005 {
1006 if (contentHandler != null) {
1007 contentHandler.processingInstruction(target, data);
1008 }
1009 }
1010
1011
1012 /**
1013 * Sends skipped entity.
1014 *
1015 * @param name The name of the skipped entity.
1016 * @exception org.xml.sax.SAXException The client may throw
1017 * an exception during processing.
1018 * @see org.xml.sax.ContentHandler#skippedEntity
1019 */
1020 @Override
1021 public void skippedEntity (String name)
1022 throws SAXException
1023 {
1024 if (contentHandler != null) {
1025 contentHandler.skippedEntity(name);
1026 }
1027 }
1028
1029
1030
1031 ////////////////////////////////////////////////////////////////////
1032 // Implementation of org.xml.sax.ErrorHandler.
1033 ////////////////////////////////////////////////////////////////////
1034
1035
1036 /**
1037 * Sends warning.
1038 *
1039 * @param e The nwarning as an exception.
1040 * @exception org.xml.sax.SAXException The client may throw
1041 * an exception during processing.
1042 * @see org.xml.sax.ErrorHandler#warning
1043 */
1044 @Override
1045 public void warning (SAXParseException e)
1046 throws SAXException
1047 {
1048 if (errorHandler != null) {
1049 errorHandler.warning(e);
1050 }
1051 }
1052
1053
1054 /**
1055 * Sends error.
1056 *
1057 * @param e The error as an exception.
1058 * @exception org.xml.sax.SAXException The client may throw
1059 * an exception during processing.
1060 * @see org.xml.sax.ErrorHandler#error
1061 */
1062 @Override
1063 public void error (SAXParseException e)
1064 throws SAXException
1065 {
1066 if (errorHandler != null) {
1067 errorHandler.error(e);
1068 }
1069 }
1070
1071
1072 /**
1073 * Sends fatal error.
1074 *
1075 * @param e The error as an exception.
1076 * @exception org.xml.sax.SAXException The client may throw
1077 * an exception during processing.
1078 * @see org.xml.sax.ErrorHandler#fatalError
1079 */
1080 @Override
1081 public void fatalError (SAXParseException e)
1082 throws SAXException
1083 {
1084 if (errorHandler != null) {
1085 errorHandler.fatalError(e);
1086 }
1087 }
1088
1089
1090
1091 ////////////////////////////////////////////////////////////////////
1092 // Implementation of org.xml.sax.ext.LexicalHandler.
1093 ////////////////////////////////////////////////////////////////////
1094
1095
1096 /**
1097 * Sends start of DTD.
1098 *
1099 * @param name The document type name.
1100 * @param publicId The declared public identifier for the
1101 * external DTD subset, or null if none was declared.
1102 * @param systemId The declared system identifier for the
1103 * external DTD subset, or null if none was declared.
1104 * @exception org.xml.sax.SAXException If a filter
1105 * further down the chain raises an exception.
1106 * @see org.xml.sax.ext.LexicalHandler#startDTD
1107 */
1108 @Override
1109 public void startDTD(String name, String publicId, String systemId)
1110 throws SAXException {
1111 if (lexicalHandler != null) {
1112 lexicalHandler.startDTD(name, publicId, systemId);
1113 }
1114 }
1115
1116
1117 /**
1118 * Sends end of DTD.
1119 *
1120 * @exception org.xml.sax.SAXException If a filter
1121 * further down the chain raises an exception.
1122 * @see org.xml.sax.ext.LexicalHandler#endDTD
1123 */
1124 @Override
1125 public void endDTD()
1126 throws SAXException {
1127 if (lexicalHandler != null) {
1128 lexicalHandler.endDTD();
1129 }
1130 }
1131
1132
1133 /*
1134 * Sends start of entity.
1135 *
1136 * @param name The name of the entity. If it is a parameter
1137 * entity, the name will begin with '%', and if it is the
1138 * external DTD subset, it will be "[dtd]".
1139 * @exception org.xml.sax.SAXException If a filter
1140 * further down the chain raises an exception.
1141 * @see org.xml.sax.ext.LexicalHandler#startEntity
1142 */
1143 @Override
1144 public void startEntity(String name)
1145 throws SAXException {
1146 if (lexicalHandler != null) {
1147 lexicalHandler.startEntity(name);
1148 }
1149 }
1150
1151
1152 /*
1153 * Sends end of entity.
1154 *
1155 * @param name The name of the entity that is ending.
1156 * @exception org.xml.sax.SAXException If a filter
1157 * further down the chain raises an exception.
1158 * @see org.xml.sax.ext.LexicalHandler#endEntity
1159 */
1160 @Override
1161 public void endEntity(String name)
1162 throws SAXException {
1163 if (lexicalHandler != null) {
1164 lexicalHandler.endEntity(name);
1165 }
1166 }
1167
1168
1169 /*
1170 * Sends start of CDATA.
1171 *
1172 * @exception org.xml.sax.SAXException If a filter
1173 * further down the chain raises an exception.
1174 * @see org.xml.sax.ext.LexicalHandler#startCDATA
1175 */
1176 @Override
1177 public void startCDATA()
1178 throws SAXException {
1179 if (lexicalHandler != null) {
1180 lexicalHandler.startCDATA();
1181 }
1182 }
1183
1184
1185 /*
1186 * Sends end of CDATA.
1187 *
1188 * @exception org.xml.sax.SAXException If a filter
1189 * further down the chain raises an exception.
1190 * @see org.xml.sax.ext.LexicalHandler#endCDATA
1191 */
1192 @Override
1193 public void endCDATA()
1194 throws SAXException {
1195 if (lexicalHandler != null) {
1196 lexicalHandler.endCDATA();
1197 }
1198 }
1199
1200
1201 /*
1202 * Sends comment.
1203 *
1204 * @param ch An array holding the characters in the comment.
1205 * @param start The starting position in the array.
1206 * @param length The number of characters to use from the array.
1207 * @exception org.xml.sax.SAXException If a filter
1208 * further down the chain raises an exception.
1209 * @see org.xml.sax.ext.LexicalHandler#comment
1210 */
1211 @Override
1212 public void comment(char[] ch, int start, int length)
1213 throws SAXException {
1214 if (lexicalHandler != null) {
1215 lexicalHandler.comment(ch, start, length);
1216 }
1217 }
1218
1219
1220
1221 ////////////////////////////////////////////////////////////////////
1222 // Internal state.
1223 ////////////////////////////////////////////////////////////////////
1224
1225 //private Locator locator = null;
1226 private EntityResolver entityResolver = null;
1227 private DTDHandler dtdHandler = null;
1228 private ContentHandler contentHandler = null;
1229 private ErrorHandler errorHandler = null;
1230 private LexicalHandler lexicalHandler = null;
1231
1232
1233
1234 ////////////////////////////////////////////////////////////////////
1235 // Constants.
1236 ////////////////////////////////////////////////////////////////////
1237
1238
1239 protected static final Attributes EMPTY_ATTS = new AttributesImpl();
1240
1241 protected static final String[] LEXICAL_HANDLER_NAMES = {
1242 "http://xml.org/sax/properties/lexical-handler",
1243 "http://xml.org/sax/handlers/LexicalHandler"
1244 };
1245
1246
1247 }
1248
1249 // end of XMLReaderBase.java
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53 package sax;
54
55 import java.io.IOException;
56 import java.io.OutputStreamWriter;
57 import java.io.Writer;
58 import java.util.Enumeration;
59 import java.util.HashMap;
60 import java.util.Iterator;
61 import java.util.Map;
62
63 import org.xml.sax.Attributes;
64 import org.xml.sax.SAXException;
65 import org.xml.sax.XMLReader;
66 import org.xml.sax.helpers.NamespaceSupport;
67
68
69 /**
70 * Filter to write an XML document from a SAX event stream.
71 *
72 * <i>Code and comments adapted from XMLWriter-0.2, written
73 * by David Megginson and released into the public domain,
74 * without warranty.</i>
75 *
76 * <p>This class can be used by itself or as part of a SAX event
77 * stream: it takes as input a series of SAX2 ContentHandler
78 * events and uses the information in those events to write
79 * an XML document. Since this class is a filter, it can also
80 * pass the events on down a filter chain for further processing
81 * (you can use the XMLWriter to take a snapshot of the current
82 * state at any point in a filter chain), and it can be
83 * used directly as a ContentHandler for a SAX2 XMLReader.</p>
84 *
85 * <p>The client creates a document by invoking the methods for
86 * standard SAX2 events, always beginning with the
87 * {@link #startDocument startDocument} method and ending with
88 * the {@link #endDocument endDocument} method.</p>
89 *
90 * <p>The following code will send a simple XML document to
91 * standard output:</p>
92 *
93 * <pre>
94 * XMLWriter w = new XMLWriter();
95 *
96 * w.startDocument();
97 * w.dataElement("greeting", "Hello, world!");
98 * w.endDocument();
99 * </pre>
100 *
101 * <p>The resulting document will look like this:</p>
102 *
103 * <pre>
104 * &lt;?xml version="1.0"?>
105 *
106 * &lt;greeting>Hello, world!&lt;/greeting>
107 * </pre>
108 *
109 * <h2>Whitespace</h2>
110 *
111 * <p>According to the XML Recommendation, <em>all</em> whitespace
112 * in an XML document is potentially significant to an application,
113 * so this class never adds newlines or indentation. If you
114 * insert three elements in a row, as in</p>
115 *
116 * <pre>
117 * w.dataElement("item", "1");
118 * w.dataElement("item", "2");
119 * w.dataElement("item", "3");
120 * </pre>
121 *
122 * <p>you will end up with</p>
123 *
124 * <pre>
125 * &lt;item>1&lt;/item>&lt;item>3&lt;/item>&lt;item>3&lt;/item>
126 * </pre>
127 *
128 * <p>You need to invoke one of the <var>characters</var> methods
129 * explicitly to add newlines or indentation. Alternatively, you
130 * can use {@link samples.sax.DataFormatFilter DataFormatFilter}
131 * add linebreaks and indentation (but does not support mixed content
132 * properly).</p>
133 *
134 *
135 * <h2>Namespace Support</h2>
136 *
137 * <p>The writer contains extensive support for XML Namespaces, so that
138 * a client application does not have to keep track of prefixes and
139 * supply <var>xmlns</var> attributes. By default, the XML writer will
140 * generate Namespace declarations in the form _NS1, _NS2, etc., wherever
141 * they are needed, as in the following example:</p>
142 *
143 * <pre>
144 * w.startDocument();
145 * w.emptyElement("http://www.foo.com/ns/", "foo");
146 * w.endDocument();
147 * </pre>
148 *
149 * <p>The resulting document will look like this:</p>
150 *
151 * <pre>
152 * &lt;?xml version="1.0"?>
153 *
154 * &lt;_NS1:foo xmlns:_NS1="http://www.foo.com/ns/"/>
155 * </pre>
156 *
157 * <p>In many cases, document authors will prefer to choose their
158 * own prefixes rather than using the (ugly) default names. The
159 * XML writer allows two methods for selecting prefixes:</p>
160 *
161 * <ol>
162 * <li>the qualified name</li>
163 * <li>the {@link #setPrefix setPrefix} method.</li>
164 * </ol>
165 *
166 * <p>Whenever the XML writer finds a new Namespace URI, it checks
167 * to see if a qualified (prefixed) name is also available; if so
168 * it attempts to use the name's prefix (as long as the prefix is
169 * not already in use for another Namespace URI).</p>
170 *
171 * <p>Before writing a document, the client can also pre-map a prefix
172 * to a Namespace URI with the setPrefix method:</p>
173 *
174 * <pre>
175 * w.setPrefix("http://www.foo.com/ns/", "foo");
176 * w.startDocument();
177 * w.emptyElement("http://www.foo.com/ns/", "foo");
178 * w.endDocument();
179 * </pre>
180 *
181 * <p>The resulting document will look like this:</p>
182 *
183 * <pre>
184 * &lt;?xml version="1.0"?>
185 *
186 * &lt;foo:foo xmlns:foo="http://www.foo.com/ns/"/>
187 * </pre>
188 *
189 * <p>The default Namespace simply uses an empty string as the prefix:</p>
190 *
191 * <pre>
192 * w.setPrefix("http://www.foo.com/ns/", "");
193 * w.startDocument();
194 * w.emptyElement("http://www.foo.com/ns/", "foo");
195 * w.endDocument();
196 * </pre>
197 *
198 * <p>The resulting document will look like this:</p>
199 *
200 * <pre>
201 * &lt;?xml version="1.0"?>
202 *
203 * &lt;foo xmlns="http://www.foo.com/ns/"/>
204 * </pre>
205 *
206 * <p>By default, the XML writer will not declare a Namespace until
207 * it is actually used. Sometimes, this approach will create
208 * a large number of Namespace declarations, as in the following
209 * example:</p>
210 *
211 * <pre>
212 * &lt;xml version="1.0"?>
213 *
214 * &lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
215 * &lt;rdf:Description about="http://www.foo.com/ids/books/12345">
216 * &lt;dc:title xmlns:dc="http://www.purl.org/dc/">A Dark Night&lt;/dc:title>
217 * &lt;dc:creator xmlns:dc="http://www.purl.org/dc/">Jane Smith&lt;/dc:title>
218 * &lt;dc:date xmlns:dc="http://www.purl.org/dc/">2000-09-09&lt;/dc:title>
219 * &lt;/rdf:Description>
220 * &lt;/rdf:RDF>
221 * </pre>
222 *
223 * <p>The "rdf" prefix is declared only once, because the RDF Namespace
224 * is used by the root element and can be inherited by all of its
225 * descendants; the "dc" prefix, on the other hand, is declared three
226 * times, because no higher element uses the Namespace. To solve this
227 * problem, you can instruct the XML writer to predeclare Namespaces
228 * on the root element even if they are not used there:</p>
229 *
230 * <pre>
231 * w.forceNSDecl("http://www.purl.org/dc/");
232 * </pre>
233 *
234 * <p>Now, the "dc" prefix will be declared on the root element even
235 * though it's not needed there, and can be inherited by its
236 * descendants:</p>
237 *
238 * <pre>
239 * &lt;xml version="1.0"?>
240 *
241 * &lt;rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
242 * xmlns:dc="http://www.purl.org/dc/">
243 * &lt;rdf:Description about="http://www.foo.com/ids/books/12345">
244 * &lt;dc:title>A Dark Night&lt;/dc:title>
245 * &lt;dc:creator>Jane Smith&lt;/dc:title>
246 * &lt;dc:date>2000-09-09&lt;/dc:title>
247 * &lt;/rdf:Description>
248 * &lt;/rdf:RDF>
249 * </pre>
250 *
251 * <p>This approach is also useful for declaring Namespace prefixes
252 * that be used by qualified names appearing in attribute values or
253 * character data.</p>
254 *
255 * @see XMLFilterBase
256 */
257 @SuppressWarnings("javadoc")
258 public class XMLWriter extends XMLFilterBase
259 {
260
261
262 ////////////////////////////////////////////////////////////////////
263 // Constructors.
264 ////////////////////////////////////////////////////////////////////
265
266
267 /**
268 * Create a new XML writer.
269 *
270 * <p>Write to standard output.</p>
271 */
272 public XMLWriter()
273 {
274 init(null);
275 }
276
277
278 /**
279 * Create a new XML writer.
280 *
281 * <p>Write to the writer provided.</p>
282 *
283 * @param writer The output destination, or null to use standard
284 * output.
285 */
286 public XMLWriter(Writer writer)
287 {
288 init(writer);
289 }
290
291
292 /**
293 * Create a new XML writer.
294 *
295 * <p>Use the specified XML reader as the parent.</p>
296 *
297 * @param xmlreader The parent in the filter chain, or null
298 * for no parent.
299 */
300 public XMLWriter(XMLReader xmlreader)
301 {
302 super(xmlreader);
303 init(null);
304 }
305
306
307 /**
308 * Create a new XML writer.
309 *
310 * <p>Use the specified XML reader as the parent, and write
311 * to the specified writer.</p>
312 *
313 * @param xmlreader The parent in the filter chain, or null
314 * for no parent.
315 * @param writer The output destination, or null to use standard
316 * output.
317 */
318 public XMLWriter(XMLReader xmlreader, Writer writer)
319 {
320 super(xmlreader);
321 init(writer);
322 }
323
324
325 /**
326 * Internal initialization method.
327 *
328 * <p>All of the public constructors invoke this method.
329 *
330 * @param writer The output destination, or null to use
331 * standard output.
332 */
333 private void init (Writer writer)
334 {
335 setOutput(writer);
336 nsSupport = new NamespaceSupport();
337 prefixTable = new HashMap<String, String>();
338 forcedDeclTable = new HashMap<String, Boolean>();
339 doneDeclTable = new HashMap<String, String>();
340 }
341
342
343
344 ////////////////////////////////////////////////////////////////////
345 // Public methods.
346 ////////////////////////////////////////////////////////////////////
347
348
349 /**
350 * Reset the writer.
351 *
352 * <p>This method is especially useful if the writer throws an
353 * exception before it is finished, and you want to reuse the
354 * writer for a new document. It is usually a good idea to
355 * invoke {@link #flush flush} before resetting the writer,
356 * to make sure that no output is lost.</p>
357 *
358 * <p>This method is invoked automatically by the
359 * {@link #startDocument startDocument} method before writing
360 * a new document.</p>
361 *
362 * <p><strong>Note:</strong> this method will <em>not</em>
363 * clear the prefix or URI information in the writer or
364 * the selected output writer.</p>
365 *
366 * @see #flush
367 */
368 public void reset ()
369 {
370 openElement = false;
371 elementLevel = 0;
372 prefixCounter = 0;
373 nsSupport.reset();
374 inDTD = false;
375 }
376
377
378 /**
379 * Flush the output.
380 *
381 * <p>This method flushes the output stream. It is especially useful
382 * when you need to make certain that the entire document has
383 * been written to output but do not want to close the output
384 * stream.</p>
385 *
386 * <p>This method is invoked automatically by the
387 * {@link #endDocument endDocument} method after writing a
388 * document.</p>
389 *
390 * @see #reset
391 */
392 public void flush ()
393 throws IOException
394 {
395 output.flush();
396 }
397
398
399 /**
400 * Set a new output destination for the document.
401 *
402 * @param writer The output destination, or null to use
403 * standard output.
404 * @return The current output writer.
405 * @see #flush
406 */
407 public void setOutput (Writer writer)
408 {
409 if (writer == null) {
410 output = new OutputStreamWriter(System.out);
411 } else {
412 output = writer;
413 }
414 }
415
416
417 /**
418 * Specify a preferred prefix for a Namespace URI.
419 *
420 * <p>Note that this method does not actually force the Namespace
421 * to be declared; to do that, use the {@link
422 * #forceNSDecl(java.lang.String) forceNSDecl} method as well.</p>
423 *
424 * @param uri The Namespace URI.
425 * @param prefix The preferred prefix, or "" to select
426 * the default Namespace.
427 * @see #getPrefix
428 * @see #forceNSDecl(java.lang.String)
429 * @see #forceNSDecl(java.lang.String,java.lang.String)
430 */
431 public void setPrefix (String uri, String prefix)
432 {
433 prefixTable.put(uri, prefix);
434 }
435
436
437 /**
438 * Get the current or preferred prefix for a Namespace URI.
439 *
440 * @param uri The Namespace URI.
441 * @return The preferred prefix, or "" for the default Namespace.
442 * @see #setPrefix
443 */
444 public String getPrefix (String uri)
445 {
446 return prefixTable.get(uri);
447 }
448
449
450 /**
451 * Force a Namespace to be declared on the root element.
452 *
453 * <p>By default, the XMLWriter will declare only the Namespaces
454 * needed for an element; as a result, a Namespace may be
455 * declared many places in a document if it is not used on the
456 * root element.</p>
457 *
458 * <p>This method forces a Namespace to be declared on the root
459 * element even if it is not used there, and reduces the number
460 * of xmlns attributes in the document.</p>
461 *
462 * @param uri The Namespace URI to declare.
463 * @see #forceNSDecl(java.lang.String,java.lang.String)
464 * @see #setPrefix
465 */
466 public void forceNSDecl (String uri)
467 {
468 forcedDeclTable.put(uri, Boolean.TRUE);
469 }
470
471
472 /**
473 * Force a Namespace declaration with a preferred prefix.
474 *
475 * <p>This is a convenience method that invokes {@link
476 * #setPrefix setPrefix} then {@link #forceNSDecl(java.lang.String)
477 * forceNSDecl}.</p>
478 *
479 * @param uri The Namespace URI to declare on the root element.
480 * @param prefix The preferred prefix for the Namespace, or ""
481 * for the default Namespace.
482 * @see #setPrefix
483 * @see #forceNSDecl(java.lang.String)
484 */
485 public void forceNSDecl (String uri, String prefix)
486 {
487 setPrefix(uri, prefix);
488 forceNSDecl(uri);
489 }
490
491
492
493 ////////////////////////////////////////////////////////////////////
494 // Methods from org.xml.sax.ContentHandler.
495 ////////////////////////////////////////////////////////////////////
496
497
498 /**
499 * Write the XML declaration at the beginning of the document.
500 *
501 * Pass the event on down the filter chain for further processing.
502 *
503 * @exception org.xml.sax.SAXException If there is an error
504 * writing the XML declaration, or if a handler further down
505 * the filter chain raises an exception.
506 * @see org.xml.sax.ContentHandler#startDocument
507 */
508 @Override
509 public void startDocument ()
510 throws SAXException
511 {
512 reset();
513 //write("<?xml version=\"1.0\" standalone=\"yes\"?>\n\n");
514 write("<?xml version=\"1.0\"?>\n\n");
515 super.startDocument();
516 }
517
518
519 /**
520 * Write a newline at the end of the document.
521 *
522 * Pass the event on down the filter chain for further processing.
523 *
524 * @exception org.xml.sax.SAXException If there is an error
525 * writing the newline, or if a handler further down
526 * the filter chain raises an exception.
527 * @see org.xml.sax.ContentHandler#endDocument
528 */
529 @Override
530 public void endDocument ()
531 throws SAXException
532 {
533 closeElement();
534 write('\n');
535 super.endDocument();
536 try {
537 flush();
538 } catch (IOException e) {
539 throw new SAXException(e);
540 }
541 }
542
543
544 /**
545 * Write a start tag.
546 *
547 * Pass the event on down the filter chain for further processing.
548 *
549 * @param uri The Namespace URI, or the empty string if none
550 * is available.
551 * @param localName The element's local (unprefixed) name (required).
552 * @param qName The element's qualified (prefixed) name, or the
553 * empty string is none is available. This method will
554 * use the qName as a template for generating a prefix
555 * if necessary, but it is not guaranteed to use the
556 * same qName.
557 * @param atts The element's attribute list (must not be null).
558 * @exception org.xml.sax.SAXException If there is an error
559 * writing the start tag, or if a handler further down
560 * the filter chain raises an exception.
561 * @see org.xml.sax.ContentHandler#startElement
562 */
563 @Override
564 public void startElement (String uri, String localName,
565 String qName, Attributes atts)
566 throws SAXException
567 {
568 closeElement();
569 elementLevel++;
570 nsSupport.pushContext();
571 write('<');
572 writeName(uri, localName, qName, true);
573 writeAttributes(atts);
574 if (elementLevel == 1) {
575 forceNSDecls();
576 }
577 writeNSDecls();
578 openElement = true;
579 super.startElement(uri, localName, qName, atts);
580 }
581
582
583 /**
584 * Write an end tag.
585 *
586 * Pass the event on down the filter chain for further processing.
587 *
588 * @param uri The Namespace URI, or the empty string if none
589 * is available.
590 * @param localName The element's local (unprefixed) name (required).
591 * @param qName The element's qualified (prefixed) name, or the
592 * empty string is none is available. This method will
593 * use the qName as a template for generating a prefix
594 * if necessary, but it is not guaranteed to use the
595 * same qName.
596 * @exception org.xml.sax.SAXException If there is an error
597 * writing the end tag, or if a handler further down
598 * the filter chain raises an exception.
599 * @see org.xml.sax.ContentHandler#endElement
600 */
601 @Override
602 public void endElement (String uri, String localName, String qName)
603 throws SAXException
604 {
605 if (openElement) {
606 write("/>");
607 openElement = false;
608 } else {
609 write("</");
610 writeName(uri, localName, qName, true);
611 write('>');
612 }
613 if (elementLevel == 1) {
614 write('\n');
615 }
616 super.endElement(uri, localName, qName);
617 nsSupport.popContext();
618 elementLevel--;
619 }
620
621
622 /**
623 * Write character data.
624 *
625 * Pass the event on down the filter chain for further processing.
626 *
627 * @param ch The array of characters to write.
628 * @param start The starting position in the array.
629 * @param length The number of characters to write.
630 * @exception org.xml.sax.SAXException If there is an error
631 * writing the characters, or if a handler further down
632 * the filter chain raises an exception.
633 * @see org.xml.sax.ContentHandler#characters
634 */
635 @Override
636 public void characters (char ch[], int start, int len)
637 throws SAXException
638 {
639 closeElement();
640 writeEsc(ch, start, len, false);
641 super.characters(ch, start, len);
642 }
643
644
645 /**
646 * Write ignorable whitespace.
647 *
648 * Pass the event on down the filter chain for further processing.
649 *
650 * @param ch The array of characters to write.
651 * @param start The starting position in the array.
652 * @param length The number of characters to write.
653 * @exception org.xml.sax.SAXException If there is an error
654 * writing the whitespace, or if a handler further down
655 * the filter chain raises an exception.
656 * @see org.xml.sax.ContentHandler#ignorableWhitespace
657 */
658 @Override
659 public void ignorableWhitespace (char ch[], int start, int length)
660 throws SAXException
661 {
662 closeElement();
663 writeEsc(ch, start, length, false);
664 super.ignorableWhitespace(ch, start, length);
665 }
666
667
668
669 /**
670 * Write a processing instruction.
671 *
672 * Pass the event on down the filter chain for further processing.
673 *
674 * @param target The PI target.
675 * @param data The PI data.
676 * @exception org.xml.sax.SAXException If there is an error
677 * writing the PI, or if a handler further down
678 * the filter chain raises an exception.
679 * @see org.xml.sax.ContentHandler#processingInstruction
680 */
681 @Override
682 public void processingInstruction (String target, String data)
683 throws SAXException
684 {
685 closeElement();
686 write("<?");
687 write(target);
688 write(' ');
689 write(data);
690 write("?>");
691 if (elementLevel < 1) {
692 write('\n');
693 }
694 super.processingInstruction(target, data);
695 }
696
697
698
699 ////////////////////////////////////////////////////////////////////
700 // Methods from org.xml.sax.ext.LexicalHandler.
701 ////////////////////////////////////////////////////////////////////
702
703
704 /**
705 * Write start of DOCTYPE declaration.
706 *
707 * Pass the event on down the filter chain for further processing.
708 *
709 * @param name The document type name.
710 * @param publicId The declared public identifier for the
711 * external DTD subset, or null if none was declared.
712 * @param systemId The declared system identifier for the
713 * external DTD subset, or null if none was declared.
714 * @exception org.xml.sax.SAXException If a filter
715 * further down the chain raises an exception.
716 * @see org.xml.sax.ext.LexicalHandler#startDTD
717 */
718 @Override
719 public void startDTD(String name, String publicId, String systemId)
720 throws SAXException {
721 //closeElement();
722 inDTD = true;
723 write("<!DOCTYPE ");
724 write(name);
725 boolean hasPublic = publicId != null && !publicId.equals("");
726 if (hasPublic) {
727 write(" PUBLIC \"");
728 write(publicId);
729 write('\"');
730 }
731 if (systemId != null && !systemId.equals("")) {
732 if (!hasPublic) {
733 write(" SYSTEM");
734 }
735 write(" \"");
736 write(systemId);
737 write('\"');
738 }
739 write(">\n\n");
740 super.startDTD(name, publicId, systemId);
741 }
742
743
744 /**
745 * Write end of DOCTYPE declaration.
746 *
747 * Pass the event on down the filter chain for further processing.
748 *
749 * @exception org.xml.sax.SAXException If a filter
750 * further down the chain raises an exception.
751 * @see org.xml.sax.ext.LexicalHandler#endDTD
752 */
753 @Override
754 public void endDTD()
755 throws SAXException {
756 inDTD = false;
757 super.endDTD();
758 }
759
760
761 /*
762 * Write entity.
763 *
764 * Pass the event on down the filter chain for further processing.
765 *
766 * @param name The name of the entity. If it is a parameter
767 * entity, the name will begin with '%', and if it is the
768 * external DTD subset, it will be "[dtd]".
769 * @exception org.xml.sax.SAXException If a filter
770 * further down the chain raises an exception.
771 * @see org.xml.sax.ext.LexicalHandler#startEntity
772 */
773 @Override
774 public void startEntity(String name)
775 throws SAXException {
776 closeElement();
777 write('&');
778 write(name);
779 write(';');
780 super.startEntity(name);
781 }
782
783
784 /*
785 * Filter a end entity event.
786 *
787 * Pass the event on down the filter chain for further processing.
788 *
789 * @param name The name of the entity that is ending.
790 * @exception org.xml.sax.SAXException If a filter
791 * further down the chain raises an exception.
792 * @see org.xml.sax.ext.LexicalHandler#endEntity
793 */
794 @Override
795 public void endEntity(String name)
796 throws SAXException {
797 super.endEntity(name);
798 }
799
800
801 /*
802 * Write start of CDATA.
803 *
804 * Pass the event on down the filter chain for further processing.
805 *
806 * @exception org.xml.sax.SAXException If a filter
807 * further down the chain raises an exception.
808 * @see org.xml.sax.ext.LexicalHandler#startCDATA
809 */
810 @Override
811 public void startCDATA()
812 throws SAXException {
813 closeElement();
814 write("<![CDATA[");
815 super.startCDATA();
816 }
817
818
819 /*
820 * Write end of CDATA.
821 *
822 * Pass the event on down the filter chain for further processing.
823 *
824 * @exception org.xml.sax.SAXException If a filter
825 * further down the chain raises an exception.
826 * @see org.xml.sax.ext.LexicalHandler#endCDATA
827 */
828 @Override
829 public void endCDATA()
830 throws SAXException {
831 write("]]>");
832 super.endCDATA();
833 }
834
835
836 /*
837 * Write a comment.
838 *
839 * Pass the event on down the filter chain for further processing.
840 *
841 * @param ch An array holding the characters in the comment.
842 * @param start The starting position in the array.
843 * @param length The number of characters to use from the array.
844 * @exception org.xml.sax.SAXException If a filter
845 * further down the chain raises an exception.
846 * @see org.xml.sax.ext.LexicalHandler#comment
847 */
848 @Override
849 public void comment(char[] ch, int start, int length)
850 throws SAXException {
851 if (!inDTD) {
852 closeElement();
853 write("<!--");
854 write(ch, start, length);
855 write("-->");
856 if (elementLevel < 1) {
857 write('\n');
858 }
859 }
860 super.comment(ch, start, length);
861 }
862
863
864
865 ////////////////////////////////////////////////////////////////////
866 // Internal methods.
867 ////////////////////////////////////////////////////////////////////
868
869
870 /**
871 * Force all Namespaces to be declared.
872 *
873 * This method is used on the root element to ensure that
874 * the predeclared Namespaces all appear.
875 */
876 private void forceNSDecls ()
877 {
878 Iterator<String> prefixes = forcedDeclTable.keySet().iterator();
879 while (prefixes.hasNext()) {
880 String prefix = prefixes.next();
881 doPrefix(prefix, null, true);
882 }
883 }
884
885
886 /**
887 * Determine the prefix for an element or attribute name.
888 *
889 * TODO: this method probably needs some cleanup.
890 *
891 * @param uri The Namespace URI.
892 * @param qName The qualified name (optional); this will be used
893 * to indicate the preferred prefix if none is currently
894 * bound.
895 * @param isElement true if this is an element name, false
896 * if it is an attribute name (which cannot use the
897 * default Namespace).
898 */
899 private String doPrefix (String uri, String qName, boolean isElement)
900 {
901 String defaultNS = nsSupport.getURI("");
902 if ("".equals(uri)) {
903 if (isElement && defaultNS != null)
904 nsSupport.declarePrefix("", "");
905 return null;
906 }
907 String prefix;
908 if (isElement && defaultNS != null && uri.equals(defaultNS)) {
909 prefix = "";
910 } else {
911 prefix = nsSupport.getPrefix(uri);
912 }
913 if (prefix != null) {
914 return prefix;
915 }
916 prefix = doneDeclTable.get(uri);
917 if (prefix != null &&
918 ((!isElement || defaultNS != null) &&
919 "".equals(prefix) || nsSupport.getURI(prefix) != null)) {
920 prefix = null;
921 }
922 if (prefix == null) {
923 prefix = prefixTable.get(uri);
924 if (prefix != null &&
925 ((!isElement || defaultNS != null) &&
926 "".equals(prefix) || nsSupport.getURI(prefix) != null)) {
927 prefix = null;
928 }
929 }
930 if (prefix == null && qName != null && !"".equals(qName)) {
931 int i = qName.indexOf(':');
932 if (i == -1) {
933 if (isElement && defaultNS == null) {
934 prefix = "";
935 }
936 } else {
937 prefix = qName.substring(0, i);
938 }
939 }
940 for (;
941 prefix == null || nsSupport.getURI(prefix) != null;
942 prefix = "__NS" + ++prefixCounter)
943
944 nsSupport.declarePrefix(prefix, uri);
945 doneDeclTable.put(uri, prefix);
946 return prefix;
947 }
948
949
950 /**
951 * Write a raw character.
952 *
953 * @param c The character to write.
954 * @exception org.xml.sax.SAXException If there is an error writing
955 * the character, this method will throw an IOException
956 * wrapped in a SAXException.
957 */
958 private void write (char c)
959 throws SAXException
960 {
961 try {
962 output.write(c);
963 } catch (IOException e) {
964 throw new SAXException(e);
965 }
966 }
967
968
969 /**
970 * Write a portion of an array of characters.
971 *
972 * @param cbuf Array of characters.
973 * @param off Offset from which to start writing characters.
974 * @param len Number of characters to write.
975 * @exception org.xml.sax.SAXException If there is an error writing
976 * the character, this method will throw an IOException
977 * wrapped in a SAXException.
978 */
979 private void write (char[] cbuf, int off, int len)
980 throws SAXException
981 {
982 try {
983 output.write(cbuf, off, len);
984 } catch (IOException e) {
985 throw new SAXException(e);
986 }
987 }
988
989
990 /**
991 * Write a raw string.
992 *
993 * @param s
994 * @exception org.xml.sax.SAXException If there is an error writing
995 * the string, this method will throw an IOException
996 * wrapped in a SAXException
997 */
998 private void write (String s)
999 throws SAXException
1000 {
1001 try {
1002 output.write(s);
1003 } catch (IOException e) {
1004 throw new SAXException(e);
1005 }
1006 }
1007
1008
1009 /**
1010 * Write out an attribute list, escaping values.
1011 *
1012 * The names will have prefixes added to them.
1013 *
1014 * @param atts The attribute list to write.
1015 * @exception org.xml.SAXException If there is an error writing
1016 * the attribute list, this method will throw an
1017 * IOException wrapped in a SAXException.
1018 */
1019 private void writeAttributes (Attributes atts)
1020 throws SAXException
1021 {
1022 int len = atts.getLength();
1023 for (int i = 0; i < len; i++) {
1024 char ch[] = atts.getValue(i).toCharArray();
1025 write(' ');
1026 writeName(atts.getURI(i), atts.getLocalName(i),
1027 atts.getQName(i), false);
1028 write("=\"");
1029 writeEsc(ch, 0, ch.length, true);
1030 write('"');
1031 }
1032 }
1033
1034
1035 /**
1036 * Write an array of data characters with escaping.
1037 *
1038 * @param ch The array of characters.
1039 * @param start The starting position.
1040 * @param length The number of characters to use.
1041 * @param isAttVal true if this is an attribute value literal.
1042 * @exception org.xml.SAXException If there is an error writing
1043 * the characters, this method will throw an
1044 * IOException wrapped in a SAXException.
1045 */
1046 private void writeEsc (char ch[], int start,
1047 int length, boolean isAttVal)
1048 throws SAXException
1049 {
1050 for (int i = start; i < start + length; i++) {
1051 switch (ch[i]) {
1052 case '&':
1053 write("&amp;");
1054 break;
1055 case '<':
1056 write("&lt;");
1057 break;
1058 case '>':
1059 write("&gt;");
1060 break;
1061 case '\"':
1062 if (isAttVal) {
1063 write("&quot;");
1064 } else {
1065 write('\"');
1066 }
1067 break;
1068 default:
1069 if (ch[i] > '\u007f') {
1070 write("&#");
1071 write(Integer.toString(ch[i]));
1072 write(';');
1073 } else {
1074 write(ch[i]);
1075 }
1076 }
1077 }
1078 }
1079
1080
1081 /**
1082 * Write out the list of Namespace declarations.
1083 *
1084 * @exception org.xml.sax.SAXException This method will throw
1085 * an IOException wrapped in a SAXException if
1086 * there is an error writing the Namespace
1087 * declarations.
1088 */
1089 private void writeNSDecls ()
1090 throws SAXException
1091 {
1092 Enumeration<?> prefixes = nsSupport.getDeclaredPrefixes();
1093 while (prefixes.hasMoreElements()) {
1094 String prefix = (String) prefixes.nextElement();
1095 String uri = nsSupport.getURI(prefix);
1096 if (uri == null) {
1097 uri = "";
1098 }
1099 char ch[] = uri.toCharArray();
1100 write(' ');
1101 if ("".equals(prefix)) {
1102 write("xmlns=\"");
1103 } else {
1104 write("xmlns:");
1105 write(prefix);
1106 write("=\"");
1107 }
1108 writeEsc(ch, 0, ch.length, true);
1109 write('\"');
1110 }
1111 }
1112
1113
1114 /**
1115 * Write an element or attribute name.
1116 *
1117 * @param uri The Namespace URI.
1118 * @param localName The local name.
1119 * @param qName The prefixed name, if available, or the empty string.
1120 * @param isElement true if this is an element name, false if it
1121 * is an attribute name.
1122 * @exception org.xml.sax.SAXException This method will throw an
1123 * IOException wrapped in a SAXException if there is
1124 * an error writing the name.
1125 */
1126 private void writeName (String uri, String localName,
1127 String qName, boolean isElement)
1128 throws SAXException
1129 {
1130 String prefix = doPrefix(uri, qName, isElement);
1131 if (prefix != null && !"".equals(prefix)) {
1132 write(prefix);
1133 write(':');
1134 }
1135 write(localName);
1136 }
1137
1138
1139 /**
1140 * If start element tag is still open, write closing bracket.
1141 */
1142 private void closeElement()
1143 throws SAXException
1144 {
1145 if (openElement) {
1146 write('>');
1147 openElement = false;
1148 }
1149 }
1150
1151
1152
1153 ////////////////////////////////////////////////////////////////////
1154 // Internal state.
1155 ////////////////////////////////////////////////////////////////////
1156
1157 private Map<String,String> prefixTable;
1158 private Map<String,Boolean> forcedDeclTable;
1159 private Map<String,String> doneDeclTable;
1160 private boolean openElement = false;
1161 private int elementLevel = 0;
1162 private Writer output;
1163 private NamespaceSupport nsSupport;
1164 private int prefixCounter = 0;
1165 private boolean inDTD = false;
1166
1167 }
1168
1169 // end of XMLWriter.java
0 <?xml version="1.0" standalone="yes"?>
1
2 <Person><name>Jane Smith</name><date-of-birth>1965-05-23</date-of-birth><citizenship>US</citizenship></Person>
3
0 <?xml version="1.0" standalone="yes"?>
1
2 <Person>
3 <name>Jane Smith</name>
4 <date-of-birth>1965-05-23</date-of-birth>
5 <citizenship>US</citizenship>
6 </Person>
7
8
0 <Template>
1 <Application1 xmlns:xplt="www.xxxx.com"
2 xmlns:xpl="www.xxxx.com"
3 version="3.0"
4 >
5 <xpl:insertText/>
6 <xplt:anyElement>
7 <Name/>
8 </xplt:anyElement>
9 </Application1>
10
11 <Application2 xmlns:xplt="www.xxxx.com"
12 xmlns:xpl="www.xxxx.com"
13 version="3.0"
14 >
15 <xpl:insertText/>
16 <xplt:anyElement>
17 <Name/>
18 </xplt:anyElement>
19 </Application2>
20 </Template>
0 <?xml version="1.0" encoding="ISO-8859-1"?>
1
2 <!--
3 <!DOCTYPE web-app
4 PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
5 "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
6 -->
7
8 <web-app>
9 <servlet>
10 <servlet-name>
11 snoop
12 </servlet-name>
13 <servlet-class>
14 SnoopServlet
15 </servlet-class>
16 </servlet>
17 <servlet>
18 <servlet-name>
19 file
20 </servlet-name>
21 <servlet-class>
22 ViewFile
23 </servlet-class>
24 <init-param>
25 <param-name>
26 initial
27 </param-name>
28 <param-value>
29 1000
30 </param-value>
31 <description>
32 The initial value for the counter <!-- optional -->
33 </description>
34 </init-param>
35 </servlet>
36 <servlet-mapping>
37 <servlet-name>
38 mv
39 </servlet-name>
40 <url-pattern>
41 *.wm
42 </url-pattern>
43 </servlet-mapping>
44
45 <distributed/>
46
47 <security-role>
48 <role-name>
49 manager
50 </role-name>
51 <role-name>
52 director
53 </role-name>
54 <role-name>
55 president
56 </role-name>
57 </security-role>
58
59
60 </web-app>
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.io.Serializable;
57 import java.util.ArrayList;
58 import java.util.Collections;
59 import java.util.List;
60 import java.util.TreeMap;
61
62 /**
63 * An XML attribute. Methods allow the user to obtain the value of the attribute
64 * as well as namespace and type information.
65 * <p>
66 * <strong>JDOM 1.x Compatibility Note:</strong><br>
67 * The Attribute class in JDOM 1.x had a number of int Constants declared to
68 * represent different Attribute Types. JDOM2 has introduced an AttributeType
69 * enumeration instead. To facilitate compatibility and to simplify JDOM 1.x
70 * migrations, the replacement AttributeType enums are referenced still using
71 * the JDOM 1.x constant names. In JDOM 1.x these names referenced constant
72 * int values. In JDOM2 these names reference Enum constants.
73 *
74 * @author Brett McLaughlin
75 * @author Jason Hunter
76 * @author Elliotte Rusty Harold
77 * @author Wesley Biggs
78 * @author Victor Toni
79 * @author Rolf Lear
80 */
81 public class Attribute extends CloneBase
82 implements NamespaceAware, Serializable, Cloneable {
83
84 /**
85 * JDOM 2.0.0 Serialization version. Attribute is simple
86 */
87 private static final long serialVersionUID = 200L;
88
89 // Keep the old constant names for one beta cycle to help migration
90
91 /** JDOM 1.x compatible reference to {@link AttributeType#UNDECLARED} */
92 public final static AttributeType UNDECLARED_TYPE = AttributeType.UNDECLARED;
93
94 /** JDOM 1.x compatible reference to {@link AttributeType#CDATA} */
95 public final static AttributeType CDATA_TYPE = AttributeType.CDATA;
96
97 /** JDOM 1.x compatible reference to {@link AttributeType#ID} */
98 public final static AttributeType ID_TYPE = AttributeType.ID;
99
100 /** JDOM 1.x compatible reference to {@link AttributeType#IDREF} */
101 public final static AttributeType IDREF_TYPE = AttributeType.IDREF;
102
103 /** JDOM 1.x compatible reference to {@link AttributeType#IDREFS} */
104 public final static AttributeType IDREFS_TYPE = AttributeType.IDREFS;
105
106 /** JDOM 1.x compatible reference to {@link AttributeType#ENTITY} */
107 public final static AttributeType ENTITY_TYPE = AttributeType.ENTITY;
108
109 /** JDOM 1.x compatible reference to {@link AttributeType#ENTITIES} */
110 public final static AttributeType ENTITIES_TYPE = AttributeType.ENTITIES;
111
112 /** JDOM 1.x compatible reference to {@link AttributeType#NMTOKEN} */
113 public final static AttributeType NMTOKEN_TYPE = AttributeType.NMTOKEN;
114
115 /** JDOM 1.x compatible reference to {@link AttributeType#NMTOKENS} */
116 public final static AttributeType NMTOKENS_TYPE = AttributeType.NMTOKENS;
117
118 /** JDOM 1.x compatible reference to {@link AttributeType#NOTATION} */
119 public final static AttributeType NOTATION_TYPE = AttributeType.NOTATION;
120
121 /** JDOM 1.x compatible reference to {@link AttributeType#ENUMERATION} */
122 public final static AttributeType ENUMERATED_TYPE = AttributeType.ENUMERATION;
123
124
125
126
127 /** The local name of the <code>Attribute</code> */
128 protected String name;
129
130 /** The <code>{@link Namespace}</code> of the <code>Attribute</code> */
131 protected Namespace namespace;
132
133 /** The value of the <code>Attribute</code> */
134 protected String value;
135
136 /** The type of the <code>Attribute</code> */
137 protected AttributeType type = AttributeType.UNDECLARED;
138
139 /**
140 * Specified attributes are part of the XML,
141 * unspecified attributes are 'defaulted' from a DTD.
142 */
143 protected boolean specified = true;
144
145 /**
146 * The parent to which this Attribute belongs. Change it with
147 * {@link #setParent(Element)}
148 */
149 protected transient Element parent;
150
151 /**
152 * Default, no-args constructor for implementations to use if needed.
153 */
154 protected Attribute() {
155 }
156
157 /**
158 * This will create a new <code>Attribute</code> with the
159 * specified (local) name and value, and in the provided
160 * <code>{@link Namespace}</code>.
161 *
162 * @param name <code>String</code> name of <code>Attribute</code>.
163 * @param value <code>String</code> value for new attribute.
164 * @param namespace <code>Namespace</code> namespace for new attribute.
165 * @throws IllegalNameException if the given name is illegal as an
166 * attribute name or if if the new namespace is the default
167 * namespace. Attributes cannot be in a default namespace.
168 * @throws IllegalDataException if the given attribute value is
169 * illegal character data (as determined by
170 * {@link org.jdom.Verifier#checkCharacterData}).
171 */
172 public Attribute(final String name, final String value, final Namespace namespace) {
173 this(name, value, AttributeType.UNDECLARED, namespace);
174 }
175
176 /**
177 * This will create a new <code>Attribute</code> with the
178 * specified (local) name, value, and type, and in the provided
179 * <code>{@link Namespace}</code>.
180 *
181 * @param name <code>String</code> name of <code>Attribute</code>.
182 * @param value <code>String</code> value for new attribute.
183 * @param type <code>int</code> type for new attribute.
184 * @param namespace <code>Namespace</code> namespace for new attribute.
185 * @throws IllegalNameException if the given name is illegal as an
186 * attribute name or if if the new namespace is the default
187 * namespace. Attributes cannot be in a default namespace.
188 * @throws IllegalDataException if the given attribute value is
189 * illegal character data (as determined by
190 * {@link org.jdom.Verifier#checkCharacterData}) or
191 * if the given attribute type is not one of the
192 * supported types.
193 * @deprecated Use {@link #Attribute(String, String, AttributeType, Namespace)}.
194 */
195 @Deprecated
196 public Attribute(final String name, final String value, final int type, final Namespace namespace) {
197 this(name, value, AttributeType.byIndex(type), namespace);
198 }
199
200 /**
201 * This will create a new <code>Attribute</code> with the
202 * specified (local) name, value, and type, and in the provided
203 * <code>{@link Namespace}</code>.
204 *
205 * @param name <code>String</code> name of <code>Attribute</code>.
206 * @param value <code>String</code> value for new attribute.
207 * @param type <code>AttributeType</code> for new attribute.
208 * @param namespace <code>Namespace</code> namespace for new attribute.
209 * @throws IllegalNameException if the given name is illegal as an
210 * attribute name or if if the new namespace is the default
211 * namespace. Attributes cannot be in a default namespace.
212 * @throws IllegalDataException if the given attribute value is
213 * illegal character data (as determined by
214 * {@link org.jdom.Verifier#checkCharacterData}) or
215 * if the given attribute type is not one of the
216 * supported types.
217 */
218 public Attribute(final String name, final String value, final AttributeType type, final Namespace namespace) {
219 setName(name);
220 setValue(value);
221 setAttributeType(type);
222 setNamespace(namespace);
223 }
224
225 /**
226 * This will create a new <code>Attribute</code> with the
227 * specified (local) name and value, and does not place
228 * the attribute in a <code>{@link Namespace}</code>.
229 * <p>
230 * <b>Note</b>: This actually explicitly puts the
231 * <code>Attribute</code> in the "empty" <code>Namespace</code>
232 * (<code>{@link Namespace#NO_NAMESPACE}</code>).
233 *
234 * @param name <code>String</code> name of <code>Attribute</code>.
235 * @param value <code>String</code> value for new attribute.
236 * @throws IllegalNameException if the given name is illegal as an
237 * attribute name.
238 * @throws IllegalDataException if the given attribute value is
239 * illegal character data (as determined by
240 * {@link org.jdom.Verifier#checkCharacterData}).
241 */
242 public Attribute(final String name, final String value) {
243 this(name, value, AttributeType.UNDECLARED, Namespace.NO_NAMESPACE);
244 }
245
246 /**
247 * This will create a new <code>Attribute</code> with the
248 * specified (local) name, value and type, and does not place
249 * the attribute in a <code>{@link Namespace}</code>.
250 * <p>
251 * <b>Note</b>: This actually explicitly puts the
252 * <code>Attribute</code> in the "empty" <code>Namespace</code>
253 * (<code>{@link Namespace#NO_NAMESPACE}</code>).
254 *
255 * @param name <code>String</code> name of <code>Attribute</code>.
256 * @param value <code>String</code> value for new attribute.
257 * @param type <code>AttributeType</code> for new attribute.
258 * @throws IllegalNameException if the given name is illegal as an
259 * attribute name.
260 * @throws IllegalDataException if the given attribute value is
261 * illegal character data (as determined by
262 * {@link org.jdom.Verifier#checkCharacterData}) or
263 * if the given attribute type is not one of the
264 * supported types.
265 */
266 public Attribute(final String name, final String value, final AttributeType type) {
267 this(name, value, type, Namespace.NO_NAMESPACE);
268 }
269
270 /**
271 * This will create a new <code>Attribute</code> with the
272 * specified (local) name, value and type, and does not place
273 * the attribute in a <code>{@link Namespace}</code>.
274 * <p>
275 * <b>Note</b>: This actually explicitly puts the
276 * <code>Attribute</code> in the "empty" <code>Namespace</code>
277 * (<code>{@link Namespace#NO_NAMESPACE}</code>).
278 *
279 * @param name <code>String</code> name of <code>Attribute</code>.
280 * @param value <code>String</code> value for new attribute.
281 * @param type <code>int</code> type for new attribute.
282 * @throws IllegalNameException if the given name is illegal as an
283 * attribute name.
284 * @throws IllegalDataException if the given attribute value is
285 * illegal character data (as determined by
286 * {@link org.jdom.Verifier#checkCharacterData}) or
287 * if the given attribute type is not one of the
288 * supported types.
289 * @deprecated Use {@link #Attribute(String, String, AttributeType)}
290 */
291 @Deprecated
292 public Attribute(final String name, final String value, final int type) {
293 this(name, value, type, Namespace.NO_NAMESPACE);
294 }
295
296 /**
297 * This will return the parent of this <code>Attribute</code>.
298 * If there is no parent, then this returns <code>null</code>.
299 * Use return-type covariance to override Content's getParent() method
300 * to return an Element, not just a Parent
301 *
302 * @return parent of this <code>Attribute</code>
303 */
304 public Element getParent() {
305 return parent;
306 }
307
308 /**
309 * Get this Attribute's Document.
310 * @return The document to which this Attribute is associated, may be null.
311 */
312 public Document getDocument() {
313 return parent == null ? null : parent.getDocument();
314 }
315
316 /**
317 * This will retrieve the local name of the
318 * <code>Attribute</code>. For any XML attribute
319 * which appears as
320 * <code>[namespacePrefix]:[attributeName]</code>,
321 * the local name of the attribute would be
322 * <code>[attributeName]</code>. When the attribute
323 * has no namespace, the local name is simply the attribute
324 * name.
325 * <p>
326 * To obtain the namespace prefix for this
327 * attribute, the
328 * <code>{@link #getNamespacePrefix()}</code>
329 * method should be used.
330 *
331 * @return <code>String</code> - name of this attribute,
332 * without any namespace prefix.
333 */
334 public String getName() {
335 return name;
336 }
337
338 /**
339 * This sets the local name of the <code>Attribute</code>.
340 *
341 * @param name the new local name to set
342 * @return <code>Attribute</code> - the attribute modified.
343 * @throws IllegalNameException if the given name is illegal as an
344 * attribute name.
345 */
346 public Attribute setName(final String name) {
347 if (name == null) {
348 throw new NullPointerException(
349 "Can not set a null name for an Attribute.");
350 }
351 final String reason = Verifier.checkAttributeName(name);
352 if (reason != null) {
353 throw new IllegalNameException(name, "attribute", reason);
354 }
355 this.name = name;
356 specified = true;
357 return this;
358 }
359
360 /**
361 * This will retrieve the qualified name of the <code>Attribute</code>.
362 * For any XML attribute whose name is
363 * <code>[namespacePrefix]:[elementName]</code>,
364 * the qualified name of the attribute would be
365 * everything (both namespace prefix and
366 * element name). When the attribute has no
367 * namespace, the qualified name is simply the attribute's
368 * local name.
369 * <p>
370 * To obtain the local name of the attribute, the
371 * <code>{@link #getName()}</code> method should be used.
372 * <p>
373 * To obtain the namespace prefix for this attribute,
374 * the <code>{@link #getNamespacePrefix()}</code>
375 * method should be used.
376 *
377 * @return <code>String</code> - full name for this element.
378 */
379 public String getQualifiedName() {
380 // Note: Any changes here should be reflected in
381 // XMLOutputter.printQualifiedName()
382 final String prefix = namespace.getPrefix();
383
384 // no prefix found
385 if ("".equals(prefix)) {
386 return getName();
387 }
388 return new StringBuilder(prefix)
389 .append(':')
390 .append(getName())
391 .toString();
392 }
393
394 /**
395 * This will retrieve the namespace prefix of the
396 * <code>Attribute</code>. For any XML attribute
397 * which appears as
398 * <code>[namespacePrefix]:[attributeName]</code>,
399 * the namespace prefix of the attribute would be
400 * <code>[namespacePrefix]</code>. When the attribute
401 * has no namespace, an empty <code>String</code> is returned.
402 *
403 * @return <code>String</code> - namespace prefix of this
404 * attribute.
405 */
406 public String getNamespacePrefix() {
407 return namespace.getPrefix();
408 }
409
410 /**
411 * This returns the URI mapped to this <code>Attribute</code>'s
412 * prefix. If no mapping is found, an empty <code>String</code> is
413 * returned.
414 *
415 * @return <code>String</code> - namespace URI for this <code>Attribute</code>.
416 */
417 public String getNamespaceURI() {
418 return namespace.getURI();
419 }
420
421 /**
422 * This will return this <code>Attribute</code>'s
423 * <code>{@link Namespace}</code>.
424 *
425 * @return <code>Namespace</code> - Namespace object for this <code>Attribute</code>
426 */
427 public Namespace getNamespace() {
428 return namespace;
429 }
430
431 /**
432 * This sets this <code>Attribute</code>'s <code>{@link Namespace}</code>.
433 * If the provided namespace is null, the attribute will have no namespace.
434 * The namespace must have a prefix.
435 *
436 * @param namespace the new namespace
437 * @return <code>Element</code> - the element modified.
438 * @throws IllegalNameException if the new namespace is the default
439 * namespace. Attributes cannot be in a default namespace.
440 */
441 public Attribute setNamespace(Namespace namespace) {
442 if (namespace == null) {
443 namespace = Namespace.NO_NAMESPACE;
444 }
445
446 // Verify the attribute isn't trying to be in a default namespace
447 // Attributes can't be in a default namespace
448 if (namespace != Namespace.NO_NAMESPACE &&
449 "".equals(namespace.getPrefix())) {
450 throw new IllegalNameException("", "attribute namespace",
451 "An attribute namespace without a prefix can only be the " +
452 "NO_NAMESPACE namespace");
453 }
454 this.namespace = namespace;
455 specified = true;
456 return this;
457 }
458
459 /**
460 * This will return the actual textual value of this
461 * <code>Attribute</code>. This will include all text
462 * within the quotation marks.
463 *
464 * @return <code>String</code> - value for this attribute.
465 */
466 public String getValue() {
467 return value;
468 }
469
470 /**
471 * This will set the value of the <code>Attribute</code>.
472 *
473 * @param value <code>String</code> value for the attribute.
474 * @return <code>Attribute</code> - this Attribute modified.
475 * @throws IllegalDataException if the given attribute value is
476 * illegal character data (as determined by
477 * {@link org.jdom.Verifier#checkCharacterData}).
478 */
479 public Attribute setValue(final String value) {
480 if (value == null) {
481 throw new NullPointerException(
482 "Can not set a null value for an Attribute");
483 }
484 final String reason = Verifier.checkCharacterData(value);
485 if (reason != null) {
486 throw new IllegalDataException(value, "attribute", reason);
487 }
488 this.value = value;
489 specified = true;
490 return this;
491 }
492
493 /**
494 * This will return the declared type of this <code>Attribute</code>.
495 *
496 * @return <code>AttributeType</code> - type for this attribute.
497 */
498 public AttributeType getAttributeType() {
499 return type;
500 }
501
502 /**
503 * This will set the type of the <code>Attribute</code>.
504 *
505 * @param type <code>int</code> type for the attribute.
506 * @return <code>Attribute</code> - this Attribute modified.
507 * @throws IllegalDataException if the given attribute type is
508 * not one of the supported types.
509 */
510 public Attribute setAttributeType(final AttributeType type) {
511 this.type = type == null ? AttributeType.UNDECLARED : type;
512 specified = true;
513 return this;
514 }
515
516 /**
517 * This will set the type of the <code>Attribute</code>.
518 *
519 * @param type <code>int</code> type for the attribute.
520 * @return <code>Attribute</code> - this Attribute modified.
521 * @throws IllegalDataException if the given attribute type is
522 * not one of the supported types.
523 * @deprecated use {@link #setAttributeType(AttributeType)}
524 */
525 @Deprecated
526 public Attribute setAttributeType(final int type) {
527 setAttributeType(AttributeType.byIndex(type));
528 return this;
529 }
530
531 /**
532 * Get the 'specified' flag. True values indicate this attribute
533 * was part of an XML document, false indicates it was defaulted
534 * from a DTD.
535 * @return the specified flag.
536 * @since JDOM2
537 */
538 public boolean isSpecified() {
539 return specified;
540 }
541
542 /**
543 * Change the specified flag to the given value.
544 * @param specified The value to set the specified flag to.
545 * @since JDOM2
546 */
547 public void setSpecified(boolean specified) {
548 this.specified = specified;
549 }
550
551 /**
552 * This returns a <code>String</code> representation of the
553 * <code>Attribute</code>, suitable for debugging.
554 *
555 * @return <code>String</code> - information about the
556 * <code>Attribute</code>
557 */
558 @Override
559 public String toString() {
560 return new StringBuilder()
561 .append("[Attribute: ")
562 .append(getQualifiedName())
563 .append("=\"")
564 .append(value)
565 .append("\"")
566 .append("]")
567 .toString();
568 }
569
570 @Override
571 public Attribute clone() {
572 final Attribute clone = (Attribute) super.clone();
573 clone.parent = null;
574 return clone;
575 }
576
577 /**
578 * Detach this Attribute from its parent.
579 * @return this Attribute (detached).
580 */
581 public Attribute detach() {
582 if (parent != null) {
583 parent.removeAttribute(this);
584 }
585 return this;
586 }
587
588 /**
589 * Set this Attribute's parent. This is not public!
590 * @param parent The parent to set
591 * @return this Attribute (state may be indeterminate depending on whether
592 * this has been included in the Element's list yet).
593 */
594 protected Attribute setParent(Element parent) {
595 this.parent = parent;
596 return this;
597 }
598
599
600 /////////////////////////////////////////////////////////////////
601 // Convenience Methods below here
602 /////////////////////////////////////////////////////////////////
603
604 /**
605 * This gets the value of the attribute, in
606 * <code>int</code> form, and if no conversion
607 * can occur, throws a
608 * <code>{@link DataConversionException}</code>
609 *
610 * @return <code>int</code> value of attribute.
611 * @throws DataConversionException when conversion fails.
612 */
613 public int getIntValue() throws DataConversionException {
614 try {
615 return Integer.parseInt(value.trim());
616 } catch (final NumberFormatException e) {
617 throw new DataConversionException(name, "int");
618 }
619 }
620
621 /**
622 * This gets the value of the attribute, in
623 * <code>long</code> form, and if no conversion
624 * can occur, throws a
625 * <code>{@link DataConversionException}</code>
626 *
627 * @return <code>long</code> value of attribute.
628 * @throws DataConversionException when conversion fails.
629 */
630 public long getLongValue() throws DataConversionException {
631 try {
632 return Long.parseLong(value.trim());
633 } catch (final NumberFormatException e) {
634 throw new DataConversionException(name, "long");
635 }
636 }
637
638 /**
639 * This gets the value of the attribute, in
640 * <code>float</code> form, and if no conversion
641 * can occur, throws a
642 * <code>{@link DataConversionException}</code>
643 *
644 * @return <code>float</code> value of attribute.
645 * @throws DataConversionException when conversion fails.
646 */
647 public float getFloatValue() throws DataConversionException {
648 try {
649 // Avoid Float.parseFloat() to support JDK 1.1
650 return Float.valueOf(value.trim()).floatValue();
651 } catch (final NumberFormatException e) {
652 throw new DataConversionException(name, "float");
653 }
654 }
655
656 /**
657 * This gets the value of the attribute, in
658 * <code>double</code> form, and if no conversion
659 * can occur, throws a
660 * <code>{@link DataConversionException}</code>
661 *
662 * @return <code>double</code> value of attribute.
663 * @throws DataConversionException when conversion fails.
664 */
665 public double getDoubleValue() throws DataConversionException {
666 try {
667 // Avoid Double.parseDouble() to support JDK 1.1
668 return Double.valueOf(value.trim()).doubleValue();
669 } catch (final NumberFormatException e) {
670 // Specially handle INF and -INF that Double.valueOf doesn't do
671 String v = value.trim();
672 if ("INF".equals(v)) {
673 return Double.POSITIVE_INFINITY;
674 }
675 if ("-INF".equals(v)) {
676 return Double.NEGATIVE_INFINITY;
677 }
678 throw new DataConversionException(name, "double");
679 }
680 }
681
682 /**
683 * This gets the effective boolean value of the attribute, or throws a
684 * <code>{@link DataConversionException}</code> if a conversion can't be
685 * performed. True values are: "true", "on", "1", and "yes". False
686 * values are: "false", "off", "0", and "no". Values are trimmed before
687 * comparison. Values other than those listed here throw the exception.
688 *
689 * @return <code>boolean</code> value of attribute.
690 * @throws DataConversionException when conversion fails.
691 */
692 public boolean getBooleanValue() throws DataConversionException {
693 final String valueTrim = value.trim();
694 if (
695 (valueTrim.equalsIgnoreCase("true")) ||
696 (valueTrim.equalsIgnoreCase("on")) ||
697 (valueTrim.equalsIgnoreCase("1")) ||
698 (valueTrim.equalsIgnoreCase("yes"))) {
699 return true;
700 } else if (
701 (valueTrim.equalsIgnoreCase("false")) ||
702 (valueTrim.equalsIgnoreCase("off")) ||
703 (valueTrim.equalsIgnoreCase("0")) ||
704 (valueTrim.equalsIgnoreCase("no"))
705 ) {
706 return false;
707 } else {
708 throw new DataConversionException(name, "boolean");
709 }
710 }
711
712 /**
713 * Get the namespaces that are in-scope on this Attribute.
714 * <p>
715 * Attribute has peculiarities that affect the in-scope Namespaces because
716 * there are conditions in which the Attribute's scope is different to its
717 * parent Element's scope. Specifically, if the parent Element is in a
718 * 'default' Namespace that is not the empty Namespace (e.g.
719 * xmlns="someurl") and this Attribute is also in the default Namespace (has
720 * no prefix - but for Attributes that means the Namespace URL is ""), then
721 * this Attribute has a different namespace scope from it's parent Element
722 * because it does not include the 'someurl' Namespace.
723 * <p>
724 * In the above conditions (no-prefix Attribute in an Element with a
725 * non-empty no-prefix Namespace) this Attribute effectively re-binds the ""
726 * prefix to the "" URL, thus the Attribute 'introduces' the Namespace.
727 * It follows then that the getNamespacesIntroduced() will return a list
728 * with the single member {@link Namespace#NO_NAMESPACE}.
729 * <p>
730 * Note that the Attribute's Namespace will always be reported first.
731 * <p>
732 * <strong>Description copied from</strong>
733 * {@link NamespaceAware#getNamespacesInScope()}:
734 * <p>
735 * {@inheritDoc}
736 */
737 @Override
738 public List<Namespace> getNamespacesInScope() {
739 if (getParent() == null) {
740 ArrayList<Namespace> ret = new ArrayList<Namespace>(3);
741 ret.add(getNamespace());
742 ret.add(Namespace.XML_NAMESPACE);
743 return Collections.unmodifiableList(ret);
744 }
745 return orderFirst(getNamespace(), getParent().getNamespacesInScope());
746 }
747
748 @Override
749 public List<Namespace> getNamespacesIntroduced() {
750 if (getParent() == null) {
751 return Collections.singletonList(getNamespace());
752 }
753 return Collections.emptyList();
754 }
755
756 @Override
757 public List<Namespace> getNamespacesInherited() {
758 if (getParent() == null) {
759 return Collections.singletonList(Namespace.XML_NAMESPACE);
760 }
761 return orderFirst(getNamespace(), getParent().getNamespacesInScope());
762 }
763
764
765 private static final List<Namespace> orderFirst(final Namespace nsa,
766 final List<Namespace> nsl) {
767 if (nsl.get(0) == nsa) {
768 return nsl;
769 }
770 // OK, we have our namespace list, but our's is not the first.
771 // we need the Attribute's Namespace to be up front.
772 TreeMap<String,Namespace> tm = new TreeMap<String, Namespace>();
773 for (Namespace ns : nsl) {
774 if (ns != nsa) {
775 tm.put(ns.getPrefix(), ns);
776 }
777 }
778 ArrayList<Namespace> ret = new ArrayList<Namespace>(tm.size() + 1);
779 ret.add(nsa);
780 ret.addAll(tm.values());
781 return Collections.unmodifiableList(ret);
782 }
783
784 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.*;
57
58 import org.jdom.internal.ArrayCopy;
59
60 /**
61 * <code>AttributeList</code> represents legal JDOM
62 * <code>{@link Attribute}</code> content.
63 * <p>
64 * This class is NOT PUBLIC; users should see it as a simple List
65 * implementation, although it behaves something like a Set because you cannot
66 * add duplicate Attributes. An attribute is considered duplicate if it has the
67 * same Namespace URI and Attribute name as another existing Attribute.
68 *
69 * @author Alex Rosen
70 * @author Philippe Riand
71 * @author Bradley S. Huffman
72 * @author Rolf Lear
73 */
74 final class AttributeList extends AbstractList<Attribute>
75 implements RandomAccess {
76
77 /** The initial size to start the backing array. */
78 private static final int INITIAL_ARRAY_SIZE = 4;
79
80 /** The backing array */
81 private Attribute attributeData[];
82
83 /** The current size */
84 private int size;
85
86 /** The parent Element */
87 private final Element parent;
88
89 private static final Comparator<Attribute> ATTRIBUTE_NATURAL = new Comparator<Attribute>() {
90
91 @Override
92 public int compare(Attribute a1, Attribute a2) {
93 int pcomp = a1.getNamespacePrefix().compareTo(a2.getNamespacePrefix());
94 if (pcomp != 0) {
95 return pcomp;
96 }
97 return a1.getName().compareTo(a2.getName());
98 }
99
100 };
101
102 /**
103 * Create a new instance of the AttributeList representing <i>parent</i>
104 * Element's Attributes
105 *
106 * @param parent
107 * Element whose Attributes are to be held
108 */
109 AttributeList(final Element parent) {
110 this.parent = parent;
111 }
112
113 /**
114 * Package internal method to support building from sources that are 100%
115 * trusted.
116 *
117 * @param a
118 * an Attribute to add without any checks
119 */
120 final void uncheckedAddAttribute(final Attribute a) {
121 a.parent = parent;
122 ensureCapacity(size + 1);
123 attributeData[size++] = a;
124 modCount++;
125 }
126
127 /**
128 * Check and add <i>attribute</i> to the end of the list or replace an
129 * existing <code>Attribute</code> with the same name and
130 * <code>Namespace</code>.
131 *
132 * @param attribute
133 * The <code>Attribute</code> to insert into the list.
134 * @return true as specified by <code>Collection.add()</code>.
135 * @throws IllegalAddException
136 * if validation rules prevent the add
137 */
138 @Override
139 public boolean add(final Attribute attribute) {
140 if (attribute.getParent() != null) {
141 throw new IllegalAddException(
142 "The attribute already has an existing parent \""
143 + attribute.getParent().getQualifiedName() + "\"");
144 }
145
146 if (Verifier.checkNamespaceCollision(attribute, parent) != null) {
147 throw new IllegalAddException(parent, attribute,
148 Verifier.checkNamespaceCollision(attribute, parent));
149 }
150
151 // returns -1 if not exist
152 final int duplicate = indexOfDuplicate(attribute);
153 if (duplicate < 0) {
154 attribute.setParent(parent);
155 ensureCapacity(size + 1);
156 attributeData[size++] = attribute;
157 modCount++;
158 } else {
159 final Attribute old = attributeData[duplicate];
160 old.setParent(null);
161 attributeData[duplicate] = attribute;
162 attribute.setParent(parent);
163 }
164 return true;
165 }
166
167 /**
168 * Check and add <i>attribute</i> to this list at <i>index</i>.
169 *
170 * @param index
171 * where to add/insert the <code>Attribute</code>
172 * @param attribute
173 * <code>Attribute</code> to add
174 * @throws IllegalAddException
175 * if validation rules prevent the add
176 */
177 @Override
178 public void add(final int index, final Attribute attribute) {
179 if (index < 0 || index > size) {
180 throw new IndexOutOfBoundsException("Index: " + index +
181 " Size: " + size());
182 }
183
184 if (attribute.getParent() != null) {
185 throw new IllegalAddException(
186 "The attribute already has an existing parent \"" +
187 attribute.getParent().getQualifiedName() + "\"");
188 }
189 final int duplicate = indexOfDuplicate(attribute);
190 if (duplicate >= 0) {
191 throw new IllegalAddException("Cannot add duplicate attribute");
192 }
193
194 final String reason = Verifier.checkNamespaceCollision(attribute, parent);
195 if (reason != null) {
196 throw new IllegalAddException(parent, attribute, reason);
197 }
198
199 attribute.setParent(parent);
200
201 ensureCapacity(size + 1);
202 if (index == size) {
203 attributeData[size++] = attribute;
204 } else {
205 System.arraycopy(attributeData, index, attributeData, index + 1,
206 size - index);
207 attributeData[index] = attribute;
208 size++;
209 }
210 modCount++;
211 }
212
213 /**
214 * Add all the <code>Attributes</code> in <i>collection</i>.
215 *
216 * @param collection
217 * The <code>Collection</code> of <code>Attributes</code> to add.
218 * @return <code>true</code> if the list was modified as a result of the
219 * add.
220 * @throws IllegalAddException
221 * if validation rules prevent the addAll
222 */
223 @Override
224 public boolean addAll(final Collection<? extends Attribute> collection) {
225 return addAll(size(), collection);
226 }
227
228 /**
229 * Inserts the <code>Attributes</code> in <i>collection</i> at the specified
230 * <i>index</i> in this list.
231 *
232 * @param index
233 * The offset at which to start adding the <code>Attributes</code>
234 * @param collection
235 * The <code>Collection</code> containing the <code>Attributes</code>
236 * to add.
237 * @return <code>true</code> if the list was modified as a result of the
238 * add.
239 * @throws IllegalAddException
240 * if validation rules prevent the addAll
241 */
242 @Override
243 public boolean addAll(final int index,
244 final Collection<? extends Attribute> collection) {
245 if (index < 0 || index > size) {
246 throw new IndexOutOfBoundsException("Index: " + index +
247 " Size: " + size());
248 }
249
250 if (collection == null) {
251 throw new NullPointerException(
252 "Can not add a null Collection to AttributeList");
253 }
254 final int addcnt = collection.size();
255 if (addcnt == 0) {
256 return false;
257 }
258 if (addcnt == 1) {
259 // quick check for single-add.
260 add(index, collection.iterator().next());
261 return true;
262 }
263
264 ensureCapacity(size() + addcnt);
265
266 final int tmpmodcount = modCount;
267 boolean ok = false;
268
269 int count = 0;
270
271 try {
272 for (Attribute att : collection) {
273 add(index + count, att);
274 count++;
275 }
276 ok = true;
277 } finally {
278 if (!ok) {
279 while (--count >= 0) {
280 remove(index + count);
281 }
282 modCount = tmpmodcount;
283 }
284 }
285
286 return true;
287 }
288
289 /**
290 * Clear the current list.
291 */
292 @Override
293 public void clear() {
294 if (attributeData != null) {
295 while (size > 0) {
296 size--;
297 attributeData[size].setParent(null);
298 attributeData[size] = null;
299 }
300 }
301 modCount++;
302 }
303
304 /**
305 * Clear the current list and set it to the contents of <i>collection</i>.
306 *
307 * @param collection
308 * The <code>Collection</code> to use.
309 * @throws IllegalAddException
310 * if validation rules prevent the addAll
311 */
312 void clearAndSet(final Collection<? extends Attribute> collection) {
313 if (collection == null || collection.isEmpty()) {
314 clear();
315 return;
316 }
317
318 // keep a backup in case we need to roll-back...
319 final Attribute[] old = attributeData;
320 final int oldSize = size;
321 final int oldModCount = modCount;
322
323 // clear the current system
324 // we need to detatch before we add so that we don't run in to a problem
325 // where an attribute in the to-add list is one that we are 'clearing'
326 // first.
327 while (size > 0) {
328 old[--size].setParent(null);
329 }
330 size = 0;
331 attributeData = null;
332
333 boolean ok = false;
334 try {
335 addAll(0, collection);
336 ok = true;
337 } finally {
338 if (!ok) {
339 // we have an exception pending....
340 // restore the old system.
341 // re-attach the old stuff
342 attributeData = old;
343 while (size < oldSize) {
344 attributeData[size++].setParent(parent);
345 }
346 modCount = oldModCount;
347 }
348 }
349
350 }
351
352 /**
353 * Increases the capacity of this <code>AttributeList</code> instance, if
354 * necessary, to ensure that it can hold at least the number of items
355 * specified by the minimum capacity argument.
356 *
357 * @param minCapacity
358 * the desired minimum capacity.
359 */
360 private void ensureCapacity(final int minCapacity) {
361 if (attributeData == null) {
362 attributeData =
363 new Attribute[Math.max(minCapacity, INITIAL_ARRAY_SIZE)];
364 return;
365 } else if (minCapacity < attributeData.length) {
366 return;
367 }
368 // most JVM's allocate memory in multiples of 'double-words', on
369 // 64-bit it's 16-bytes, on 32-bit it's 8 bytes which all means it makes
370 // sense to increment the capacity in even values.
371 attributeData = ArrayCopy.copyOf(attributeData,
372 ((minCapacity + INITIAL_ARRAY_SIZE) >>> 1) << 1);
373 }
374
375 /**
376 * Retrieve the <code>Attribute</code> at <i>offset</i>.
377 *
378 * @param index
379 * The position of the <code>Attribute</code> to retrieve.
380 * @return The <code>Attribute</code> at position <i>index</i>.
381 */
382 @Override
383 public Attribute get(final int index) {
384 if (index < 0 || index >= size) {
385 throw new IndexOutOfBoundsException("Index: " + index +
386 " Size: " + size());
387 }
388
389 return attributeData[index];
390 }
391
392 /**
393 * Retrieve the <code>Attribute</code> with the given name and the same
394 * <code>Namespace</code> URI as <i>namespace</i>.
395 *
396 * @param name
397 * name of attribute to return
398 * @param namespace
399 * indicate what <code>Namespace</code> URI to consider
400 * @return the <code>Attribute</code>, or null if one doesn't exist.
401 */
402 Attribute get(final String name, final Namespace namespace) {
403 final int index = indexOf(name, namespace);
404 if (index < 0) {
405 return null;
406 }
407 return attributeData[index];
408 }
409
410 /**
411 * Return index of the <code>Attribute</code> with the given <i>name</i> and
412 * the same Namespace URI as <i>namespace</i>.
413 *
414 * @param name
415 * name of <code>Attribute</code> to retrieve
416 * @param namespace
417 * indicate what <code>Namespace</code> URI to consider
418 * @return the index of the attribute that matches the conditions, or
419 * <code>-1</code> if there is none.
420 */
421 int indexOf(final String name, final Namespace namespace) {
422 if (attributeData != null) {
423 if (namespace == null) {
424 return indexOf(name, Namespace.NO_NAMESPACE);
425 }
426 final String uri = namespace.getURI();
427 for (int i = 0; i < size; i++) {
428 final Attribute att = attributeData[i];
429 if (uri.equals(att.getNamespaceURI()) &&
430 name.equals(att.getName())) {
431 return i;
432 }
433 }
434 }
435 return -1;
436 }
437
438 /**
439 * Remove the <code>Attribute</code> at <i>index</i>.
440 *
441 * @param index
442 * The offset of the <code>Attribute</code> to remove.
443 * @return The removed <code>Attribute</code>.
444 */
445 @Override
446 public Attribute remove(final int index) {
447 if (index < 0 || index >= size)
448 throw new IndexOutOfBoundsException("Index: " + index +
449 " Size: " + size());
450
451 final Attribute old = attributeData[index];
452 old.setParent(null);
453 System.arraycopy(attributeData, index + 1, attributeData, index,
454 size - index - 1);
455 attributeData[--size] = null; // Let gc do its work
456 modCount++;
457 return old;
458 }
459
460 /**
461 * Remove the <code>Attribute</code> with the specified name and the same
462 * URI as <i>namespace</i>.
463 *
464 * @param name
465 * name of <code>Attribute</code> to remove
466 * @param namespace
467 * indicate what <code>Namespace</code> URI to consider
468 * @return the <code>true</code> if attribute was removed,
469 * <code>false</code> otherwise
470 */
471 boolean remove(final String name, final Namespace namespace) {
472 final int index = indexOf(name, namespace);
473 if (index < 0) {
474 return false;
475 }
476 remove(index);
477 return true;
478 }
479
480 /**
481 * Set the <code>Attribute</code> at <i>index</i> to be <i>attribute</i>.
482 *
483 * @param index
484 * The location to set the value to.
485 * @param attribute
486 * The <code>Attribute</code> to set.
487 * @return The replaced <code>Attribute</code>.
488 * @throws IllegalAddException
489 * if validation rules prevent the set
490 */
491 @Override
492 public Attribute set(final int index, final Attribute attribute) {
493 if (index < 0 || index >= size)
494 throw new IndexOutOfBoundsException("Index: " + index +
495 " Size: " + size());
496
497 if (attribute.getParent() != null) {
498 throw new IllegalAddException(
499 "The attribute already has an existing parent \"" +
500 attribute.getParent().getQualifiedName() + "\"");
501 }
502
503 final int duplicate = indexOfDuplicate(attribute);
504 if ((duplicate >= 0) && (duplicate != index)) {
505 throw new IllegalAddException("Cannot set duplicate attribute");
506 }
507
508 final String reason = Verifier.checkNamespaceCollision(attribute, parent, index);
509 if (reason != null) {
510 throw new IllegalAddException(parent, attribute, reason);
511 }
512
513 final Attribute old = attributeData[index];
514 old.setParent(null);
515
516 attributeData[index] = attribute;
517 attribute.setParent(parent);
518 return old;
519 }
520
521 /**
522 * Return index of attribute with same name and Namespace, or -1 if one
523 * doesn't exist
524 */
525 private int indexOfDuplicate(final Attribute attribute) {
526 return indexOf(attribute.getName(), attribute.getNamespace());
527 }
528
529 /**
530 * Returns an <code>Iterator</code> over the <code>Attributes</code> in this
531 * list in the proper sequence.
532 *
533 * @return an iterator.
534 */
535 @Override
536 public Iterator<Attribute> iterator() {
537 return new ALIterator();
538 }
539
540 /**
541 * Return the number of <code>Attributes</code> in this list
542 *
543 * @return The number of <code>Attributes</code> in this list.
544 */
545 @Override
546 public int size() {
547 return size;
548 }
549
550 @Override
551 public boolean isEmpty() {
552 return size == 0;
553 }
554
555 /**
556 * Return this list as a <code>String</code>
557 */
558 @Override
559 public String toString() {
560 return super.toString();
561 }
562
563 /**
564 * Unlike the Arrays.binarySearch, this method never expects an
565 * "already exists" condition, we only ever add, thus there will never
566 * be a negative insertion-point.
567 * @param indexes The pointers to search within
568 * @param len The number of pointers to search within
569 * @param val The pointer we are checking for.
570 * @param comp The Comparator to compare with
571 * @return the insertion point.
572 */
573 private final int binarySearch(final int[] indexes, final int len,
574 final int val, final Comparator<? super Attribute> comp) {
575 int left = 0, mid = 0, right = len - 1, cmp = 0;
576 final Attribute base = attributeData[val];
577 while (left <= right) {
578 mid = (left + right) >>> 1;
579 cmp = comp.compare(base, attributeData[indexes[mid]]);
580 if (cmp == 0) {
581 while (cmp == 0 && mid < right && comp.compare(
582 base, attributeData[indexes[mid + 1]]) == 0) {
583 mid++;
584 }
585 return mid + 1;
586 } else if (cmp < 0) {
587 right = mid - 1;
588 } else {
589 left = mid + 1;
590 }
591 }
592 return left;
593 }
594
595 private void sortInPlace(final int[] indexes) {
596 // the indexes are a discrete set of values that have no duplicates,
597 // and describe the relative order of each of them.
598 // as a result, we can do some tricks....
599 final int[] unsorted = ArrayCopy.copyOf(indexes, indexes.length);
600 Arrays.sort(unsorted);
601 final Attribute[] usc = new Attribute[unsorted.length];
602 for (int i = 0; i < usc.length; i++) {
603 usc[i] = attributeData[indexes[i]];
604 }
605 // usc contains the content in their pre-sorted order....
606 for (int i = 0; i < indexes.length; i ++) {
607 attributeData[unsorted[i]] = usc[i];
608 }
609 }
610
611 /**
612 * Sort the attributes using the supplied comparator. The attributes are
613 * never added using regular mechanisms, so there are never problems with
614 * detached or already-attached Attributes. The sort happens 'in place'.
615 * <p>
616 * If the comparator identifies two (or more) Attributes to be equal, then
617 * the relative order of those attributes will not be changed.
618 *
619 * @param comp The Comparator to use for sorting.
620 */
621 public void sort(Comparator<? super Attribute> comp) {
622 if (comp == null) {
623 comp = ATTRIBUTE_NATURAL;
624 }
625 final int sz = size;
626 int[] indexes = new int[sz];
627 for (int i = 0 ; i < sz; i++) {
628 final int ip = binarySearch(indexes, i, i, comp);
629 if (ip < i) {
630 System.arraycopy(indexes, ip, indexes, ip+1, i - ip);
631 }
632 indexes[ip] = i;
633 }
634 sortInPlace(indexes);
635 }
636
637 /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * */
638 /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * */
639 /**
640 * A fast iterator that can beat AbstractList because we can access the data
641 * directly. This is important because so much code now uses the for-each
642 * type loop <code>for (Attribute a : element.getAttributes()) {...}</code>,
643 * and that uses iterator().
644 *
645 * @author Rolf Lear
646 */
647 private final class ALIterator implements Iterator<Attribute> {
648 // The modCount to expect (or throw ConcurrentModeEx)
649 private int expect = -1;
650 // the index of the next Attribute to return.
651 private int cursor = 0;
652 // whether it is legal to call remove()
653 private boolean canremove = false;
654
655 private ALIterator() {
656 expect = modCount;
657 }
658
659 @Override
660 public boolean hasNext() {
661 return cursor < size;
662 }
663
664 @Override
665 public Attribute next() {
666 if (modCount != expect) {
667 throw new ConcurrentModificationException("ContentList was " +
668 "modified outside of this Iterator");
669 }
670 if (cursor >= size) {
671 throw new NoSuchElementException("Iterated beyond the end of " +
672 "the ContentList.");
673 }
674 canremove = true;
675 return attributeData[cursor++];
676 }
677
678 @Override
679 public void remove() {
680 if (modCount != expect) {
681 throw new ConcurrentModificationException("ContentList was " +
682 "modified outside of this Iterator");
683 }
684 if (!canremove) {
685 throw new IllegalStateException("Can only remove() content " +
686 "after a call to next()");
687 }
688 AttributeList.this.remove(--cursor);
689 expect = modCount;
690 canremove = false;
691 }
692
693 }
694
695 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import org.xml.sax.Attributes;
57
58 /**
59 * Use a simple enumeration for the Attribute Types
60 *
61 * @author Rolf Lear
62 *
63 */
64 public enum AttributeType {
65
66 /**
67 * Attribute type: the attribute has not been declared or type
68 * is unknown.
69 *
70 * @see #getAttributeType
71 */
72 UNDECLARED,
73
74 /**
75 * Attribute type: the attribute value is a string.
76 *
77 * @see Attribute#getAttributeType
78 */
79 CDATA,
80
81 /**
82 * Attribute type: the attribute value is a unique identifier.
83 *
84 * @see #getAttributeType
85 */
86 ID,
87
88 /**
89 * Attribute type: the attribute value is a reference to a
90 * unique identifier.
91 *
92 * @see #getAttributeType
93 */
94 IDREF,
95
96 /**
97 * Attribute type: the attribute value is a list of references to
98 * unique identifiers.
99 *
100 * @see #getAttributeType
101 */
102 IDREFS,
103 /**
104 * Attribute type: the attribute value is the name of an entity.
105 *
106 * @see #getAttributeType
107 */
108 ENTITY,
109 /**
110 * <p>
111 * Attribute type: the attribute value is a list of entity names.
112 * </p>
113 *
114 * @see #getAttributeType
115 */
116 ENTITIES,
117
118 /**
119 * Attribute type: the attribute value is a name token.
120 * <p>
121 * According to SAX 2.0 specification, attributes of enumerated
122 * types should be reported as "NMTOKEN" by SAX parsers. But the
123 * major parsers (Xerces and Crimson) provide specific values
124 * that permit to recognize them as {@link #ENUMERATION}.
125 *
126 * @see Attribute#getAttributeType
127 */
128 NMTOKEN,
129 /**
130 * Attribute type: the attribute value is a list of name tokens.
131 *
132 * @see #getAttributeType
133 */
134 NMTOKENS,
135 /**
136 * Attribute type: the attribute value is the name of a notation.
137 *
138 * @see #getAttributeType
139 */
140 NOTATION,
141 /**
142 * Attribute type: the attribute value is a name token from an
143 * enumeration.
144 *
145 * @see #getAttributeType
146 */
147 ENUMERATION;
148
149 /**
150 * Obtain a AttributeType by a int constant.
151 * This goes against the logic of enums, but this is used for backward
152 * compatibility. Thus, this method is marked Deprecated.
153 * @param index The AttributeType int equivalent to retrieve
154 * @return The AttributeType corresponding to the specified equivalent
155 * @throws IllegalArgumentException if there is no equivalent
156 * @deprecated Use normal Enums instead of int's
157 */
158 @Deprecated
159 public static final AttributeType byIndex(int index) {
160 if (index < 0) {
161 throw new IllegalDataException("No such AttributeType " + index);
162 }
163 if (index >= values().length) {
164 throw new IllegalDataException("No such AttributeType " +
165 index + ", max is " + (values().length - 1));
166 }
167 return values()[index];
168 }
169
170 /**
171 * Returns the the JDOM AttributeType value from the SAX 2.0
172 * attribute type string provided by the parser.
173 *
174 * @param typeName <code>String</code> the SAX 2.0 attribute
175 * type string.
176 *
177 * @return <code>int</code> the JDOM attribute type.
178 *
179 * @see Attribute#setAttributeType
180 * @see Attributes#getType
181 */
182 public static final AttributeType getAttributeType(String typeName) {
183 if (typeName == null) {
184 return UNDECLARED;
185 }
186
187 try {
188 return valueOf(typeName);
189 } catch (IllegalArgumentException iae) {
190 if (typeName.length() > 0 &&
191 typeName.trim().charAt(0) == '(') {
192 // Xerces 1.4.X reports attributes of enumerated type with
193 // a type string equals to the enumeration definition, i.e.
194 // starting with a parenthesis.
195 return ENUMERATION;
196 }
197 return UNDECLARED;
198 }
199
200 }
201
202 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import org.jdom.output.XMLOutputter2;
57
58 /**
59 * An XML CDATA section. Represents character-based content within an XML
60 * document that should be output within special CDATA tags. Semantically it's
61 * identical to a simple {@link Text} object, but output behavior is different.
62 * CDATA makes no guarantees about the underlying textual representation of
63 * character data, but does expose that data as a Java String.
64 *
65 * @author Dan Schaffer
66 * @author Brett McLaughlin
67 * @author Jason Hunter
68 * @author Bradley S. Huffman
69 * @author Victor Toni
70 * @author Rolf Lear
71 */
72 public class CDATA extends Text {
73
74 /**
75 * JDOM 2.0.0 Serialization version. CDATA is simple
76 */
77 private static final long serialVersionUID = 200L;
78
79 /**
80 * This is the protected, no-args constructor standard in all JDOM
81 * classes. It allows subclassers to get a raw instance with no
82 * initialization.
83 */
84 protected CDATA() {
85 super(CType.CDATA);
86 }
87
88 /**
89 * This constructor creates a new <code>CDATA</code> node, with the
90 * supplied string value as it's character content.
91 *
92 * @param string the node's character content.
93 * @throws IllegalDataException if <code>str</code> contains an
94 * illegal character such as a vertical tab (as determined
95 * by {@link org.jdom.Verifier#checkCharacterData})
96 * or the CDATA end delimiter <code>]]&gt;</code>.
97 */
98 public CDATA(final String string) {
99 super(CType.CDATA);
100 setText(string);
101 }
102
103 /**
104 * This will set the value of this <code>CDATA</code> node.
105 *
106 * @param str value for node's content.
107 * @return the object on which the method was invoked
108 * @throws IllegalDataException if <code>str</code> contains an
109 * illegal character such as a vertical tab (as determined
110 * by {@link org.jdom.Verifier#checkCharacterData})
111 * or the CDATA end delimiter <code>]]&gt;</code>.
112 */
113 @Override
114 public CDATA setText(final String str) {
115 // Overrides Text.setText() because this needs to check that CDATA rules
116 // are enforced. We could have a separate Verifier check for CDATA
117 // beyond Text and call that alone before super.setText().
118
119 if (str == null || "".equals(str)) {
120 value = EMPTY_STRING;
121 return this;
122 }
123
124 final String reason = Verifier.checkCDATASection(str);
125 if (reason != null) {
126 throw new IllegalDataException(str, "CDATA section", reason);
127 }
128
129 value = str;
130
131 return this;
132 }
133
134 /**
135 * This will append character content to whatever content already
136 * exists within this <code>CDATA</code> node.
137 *
138 * @param str character content to append.
139 * @throws IllegalDataException if <code>str</code> contains an
140 * illegal character such as a vertical tab (as determined
141 * by {@link org.jdom.Verifier#checkCharacterData})
142 * or the CDATA end delimiter <code>]]&gt;</code>.
143 */
144 @Override
145 public void append(final String str) {
146 // Overrides Text.append(String) because this needs to check that CDATA
147 // rules are enforced. We could have a separate Verifier check for CDATA
148 // beyond Text and call that alone before super.setText().
149
150 if (str == null || "".equals(str)) {
151 return;
152 }
153
154 // we need a temp value to ensure that the value is changed _after_
155 // validation
156 final String tmpValue;
157 if (value == EMPTY_STRING) {
158 tmpValue = str;
159 } else {
160 tmpValue = value + str;
161 }
162
163 // we have to do late checking since the end of a CDATA section could
164 // have been created by concating both strings:
165 // "]" + "]>"
166 // or
167 // "]]" + ">"
168 // TODO: maybe this could be optimized for this two cases
169 final String reason = Verifier.checkCDATASection(tmpValue);
170 if (reason != null) {
171 throw new IllegalDataException(str, "CDATA section", reason);
172 }
173
174 value = tmpValue;
175 }
176
177 /**
178 * This will append the content of another <code>Text</code> node
179 * to this node.
180 *
181 * @param text Text node to append.
182 */
183 @Override
184 public void append(final Text text) {
185 // Overrides Text.append(Text) because this needs to check that CDATA
186 // rules are enforced. We could have a separate Verifier check for CDATA
187 // beyond Text and call that alone before super.setText().
188
189 if (text == null) {
190 return;
191 }
192 append(text.getText());
193 }
194
195 /**
196 * This returns a <code>String</code> representation of the
197 * <code>CDATA</code> node, suitable for debugging. If the XML
198 * representation of the <code>CDATA</code> node is desired,
199 * either <code>{@link #getText}</code> or
200 * {@link XMLOutputter2#output(CDATA, java.io.Writer)}</code>
201 * should be used.
202 *
203 * @return <code>String</code> - information about this node.
204 */
205 @Override
206 public String toString() {
207 return new StringBuilder(64)
208 .append("[CDATA: ")
209 .append(getText())
210 .append("]")
211 .toString();
212 }
213
214 @Override
215 public CDATA clone() {
216 return (CDATA)super.clone();
217 }
218
219 @Override
220 public CDATA detach() {
221 return (CDATA)super.detach();
222 }
223
224 @Override
225 protected CDATA setParent(Parent parent) {
226 return (CDATA)super.setParent(parent);
227 }
228
229 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 /**
57 * This simple class just tidies up any cloneable classes. This method deals
58 * with any CloneNotSupported exceptions. THis class is package private only.
59 *
60 * @author Rolf Lear
61 */
62 class CloneBase implements Cloneable {
63
64 /**
65 * Change the permission of the no-arg constructor from public to protcted.
66 * <p>
67 * Otherwise package-private class's constructor is not really public. Changing this to
68 * 'protected' makes this constructor available to all subclasses regardless of the
69 * subclass's package. This in turn makes it possible to make all th subclasses of this
70 * CloneBase class serializable.
71 *
72 */
73 protected CloneBase() {
74 // This constructor is needed to solve issue #88
75 // There needs to be a no-arg constructor accessible by all
76 // potential subclasses of CloneBase, and 'protected' is actually more
77 // accessible than 'public' since this is a package-private class.
78 }
79
80 /**
81 * Return a deep clone of this instance. Even if this instance has a parent,
82 * the returned clone will not.
83 * <p>
84 * All JDOM core classes are Cloneable, and never throw
85 * CloneNotSupportedException. Additionally all Cloneable JDOM classes
86 * return the correct type of instance from this method and there is no
87 * need to cast the result (co-variant return vaue).
88 * <p>
89 * Subclasses of this should still call super.clone() in their clone method.
90 */
91 @Override
92 protected CloneBase clone() {
93 /*
94 * Additionally, when you use the concept of 'co-variant return values'
95 * you create 'bridge' methods. By way of example, because we change the
96 * return type of clone() from Object to CloneBase, Java is forced to
97 * put in a 'bridge' method that has an Object return type, even though
98 * we never actually call it. <p> This has an impact on the code
99 * coverage tool Cobertura, which reports that there is missed code (and
100 * there is, the bridge method). It reports it as being '0' calls to the
101 * 'class' line (the class line is marked red). By making this CloneBase
102 * code do the first level of co-variant return, it is this class which
103 * is victim of the Cobertura reporting, not the multiple subclasses
104 * (like Attribute, Document, Content, etc.).
105 */
106 try {
107 return (CloneBase) super.clone();
108 } catch (CloneNotSupportedException e) {
109 throw new IllegalStateException(String.format(
110 "Unable to clone class %s which should always support it.",
111 this.getClass().getName()), e);
112 }
113 }
114
115 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56
57 import org.jdom.output.XMLOutputter2;
58
59 /**
60 * An XML comment. Methods allow the user to get and set the text of the
61 * comment.
62 *
63 * @author Brett McLaughlin
64 * @author Jason Hunter
65 */
66 public class Comment extends Content {
67
68 /**
69 * JDOM2 Serialization. In this case, Comment is simple.
70 */
71 private static final long serialVersionUID = 200L;
72
73 /** Text of the <code>Comment</code> */
74 protected String text;
75
76 /**
77 * Default, no-args constructor for implementations to use if needed.
78 */
79 protected Comment() {
80 super(CType.Comment);
81 }
82
83 /**
84 * This creates the comment with the supplied text.
85 *
86 * @param text <code>String</code> content of comment.
87 */
88 public Comment(String text) {
89 super(CType.Comment);
90 setText(text);
91 }
92
93
94 /**
95 * Returns the XPath 1.0 string value of this element, which is the
96 * text of this comment.
97 *
98 * @return the text of this comment
99 */
100 @Override
101 public String getValue() {
102 return text;
103 }
104
105 /**
106 * This returns the textual data within the <code>Comment</code>.
107 *
108 * @return <code>String</code> - text of comment.
109 */
110 public String getText() {
111 return text;
112 }
113
114 /**
115 * This will set the value of the <code>Comment</code>.
116 *
117 * @param text <code>String</code> text for comment.
118 * @return <code>Comment</code> - this Comment modified.
119 * @throws IllegalDataException if the given text is illegal for a
120 * Comment.
121 */
122 public Comment setText(String text) {
123 String reason;
124 if ((reason = Verifier.checkCommentData(text)) != null) {
125 throw new IllegalDataException(text, "comment", reason);
126 }
127
128 this.text = text;
129 return this;
130 }
131
132 @Override
133 public Comment clone() {
134 return (Comment)super.clone();
135 }
136
137 @Override
138 public Comment detach() {
139 return (Comment)super.detach();
140 }
141
142 @Override
143 protected Comment setParent(Parent parent) {
144 return (Comment)super.setParent(parent);
145 }
146
147 /**
148 * This returns a <code>String</code> representation of the
149 * <code>Comment</code>, suitable for debugging. If the XML
150 * representation of the <code>Comment</code> is desired,
151 * {@link XMLOutputter2#outputString(Comment)}
152 * should be used.
153 *
154 * @return <code>String</code> - information about the
155 * <code>Comment</code>
156 */
157 @Override
158 public String toString() {
159 return new StringBuilder()
160 .append("[Comment: ")
161 .append(new XMLOutputter2().outputString(this))
162 .append("]")
163 .toString();
164 }
165
166 }
0 /*--
1
2 Copyright (C) 2007-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.io.*;
57 import java.util.Collections;
58 import java.util.List;
59
60 /**
61 * Superclass for JDOM objects which can be legal child content
62 * of {@link org.jdom.Parent} nodes.
63 *
64 * @see org.jdom.Comment
65 * @see org.jdom.DocType
66 * @see org.jdom.Element
67 * @see org.jdom.EntityRef
68 * @see org.jdom.Parent
69 * @see org.jdom.ProcessingInstruction
70 * @see org.jdom.Text
71 *
72 * @author Bradley S. Huffman
73 * @author Jason Hunter
74 * @author Rolf Lear
75 */
76 public abstract class Content extends CloneBase
77 implements Serializable, NamespaceAware {
78
79 /**
80 * JDOM2 Serialization.
81 */
82 private static final long serialVersionUID = 200L;
83
84 /**
85 * An enumeration useful for identifying content types without
86 * having to do <code>instanceof</code> type conditionals.
87 * <p>
88 * <code>instanceof</code> is not a particularly safe way to test content
89 * in JDOM because CDATA extends Text ( a CDATA instance is an
90 * <code>instanceof</code> Text).
91 * <p>
92 * This CType enumeration provides a direct and sure mechanism for
93 * identifying JDOM content.
94 * <p>
95 * These can be used in switch-type statements too (which is much neater
96 * than chained if (instanceof) else if (instanceof) else .... expressions):
97 * <p>
98 * <pre>
99 * switch(content.getCType()) {
100 * case Text :
101 * .....
102 * break;
103 * case CDATA :
104 * .....
105 * break;
106 * ....
107 * }
108 * </pre>
109 *
110 * @author Rolf Lear
111 * @since JDOM2
112 */
113 public static enum CType {
114 /** Represents {@link Comment} content */
115 Comment,
116 /** Represents {@link Element} content */
117 Element,
118 /** Represents {@link ProcessingInstruction} content */
119 ProcessingInstruction,
120 /** Represents {@link EntityRef} content */
121 EntityRef,
122 /** Represents {@link Text} content */
123 Text,
124 /** Represents {@link CDATA} content */
125 CDATA,
126 /** Represents {@link DocType} content */
127 DocType
128 }
129
130 /**
131 * The parent {@link Parent} of this Content.
132 * Note that the field is not serialized, thus deserialized Content
133 * instances are 'detached'
134 */
135 protected transient Parent parent = null;
136 /**
137 * The content type enumerate value for this Content
138 * @serialField This is an Enum, and cannot be null.
139 */
140 protected final CType ctype;
141
142 /**
143 * Create a new Content instance of a particular type.
144 * @param type The {@link CType} of this Content
145 */
146 protected Content(CType type) {
147 ctype = type;
148 }
149
150
151 /**
152 * All content has an enumerated type expressing the type of content.
153 * This makes it possible to use switch-type statements on the content.
154 * @return A CType enumerated value representing this content.
155 */
156 public final CType getCType() {
157 return ctype;
158 }
159
160 /**
161 * Detaches this child from its parent or does nothing if the child
162 * has no parent.
163 * <p>
164 * This method can be overridden by particular Content subclasses to return
165 * a specific type of Content (co-variant return type). All overriding
166 * subclasses <b>must</b> call <code>super.detach()</code>;
167 *
168 * @return this child detached
169 */
170 public Content detach() {
171 if (parent != null) {
172 parent.removeContent(this);
173 }
174 return this;
175 }
176
177 /**
178 * Return this child's parent, or null if this child is currently
179 * not attached. The parent can be either an {@link Element}
180 * or a {@link Document}.
181 * <p>
182 * This method can be overridden by particular Content subclasses to return
183 * a specific type of Parent (co-variant return type). All overriding
184 * subclasses <b>must</b> call <code>super.getParent()</code>;
185 *
186 * @return this child's parent or null if none
187 */
188 public Parent getParent() {
189 return parent;
190 }
191
192 /**
193 * A convenience method that returns any parent element for this element,
194 * or null if the element is unattached or is a root element. This was the
195 * original behavior of getParent() in JDOM Beta 9 which began returning
196 * Parent in Beta 10. This method provides a convenient upgrade path for
197 * JDOM Beta 10 and 1.0 users.
198 *
199 * @return the containing Element or null if unattached or a root element
200 */
201 final public Element getParentElement() {
202 Parent pnt = getParent();
203 return (Element) ((pnt instanceof Element) ? pnt : null);
204 }
205
206 /**
207 * Sets the parent of this Content. The caller is responsible for removing
208 * any pre-existing parentage.
209 * <p>
210 * This method can be overridden by particular Content subclasses to return
211 * a specific type of Content (co-variant return type). All overriding
212 * subclasses <b>must</b> call <code>super.setParent(Parent)</code>;
213 *
214 * @param parent new parent element
215 * @return the target element
216 */
217 protected Content setParent(Parent parent) {
218 this.parent = parent;
219 return this;
220 }
221
222 /**
223 * Return this child's owning document or null if the branch containing
224 * this child is currently not attached to a document.
225 *
226 * @return this child's owning document or null if none
227 */
228 public Document getDocument() {
229 if (parent == null) return null;
230 return parent.getDocument();
231 }
232
233
234 /**
235 * Returns the XPath 1.0 string value of this child.
236 *
237 * @return xpath string value of this child.
238 */
239 public abstract String getValue();
240
241 @Override
242 public Content clone() {
243 Content c = (Content)super.clone();
244 c.parent = null;
245 return c;
246 }
247
248 /**
249 * This tests for equality of this Content object to the supplied object.
250 * Content items are considered equal only if they are referentially equal
251 * (i&#46;e&#46; the same object). User code may choose to compare objects
252 * based on their properties instead.
253 *
254 * @param ob <code>Object</code> to compare to.
255 * @return <code>boolean</code> - whether the <code>Content</code> is
256 * equal to the supplied <code>Object</code>.
257 */
258 @Override
259 public final boolean equals(Object ob) {
260 return (ob == this);
261 }
262
263 /**
264 * This returns the hash code for this <code>Content</code> item.
265 *
266 * @return <code>int</code> - hash code.
267 */
268 @Override
269 public final int hashCode() {
270 return super.hashCode();
271 }
272
273 @Override
274 public List<Namespace> getNamespacesInScope() {
275 // Element class will override this method to do it differently.
276 Element emt = getParentElement();
277 if (emt == null) {
278 return Collections.singletonList(Namespace.XML_NAMESPACE);
279 }
280 return emt.getNamespacesInScope();
281 }
282
283 @Override
284 public List<Namespace> getNamespacesIntroduced() {
285 return Collections.emptyList();
286 }
287
288 @Override
289 public List<Namespace> getNamespacesInherited() {
290 // Element class will override
291 return getNamespacesInScope();
292 }
293
294 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.*;
57
58 import org.jdom.filter.AbstractFilter;
59 import org.jdom.filter2.Filter;
60 import org.jdom.internal.ArrayCopy;
61
62 /**
63 * A non-public list implementation holding only legal JDOM content, including
64 * content for Document or Element nodes. Users see this class as a simple List
65 * implementation.
66 *
67 * @see DocType
68 * @see CDATA
69 * @see Comment
70 * @see Element
71 * @see EntityRef
72 * @see ProcessingInstruction
73 * @see Text
74 * @author Alex Rosen
75 * @author Philippe Riand
76 * @author Bradley S. Huffman
77 * @author Rolf Lear
78 */
79 final class ContentList extends AbstractList<Content>
80 implements RandomAccess {
81
82 private static final int INITIAL_ARRAY_SIZE = 4;
83
84 /** Our backing list */
85 private Content elementData[] = null;
86
87 /** The amount of valid content in elementData */
88 private int size;
89
90 /**
91 * Completely remove references to AbstractList.modCount because in
92 * ContentList it is confusing. As a consequence we also need to implement
93 * a custom ListIterator for ContentList so that we don't use any of the
94 * AbstractList iterators which use modCount.... so we have our own
95 * ConcurrentModification checking.
96 *
97 */
98 private transient int sizeModCount = Integer.MIN_VALUE;
99
100 /**
101 * modCount is used for concurrent modification, but dataModCount is used
102 * for refreshing filters.
103 */
104 private transient int dataModiCount = Integer.MIN_VALUE;
105
106 /** Document or Element this list belongs to */
107 private final Parent parent;
108
109 /**
110 * Force either a Document or Element parent
111 *
112 * @param parent
113 * the Element this ContentList belongs to.
114 */
115 ContentList(final Parent parent) {
116 this.parent = parent;
117 }
118
119 /**
120 * Package internal method to support building from sources that are 100%
121 * trusted.
122 *
123 * @param c
124 * content to add without any checks
125 */
126 final void uncheckedAddContent(final Content c) {
127 c.parent = parent;
128 ensureCapacity(size + 1);
129 elementData[size++] = c;
130 incModCount();
131 }
132
133 /**
134 * In the FilterList and FilterList iterators it becomes confusing as to
135 * which modCount is being used. This formalizes the process, and using
136 * (set/get/inc)ModCount() is the only thing you should see in the remainder
137 * of this code.
138 *
139 * @param sizemod
140 * the value to set for the size-mod count.
141 * @param datamod
142 * the value to set for the data-mod count.
143 */
144 private final void setModCount(final int sizemod, final int datamod) {
145 sizeModCount = sizemod;
146 dataModiCount = datamod;
147 }
148
149 /**
150 * In the FilterList and FilterList iterators it becomes confusing as to
151 * which modCount is being used. This formalizes the process, and using
152 * (set/get/inc)ModCount() is the only thing you should see in the remainder
153 * of this code.
154 *
155 * @return mod the value.
156 */
157 private final int getModCount() {
158 return sizeModCount;
159 }
160
161 /**
162 * In the FilterList and FilterList iterators it becomes confusing as to
163 * which modCount is being used. This formalizes the process, and using
164 * (set/get/inc)ModCount() is the only thing you should see in the remainder
165 * of this code.
166 */
167 private final void incModCount() {
168 // indicate there's a change to data
169 dataModiCount++;
170 // indicate there's a change to the size
171 sizeModCount++;
172 }
173
174 private final void incDataModOnly() {
175 dataModiCount++;
176 }
177
178 /**
179 * Get the modcount of data changes.
180 * @return the current data mode count.
181 */
182 private final int getDataModCount() {
183 return dataModiCount;
184 }
185
186 private final void checkIndex(final int index, final boolean excludes) {
187 final int max = excludes ? size - 1 : size;
188
189 if (index < 0 || index > max) {
190 throw new IndexOutOfBoundsException("Index: " + index +
191 " Size: " + size);
192 }
193
194 }
195
196 private final void checkPreConditions(final Content child, final int index,
197 final boolean replace) {
198 if (child == null) {
199 throw new NullPointerException("Cannot add null object");
200 }
201
202 checkIndex(index, replace);
203
204 if (child.getParent() != null) {
205 // the content to be added already has a parent.
206 final Parent p = child.getParent();
207 if (p instanceof Document) {
208 throw new IllegalAddException((Element) child,
209 "The Content already has an existing parent document");
210 }
211 throw new IllegalAddException(
212 "The Content already has an existing parent \"" +
213 ((Element) p).getQualifiedName() + "\"");
214 }
215
216 if (child == parent) {
217 throw new IllegalAddException(
218 "The Element cannot be added to itself");
219 }
220
221 // Detect if we have <a><b><c/></b></a> and c.add(a)
222 if ((parent instanceof Element && child instanceof Element) &&
223 ((Element) child).isAncestor((Element) parent)) {
224 throw new IllegalAddException(
225 "The Element cannot be added as a descendent of itself");
226 }
227
228 }
229
230 /**
231 * Check and add the <code>Content</code> to this list at the given index.
232 * Inserts the specified object at the specified position in this list.
233 * Shifts the object currently at that position (if any) and any subsequent
234 * objects to the right (adds one to their indices).
235 *
236 * @param index
237 * index where to add <code>Element</code>
238 * @param child
239 * <code>Content</code> to add
240 */
241 @Override
242 public void add(final int index, final Content child) {
243 // Confirm basic sanity of child.
244 checkPreConditions(child, index, false);
245 // Check to see whether this parent believes it can contain this content
246 parent.canContainContent(child, index, false);
247
248 child.setParent(parent);
249
250 ensureCapacity(size + 1);
251 if (index == size) {
252 elementData[size++] = child;
253 } else {
254 System.arraycopy(elementData, index, elementData, index + 1, size - index);
255 elementData[index] = child;
256 size++;
257 }
258 // Successful add's increment the AbstractList's modCount
259 incModCount();
260 }
261
262 /**
263 * Add the specified collection to the end of this list.
264 *
265 * @param collection
266 * The collection to add to the list.
267 * @return <code>true</code> if the list was modified as a result of the
268 * add.
269 */
270 @Override
271 public boolean addAll(final Collection<? extends Content> collection) {
272 return addAll(size, collection);
273 }
274
275 /**
276 * Inserts the specified collection at the specified position in this list.
277 * Shifts the object currently at that position (if any) and any subsequent
278 * objects to the right (adds one to their indices).
279 *
280 * @param index
281 * The offset to start adding the data in the collection
282 * @param collection
283 * The collection to insert into the list.
284 * @return <code>true</code> if the list was modified as a result of the
285 * add. throws IndexOutOfBoundsException if index < 0 || index >
286 * size()
287 */
288 @Override
289 public boolean addAll(final int index,
290 final Collection<? extends Content> collection) {
291 if ((collection == null)) {
292 throw new NullPointerException(
293 "Can not add a null collection to the ContentList");
294 }
295
296 checkIndex(index, false);
297
298 if (collection.isEmpty()) {
299 // some collections are expensive to get the size of.
300 // use isEmpty().
301 return false;
302 }
303 final int addcnt = collection.size();
304 if (addcnt == 1) {
305 // quick check for single-add.
306 add(index, collection.iterator().next());
307 return true;
308 }
309
310 ensureCapacity(size() + addcnt);
311
312 final int tmpmodcount = getModCount();
313 final int tmpdmc = getDataModCount();
314 boolean ok = false;
315
316 int count = 0;
317
318 try {
319 for (Content c : collection) {
320 add(index + count, c);
321 count++;
322 }
323 ok = true;
324 } finally {
325 if (!ok) {
326 // something failed... remove all added content
327 while (--count >= 0) {
328 remove(index + count);
329 }
330 // restore the mod-counts.
331 setModCount(tmpmodcount, tmpdmc);
332 }
333 }
334
335 return true;
336 }
337
338 /**
339 * Clear the current list.
340 */
341 @Override
342 public void clear() {
343 if (elementData != null) {
344 for (int i = 0; i < size; i++) {
345 Content obj = elementData[i];
346 removeParent(obj);
347 }
348 elementData = null;
349 size = 0;
350 }
351 incModCount();
352 }
353
354 /**
355 * Clear the current list and set it to the contents of the
356 * <code>Collection</code>. object.
357 *
358 * @param collection
359 * The collection to use.
360 */
361 void clearAndSet(final Collection<? extends Content> collection) {
362 if (collection == null || collection.isEmpty()) {
363 clear();
364 return;
365 }
366
367 // keep a backup in case we need to roll-back...
368 final Content[] old = elementData;
369 final int oldSize = size;
370 final int oldModCount = getModCount();
371 final int oldDataModCount = getDataModCount();
372
373 // clear the current system
374 // we need to detach before we add so that we don't run in to a problem
375 // where a content in the to-add list is one that we are 'clearing'
376 // first.
377 while (size > 0) {
378 old[--size].setParent(null);
379 }
380 size = 0;
381 elementData = null;
382
383 boolean ok = false;
384 try {
385 addAll(0, collection);
386 ok = true;
387 } finally {
388 if (!ok) {
389 // we have an exception pending....
390 // restore the old system.
391 // we do not need to worry about the added content
392 // because the failed addAll will clear it up.
393 // re-attach the old stuff
394 elementData = old;
395 while (size < oldSize) {
396 elementData[size++].setParent(parent);
397 }
398 setModCount(oldModCount, oldDataModCount);
399 }
400 }
401
402 }
403
404 /**
405 * Increases the capacity of this <code>ContentList</code> instance, if
406 * necessary, to ensure that it can hold at least the number of items
407 * specified by the minimum capacity argument.
408 *
409 * @param minCapacity
410 * the desired minimum capacity.
411 */
412 void ensureCapacity(final int minCapacity) {
413 if (elementData == null) {
414 elementData = new Content[Math.max(minCapacity, INITIAL_ARRAY_SIZE)];
415 return;
416 } else if (minCapacity < elementData.length) {
417 return;
418 }
419 // use algorithm Wilf suggests which is essentially the same
420 // as algorithm as ArrayList.ensureCapacity....
421 // typically the minCapacity is only slightly larger than
422 // the current capacity.... so grow from the current capacity
423 // with a double-check.
424 final int newcap = ((size * 3) / 2) + 1;
425 elementData = ArrayCopy.copyOf(elementData,
426 (newcap < minCapacity ? minCapacity : newcap));
427 }
428
429 /**
430 * Return the object at the specified offset.
431 *
432 * @param index
433 * The offset of the object.
434 * @return The Object which was returned.
435 */
436 @Override
437 public Content get(final int index) {
438 checkIndex(index, true);
439 return elementData[index];
440 }
441
442 /**
443 * Return a view of this list based on the given filter.
444 *
445 * @param <E>
446 * The Generic type of the content as set by the Filter.
447 * @param filter
448 * <code>Filter</code> for this view.
449 * @return a list representing the rules of the <code>Filter</code>.
450 */
451 <E extends Content> List<E> getView(final org.jdom.filter2.Filter<E> filter) {
452 return new FilterList<E>(filter);
453 }
454
455 /**
456 * Return a view of this list based on the given filter.
457 *
458 * @param <E>
459 * The Generic type of the content as set by the Filter.
460 * @param filter
461 * <code>Filter</code> for this view.
462 * @return a list representing the rules of the <code>Filter</code>.
463 */
464 <E extends Content> List<E> getView(final org.jdom.filter.Filter<E> filter) {
465 return new FilterList<E>(AbstractFilter.toFilter2(filter));
466 }
467
468 /**
469 * Return the index of the first Element in the list. If the parent is a
470 * <code>Document</code> then the element is the root element. If the list
471 * contains no Elements, it returns -1.
472 *
473 * @return index of first element, or -1 if one doesn't exist
474 */
475 int indexOfFirstElement() {
476 if (elementData != null) {
477 for (int i = 0; i < size; i++) {
478 if (elementData[i] instanceof Element) {
479 return i;
480 }
481 }
482 }
483 return -1;
484 }
485
486 /**
487 * Return the index of the DocType element in the list. If the list contains
488 * no DocType, it returns -1.
489 *
490 * @return index of the DocType, or -1 if it doesn't exist
491 */
492 int indexOfDocType() {
493 if (elementData != null) {
494 for (int i = 0; i < size; i++) {
495 if (elementData[i] instanceof DocType) {
496 return i;
497 }
498 }
499 }
500 return -1;
501 }
502
503 /**
504 * Remove the object at the specified offset.
505 *
506 * @param index
507 * The offset of the object.
508 * @return The Object which was removed.
509 */
510 @Override
511 public Content remove(final int index) {
512 checkIndex(index, true);
513
514 final Content old = elementData[index];
515 removeParent(old);
516 System.arraycopy(elementData, index + 1, elementData, index, size - index - 1);
517 elementData[--size] = null; // Let gc do its work
518 incModCount();
519 return old;
520 }
521
522 /** Remove the parent of a Object */
523 private static void removeParent(final Content c) {
524 c.setParent(null);
525 }
526
527 /**
528 * Set the object at the specified location to the supplied object.
529 *
530 * @param index
531 * The location to set the value to.
532 * @param child
533 * The location to set the value to.
534 * @return The object which was replaced. throws IndexOutOfBoundsException
535 * if index < 0 || index >= size()
536 */
537 @Override
538 public Content set(final int index, final Content child) {
539 // Confirm basic sanity of child.
540 checkPreConditions(child, index, true);
541
542 // Ensure the detail checks out OK too.
543 parent.canContainContent(child, index, true);
544
545 /*
546 * Do a special case of set() where we don't do a remove() then add()
547 * because that affects the modCount. We want to do a true set(). See
548 * issue #15
549 */
550
551 final Content old = elementData[index];
552 removeParent(old);
553 child.setParent(parent);
554 elementData[index] = child;
555 // for set method we increment dataModCount, but not modCount
556 // set does not change the structure of the List (size())
557 incDataModOnly();
558 return old;
559 }
560
561 /**
562 * Return the number of items in this list
563 *
564 * @return The number of items in this list.
565 */
566 @Override
567 public int size() {
568 return size;
569 }
570
571 @Override
572 public Iterator<Content> iterator() {
573 return new CLIterator();
574 }
575
576 @Override
577 public ListIterator<Content> listIterator() {
578 return new CLListIterator(0);
579 }
580
581 @Override
582 public ListIterator<Content> listIterator(final int start) {
583 return new CLListIterator(start);
584 }
585
586 /**
587 * Return this list as a <code>String</code>
588 *
589 * @return The String representation of this list.
590 */
591 @Override
592 public String toString() {
593 return super.toString();
594 }
595
596 private void sortInPlace(final int[] indexes) {
597 // the indexes are a discrete set of values that have no duplicates,
598 // and describe the relative order of each of them.
599 // as a result, we can do some tricks....
600 final int[] unsorted = ArrayCopy.copyOf(indexes, indexes.length);
601 Arrays.sort(unsorted);
602 final Content[] usc = new Content[unsorted.length];
603 for (int i = 0; i < usc.length; i++) {
604 usc[i] = elementData[indexes[i]];
605 }
606 // usc contains the content in their pre-sorted order....
607 for (int i = 0; i < indexes.length; i ++) {
608 elementData[unsorted[i]] = usc[i];
609 }
610 }
611
612 /**
613 * Unlike the Arrays.binarySearch, this method never expects an
614 * "already exists" condition, we only ever add, thus there will never
615 * be a negative insertion-point.
616 * @param indexes THe pointers to search within
617 * @param len The number of pointers to search within
618 * @param val The pointer we are checking for.
619 * @param comp The Comparator to compare with
620 * @return the insertion point.
621 */
622 private final int binarySearch(final int[] indexes, final int len,
623 final int val, final Comparator<? super Content> comp) {
624 int left = 0, mid = 0, right = len - 1, cmp = 0;
625 final Content base = elementData[val];
626 while (left <= right) {
627 mid = (left + right) >>> 1;
628 cmp = comp.compare(base, elementData[indexes[mid]]);
629 if (cmp == 0) {
630 while (cmp == 0 && mid < right && comp.compare(
631 base, elementData[indexes[mid + 1]]) == 0) {
632 mid++;
633 }
634 return mid + 1;
635 } else if (cmp < 0) {
636 right = mid - 1;
637 } else {
638 left = mid + 1;
639 }
640 }
641 return left;
642 }
643
644 /**
645 * Sorts this list using the supplied Comparator to compare elements.
646 *
647 * @param comp - the Comparator used to compare list elements. A null value indicates that the elements' natural ordering should be used
648 * @Since 2.0.6
649 */
650 // @Override - only in Java8
651 public final void sort(final Comparator<? super Content> comp) {
652
653 if (comp == null) {
654 // sort by the 'natural order', which, there is none.
655 // options, throw exception, or let the current-order represent the natural order.
656 // do nothing is the better alternative.
657 return;
658 }
659
660 final int sz = size;
661 int[] indexes = new int[sz];
662 for (int i = 0 ; i < sz; i++) {
663 final int ip = binarySearch(indexes, i, i, comp);
664 if (ip < i) {
665 System.arraycopy(indexes, ip, indexes, ip+1, i - ip);
666 }
667 indexes[ip] = i;
668 }
669 sortInPlace(indexes);
670 }
671
672 /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * * * */
673 /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * * * */
674 /**
675 * A fast implementation of Iterator.
676 * <p>
677 * It is fast because it is tailored to the ContentList, and not the
678 * flexible implementation used by AbstractList. It needs to be fast because
679 * iterator() is used extensively in the for-each type loop.
680 *
681 * @author Rolf Lear
682 */
683 private final class CLIterator implements Iterator<Content> {
684 private int expect = -1;
685 private int cursor = 0;
686 private boolean canremove = false;
687
688 private CLIterator() {
689 expect = getModCount();
690 }
691
692 @Override
693 public boolean hasNext() {
694 return cursor < size;
695 }
696
697 @Override
698 public Content next() {
699 if (getModCount() != expect) {
700 throw new ConcurrentModificationException("ContentList was " +
701 "modified outside of this Iterator");
702 }
703 if (cursor >= size) {
704 throw new NoSuchElementException("Iterated beyond the end of " +
705 "the ContentList.");
706 }
707 canremove = true;
708 return elementData[cursor++];
709 }
710
711 @Override
712 public void remove() {
713 if (getModCount() != expect) {
714 throw new ConcurrentModificationException("ContentList was " +
715 "modified outside of this Iterator");
716 }
717 if (!canremove) {
718 throw new IllegalStateException("Can only remove() content " +
719 "after a call to next()");
720 }
721 canremove = false;
722 ContentList.this.remove(--cursor);
723 expect = getModCount();
724 }
725
726 }
727
728 /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * * * */
729 /* * * * * * * * * * * * * ContentListIterator * * * * * * * * * * * * * * * */
730 /**
731 * A fast implementation of Iterator.
732 * <p>
733 * It is fast because it is tailored to the ContentList, and not the
734 * flexible implementation used by AbstractList. It needs to be fast because
735 * iterator() is used extensively in the for-each type loop.
736 *
737 * @author Rolf Lear
738 */
739 private final class CLListIterator implements ListIterator<Content> {
740 /** Whether this iterator is in forward or reverse. */
741 private boolean forward = false;
742 /** Whether a call to remove() is valid */
743 private boolean canremove = false;
744 /** Whether a call to set() is valid */
745 private boolean canset = false;
746
747 /** Expected modCount in our backing list */
748 private int expectedmod = -1;
749
750 private int cursor = -1;
751
752 /**
753 * Default constructor
754 *
755 * @param flist
756 * The FilterList over which we will iterate.
757 * @param start
758 * where in the FilterList to start iteration.
759 */
760 CLListIterator(final int start) {
761 expectedmod = getModCount();
762 // always start list iterators in backward mode ....
763 // it makes sense... really.
764 forward = false;
765
766 checkIndex(start, false);
767
768 cursor = start;
769 }
770
771 private void checkConcurrent() {
772 if (expectedmod != getModCount()) {
773 throw new ConcurrentModificationException("The ContentList " +
774 "supporting this iterator has been modified by" +
775 "something other than this Iterator.");
776 }
777 }
778
779 /**
780 * Returns <code>true</code> if this list iterator has a next element.
781 */
782 @Override
783 public boolean hasNext() {
784 return (forward ? cursor + 1 : cursor) < size;
785 }
786
787 /**
788 * Returns <code>true</code> if this list iterator has more elements
789 * when traversing the list in the reverse direction.
790 */
791 @Override
792 public boolean hasPrevious() {
793 return (forward ? cursor : cursor - 1) >= 0;
794 }
795
796 /**
797 * Returns the index of the element that would be returned by a
798 * subsequent call to <code>next</code>.
799 */
800 @Override
801 public int nextIndex() {
802 return forward ? cursor + 1 : cursor;
803 }
804
805 /**
806 * Returns the index of the element that would be returned by a
807 * subsequent call to <code>previous</code>. (Returns -1 if the list
808 * iterator is at the beginning of the list.)
809 */
810 @Override
811 public int previousIndex() {
812 return forward ? cursor : cursor - 1;
813 }
814
815 /**
816 * Returns the next element in the list.
817 */
818 @Override
819 public Content next() {
820 checkConcurrent();
821 final int next = forward ? cursor + 1 : cursor;
822
823 if (next >= size) {
824 throw new NoSuchElementException("next() is beyond the end of the Iterator");
825 }
826
827 cursor = next;
828 forward = true;
829 canremove = true;
830 canset = true;
831 return elementData[cursor];
832 }
833
834 /**
835 * Returns the previous element in the list.
836 */
837 @Override
838 public Content previous() {
839 checkConcurrent();
840 final int prev = forward ? cursor : cursor - 1;
841
842 if (prev < 0) {
843 throw new NoSuchElementException("previous() is beyond the beginning of the Iterator");
844 }
845
846 cursor = prev;
847 forward = false;
848 canremove = true;
849 canset = true;
850 return elementData[cursor];
851 }
852
853 /**
854 * Inserts the specified element into the list .
855 */
856 @Override
857 public void add(final Content obj) {
858 checkConcurrent();
859 // always add before what would normally be returned by next();
860 final int next = forward ? cursor + 1 : cursor;
861
862 ContentList.this.add(next, obj);
863
864 expectedmod = getModCount();
865
866 canremove = canset = false;
867
868 // a call to next() should be unaffected, so, whatever was going to
869 // be next will still be next, remember, what was going to be next
870 // has been shifted 'right' by our insert.
871 // we ensure this by setting the cursor to next(), and making it
872 // forward
873 cursor = next;
874 forward = true;
875 }
876
877 /**
878 * Removes from the list the last element that was returned by the last
879 * call to <code>next</code> or <code>previous</code>.
880 */
881 @Override
882 public void remove() {
883 checkConcurrent();
884 if (!canremove)
885 throw new IllegalStateException("Can not remove an "
886 + "element unless either next() or previous() has been called "
887 + "since the last remove()");
888 // we are removing the last entry returned by either next() or
889 // previous().
890 // the idea is to remove it, and pretend that we used to be at the
891 // entry that happened *after* the removed entry.
892 // so, get what would be the next entry (set at tmpcursor).
893 // so call nextIndex to set tmpcursor to what would come after.
894 ContentList.this.remove(cursor);
895 forward = false;
896 expectedmod = getModCount();
897
898 canremove = false;
899 canset = false;
900 }
901
902 /**
903 * Replaces the last element returned by <code>next</code> or
904 * <code>previous</code> with the specified element.
905 */
906 @Override
907 public void set(final Content obj) {
908 checkConcurrent();
909 if (!canset) {
910 throw new IllegalStateException("Can not set an element "
911 + "unless either next() or previous() has been called since the "
912 + "last remove() or set()");
913 }
914
915 ContentList.this.set(cursor, obj);
916 expectedmod = getModCount();
917
918 }
919
920 }
921
922 /* * * * * * * * * * * * * FilterList * * * * * * * * * * * * * * * */
923 /* * * * * * * * * * * * * FilterList * * * * * * * * * * * * * * * */
924
925 /**
926 * <code>FilterList</code> represents legal JDOM content, including content
927 * for <code>Document</code>s or <code>Element</code>s.
928 * <p>
929 * FilterList represents a dynamic view of the backing ContentList, changes
930 * to the backing list are reflected in the FilterList, and visa-versa.
931 *
932 * @param <F>
933 * The Generic type of content accepted by the underlying Filter.
934 */
935
936 class FilterList<F extends Content> extends AbstractList<F> {
937
938 // The filter to apply
939 final Filter<F> filter;
940 // correlate the position in the filtered list to the index in the
941 // backing ContentList.
942 int[] backingpos = new int[size + INITIAL_ARRAY_SIZE];
943 int backingsize = 0;
944 // track data modifications in the backing ContentList.
945 int xdata = -1;
946
947 /**
948 * Create a new instance of the FilterList with the specified Filter.
949 *
950 * @param filter
951 * The underlying Filter to use for filtering the content.
952 */
953 FilterList(final Filter<F> filter) {
954 this.filter = filter;
955 }
956
957 /**
958 * Returns true if there is no content in this FilterList.
959 * @return true if there is no content in this FilterList
960 */
961 @Override
962 public boolean isEmpty() {
963 // More efficient implementation than default size() == 0
964 // we use resync() to accomplish the task. If there is an
965 // element 0 in this FilterList, then it is not empty!
966 // we may already have resync'd 0, which will be a fast return then,
967 // or, if we have not resync'd 0, then we only have to filter up to
968 // the first matching element to get a result (or the whole list
969 // if isEmpty() is true).
970 return resync(0) == size;
971 }
972
973 /**
974 * Synchronise our view to the backing list. Only synchronise the first
975 * <code>index</code> view elements. For want of a better word, we'll
976 * call this a 'Lazy' implementation.
977 *
978 * @param index
979 * how much we want to sync. Set to -1 to synchronise everything.
980 * @return the index in the backing array of the <i>index'th</i> match.
981 * or the backing data size if there is no match for the index.
982 */
983 private final int resync(final int index) {
984 if (xdata != getDataModCount()) {
985 // The underlying list was modified somehow...
986 // we need to invalidate our research...
987 xdata = getDataModCount();
988 backingsize = 0;
989 if (size >= backingpos.length) {
990 backingpos = new int[size + 1];
991 }
992 }
993
994 if (index >= 0 && index < backingsize) {
995 // we have already indexed far enough...
996 // return the backing index.
997 return backingpos[index];
998 }
999
1000 // the index in the backing list of the next value to check.
1001 int bpi = 0;
1002 if (backingsize > 0) {
1003 bpi = backingpos[backingsize - 1] + 1;
1004 }
1005
1006 while (bpi < size) {
1007 final F gotit = filter.filter(elementData[bpi]);
1008 if (gotit != null) {
1009 backingpos[backingsize] = bpi;
1010 if (backingsize++ == index) {
1011 return bpi;
1012 }
1013 }
1014 bpi++;
1015 }
1016 return size;
1017 }
1018
1019 /**
1020 * Inserts the specified object at the specified position in this list.
1021 * Shifts the object currently at that position (if any) and any
1022 * subsequent objects to the right (adds one to their indices).
1023 *
1024 * @param index
1025 * The location to set the value to.
1026 * @param obj
1027 * The object to insert into the list. throws
1028 * IndexOutOfBoundsException if index < 0 || index > size()
1029 */
1030 @Override
1031 public void add(final int index, final Content obj) {
1032 if (index < 0) {
1033 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1034 }
1035 int adj = resync(index);
1036 if (adj == size && index > size()) {
1037 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1038 }
1039 if (filter.matches(obj)) {
1040 ContentList.this.add(adj, obj);
1041
1042 // we can optimise the laziness now by doing a partial reset on
1043 // the backing list... invalidate everything *after* the added
1044 // content
1045 if (backingpos.length <= size) {
1046 backingpos = ArrayCopy.copyOf(backingpos, backingpos.length + 1);
1047 }
1048 backingpos[index] = adj;
1049 backingsize = index + 1;
1050 xdata = getDataModCount();
1051
1052 } else {
1053 throw new IllegalAddException("Filter won't allow the " +
1054 obj.getClass().getName() +
1055 " '" + obj + "' to be added to the list");
1056 }
1057 }
1058
1059 @Override
1060 public boolean addAll(final int index,
1061 final Collection<? extends F> collection) {
1062 if (collection == null) {
1063 throw new NullPointerException("Cannot add a null collection");
1064 }
1065
1066 if (index < 0) {
1067 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1068 }
1069
1070 final int adj = resync(index);
1071 if (adj == size && index > size()) {
1072 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1073 }
1074
1075 final int addcnt = collection.size();
1076 if (addcnt == 0) {
1077 return false;
1078 }
1079
1080 ContentList.this.ensureCapacity(ContentList.this.size() + addcnt);
1081
1082 final int tmpmodcount = getModCount();
1083 final int tmpdmc = getDataModCount();
1084 boolean ok = false;
1085
1086 int count = 0;
1087
1088 try {
1089 for (Content c : collection) {
1090 if (c == null) {
1091 throw new NullPointerException(
1092 "Cannot add null content");
1093 }
1094 if (filter.matches(c)) {
1095 ContentList.this.add(adj + count, c);
1096 // we can optimise the laziness now by doing a partial
1097 // reset on
1098 // the backing list... invalidate everything *after* the
1099 // added
1100 // content
1101 if (backingpos.length <= size) {
1102 backingpos = ArrayCopy.copyOf(backingpos, backingpos.length + addcnt);
1103 }
1104 backingpos[index + count] = adj + count;
1105 backingsize = index + count + 1;
1106 xdata = getDataModCount();
1107
1108 count++;
1109 } else {
1110 throw new IllegalAddException("Filter won't allow the " +
1111 c.getClass().getName() +
1112 " '" + c + "' to be added to the list");
1113
1114 }
1115 }
1116 ok = true;
1117 } finally {
1118 if (!ok) {
1119 // something failed... remove all added content
1120 while (--count >= 0) {
1121 ContentList.this.remove(adj + count);
1122 }
1123 // restore the mod-counts.
1124 setModCount(tmpmodcount, tmpdmc);
1125 // reset the cache... will need to redo some work on another
1126 // call maybe....
1127 backingsize = index;
1128 xdata = tmpmodcount;
1129 }
1130 }
1131
1132 return true;
1133 }
1134
1135 /**
1136 * Return the object at the specified offset.
1137 *
1138 * @param index
1139 * The offset of the object.
1140 * @return The Object which was returned.
1141 */
1142 @Override
1143 public F get(final int index) {
1144 if (index < 0) {
1145 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1146 }
1147 final int adj = resync(index);
1148 if (adj == size) {
1149 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1150 }
1151 return filter.filter(ContentList.this.get(adj));
1152 }
1153
1154 @Override
1155 public Iterator<F> iterator() {
1156 return new FilterListIterator<F>(this, 0);
1157 }
1158
1159 @Override
1160 public ListIterator<F> listIterator() {
1161 return new FilterListIterator<F>(this, 0);
1162 }
1163
1164 @Override
1165 public ListIterator<F> listIterator(final int index) {
1166 return new FilterListIterator<F>(this, index);
1167 }
1168
1169 /**
1170 * Remove the object at the specified offset.
1171 *
1172 * @param index
1173 * The offset of the object.
1174 * @return The Object which was removed.
1175 */
1176 @Override
1177 public F remove(final int index) {
1178 if (index < 0) {
1179 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1180 }
1181 final int adj = resync(index);
1182 if (adj == size) {
1183 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1184 }
1185 final Content oldc = ContentList.this.remove(adj);
1186 // optimise the backing cache.
1187 backingsize = index;
1188 xdata = getDataModCount();
1189 // use Filter to ensure the cast is right.
1190 return filter.filter(oldc);
1191 }
1192
1193 /**
1194 * Set the object at the specified location to the supplied object.
1195 *
1196 * @param index
1197 * The location to set the value to.
1198 * @param obj
1199 * The location to set the value to.
1200 * @return The object which was replaced. throws
1201 * IndexOutOfBoundsException if index < 0 || index >= size()
1202 */
1203 @Override
1204 public F set(final int index, final F obj) {
1205 if (index < 0) {
1206 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1207 }
1208 final int adj = resync(index);
1209 if (adj == size) {
1210 throw new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
1211 }
1212 final F ins = filter.filter(obj);
1213 if (ins != null) {
1214 final F oldc = filter.filter(ContentList.this.set(adj, ins));
1215 // optimize the backing....
1216 xdata = getDataModCount();
1217 return oldc;
1218 }
1219 throw new IllegalAddException("Filter won't allow index " +
1220 index + " to be set to " +
1221 (obj.getClass()).getName());
1222 }
1223
1224 /**
1225 * Return the number of items in this list
1226 *
1227 * @return The number of items in this list.
1228 */
1229 @Override
1230 public int size() {
1231 resync(-1);
1232 return backingsize;
1233 }
1234
1235 /**
1236 * Unlike the Arrays.binarySearch, this method never expects an
1237 * "already exists" condition, we only ever add, thus there will never
1238 * be a negative insertion-point.
1239 * @param indexes THe pointers to search within
1240 * @param len The number of pointers to search within
1241 * @param val The pointer we are checking for.
1242 * @param comp The Comparator to compare with
1243 * @return the insertion point.
1244 */
1245 @SuppressWarnings("unchecked")
1246 private final int fbinarySearch(final int[] indexes, final int len,
1247 final int val, final Comparator<? super F> comp) {
1248 int left = 0, mid = 0, right = len - 1, cmp = 0;
1249 final F base = (F)elementData[backingpos[val]];
1250 while (left <= right) {
1251 mid = (left + right) >>> 1;
1252 cmp = comp.compare(base, (F)elementData[indexes[mid]]);
1253 if (cmp == 0) {
1254 while (cmp == 0 && mid < right && comp.compare(
1255 base, (F)elementData[indexes[mid + 1]]) == 0) {
1256 mid++;
1257 }
1258 return mid + 1;
1259 } else if (cmp < 0) {
1260 right = mid - 1;
1261 } else {
1262 left = mid + 1;
1263 }
1264 }
1265 return left;
1266 }
1267
1268
1269 /**
1270 * Sorts this list using the supplied Comparator to compare elements.
1271 *
1272 * @param comp - the Comparator used to compare list elements. A null value indicates that the elements' natural ordering should be used
1273 * @Since 2.0.6
1274 */
1275 //Not till Java8 @Override
1276 public final void sort(final Comparator<? super F> comp) {
1277 // this size() forces a full scan/update of the list.
1278 if (comp == null) {
1279 // sort by the 'natural order', which, there is none.
1280 // options, throw exception, or let the current-order represent the natural order.
1281 // do nothing is the better alternative.
1282 return;
1283 }
1284 final int sz = size();
1285 final int[] indexes = new int[sz];
1286 for (int i = 0 ; i < sz; i++) {
1287 final int ip = fbinarySearch(indexes, i, i, comp);
1288 if (ip < i) {
1289 System.arraycopy(indexes, ip, indexes, ip+1, i - ip);
1290 }
1291 indexes[ip] = backingpos[i];
1292 }
1293 sortInPlace(indexes);
1294 }
1295
1296 }
1297
1298 /* * * * * * * * * * * * * FilterListIterator * * * * * * * * * * * */
1299 /* * * * * * * * * * * * * FilterListIterator * * * * * * * * * * * */
1300
1301 final class FilterListIterator<F extends Content> implements ListIterator<F> {
1302
1303 /** The Filter that applies */
1304 private final FilterList<F> filterlist;
1305
1306 /** Whether this iterator is in forward or reverse. */
1307 private boolean forward = false;
1308 /** Whether a call to remove() is valid */
1309 private boolean canremove = false;
1310 /** Whether a call to set() is valid */
1311 private boolean canset = false;
1312
1313 /** Expected modCount in our backing list */
1314 private int expectedmod = -1;
1315
1316 private int cursor = -1;
1317
1318 /**
1319 * Default constructor
1320 *
1321 * @param flist
1322 * The FilterList over which we will iterate.
1323 * @param start
1324 * where in the FilterList to start iteration.
1325 */
1326 FilterListIterator(final FilterList<F> flist, final int start) {
1327 filterlist = flist;
1328 expectedmod = getModCount();
1329 // always start list iterators in backward mode ....
1330 // it makes sense... really.
1331 forward = false;
1332
1333 if (start < 0) {
1334 throw new IndexOutOfBoundsException("Index: " + start + " Size: " + filterlist.size());
1335 }
1336
1337 final int adj = filterlist.resync(start);
1338
1339 if (adj == size && start > filterlist.size()) {
1340 // the start point is after the end of the list.
1341 // it is only allowed to be the same as size(), no larger.
1342 throw new IndexOutOfBoundsException("Index: " + start + " Size: " + filterlist.size());
1343 }
1344
1345 cursor = start;
1346 }
1347
1348 private void checkConcurrent() {
1349 if (expectedmod != getModCount()) {
1350 throw new ConcurrentModificationException("The ContentList " +
1351 "supporting the FilterList this iterator is " +
1352 "processing has been modified by something other " +
1353 "than this Iterator.");
1354 }
1355 }
1356
1357 /**
1358 * Returns <code>true</code> if this list iterator has a next element.
1359 */
1360 @Override
1361 public boolean hasNext() {
1362 return filterlist.resync(forward ? cursor + 1 : cursor) < size;
1363 }
1364
1365 /**
1366 * Returns <code>true</code> if this list iterator has more elements
1367 * when traversing the list in the reverse direction.
1368 */
1369 @Override
1370 public boolean hasPrevious() {
1371 return (forward ? cursor : cursor - 1) >= 0;
1372 }
1373
1374 /**
1375 * Returns the index of the element that would be returned by a
1376 * subsequent call to <code>next</code>.
1377 */
1378 @Override
1379 public int nextIndex() {
1380 return forward ? cursor + 1 : cursor;
1381 }
1382
1383 /**
1384 * Returns the index of the element that would be returned by a
1385 * subsequent call to <code>previous</code>. (Returns -1 if the list
1386 * iterator is at the beginning of the list.)
1387 */
1388 @Override
1389 public int previousIndex() {
1390 return forward ? cursor : cursor - 1;
1391 }
1392
1393 /**
1394 * Returns the next element in the list.
1395 */
1396 @Override
1397 public F next() {
1398 checkConcurrent();
1399 final int next = forward ? cursor + 1 : cursor;
1400
1401 if (filterlist.resync(next) >= size) {
1402 throw new NoSuchElementException("next() is beyond the end of the Iterator");
1403 }
1404
1405 cursor = next;
1406 forward = true;
1407 canremove = true;
1408 canset = true;
1409 return filterlist.get(cursor);
1410 }
1411
1412 /**
1413 * Returns the previous element in the list.
1414 */
1415 @Override
1416 public F previous() {
1417 checkConcurrent();
1418 final int prev = forward ? cursor : cursor - 1;
1419
1420 if (prev < 0) {
1421 throw new NoSuchElementException("previous() is beyond the beginning of the Iterator");
1422 }
1423
1424 cursor = prev;
1425 forward = false;
1426 canremove = true;
1427 canset = true;
1428 return filterlist.get(cursor);
1429 }
1430
1431 /**
1432 * Inserts the specified element into the list .
1433 */
1434 @Override
1435 public void add(final Content obj) {
1436 checkConcurrent();
1437 // always add before what would normally be returned by next();
1438 final int next = forward ? cursor + 1 : cursor;
1439
1440 filterlist.add(next, obj);
1441
1442 expectedmod = getModCount();
1443
1444 canremove = canset = false;
1445
1446 // a call to next() should be unaffected, so, whatever was going to
1447 // be next will still be next, remember, what was going to be next
1448 // has been shifted 'right' by our insert.
1449 // we ensure this by setting the cursor to next(), and making it
1450 // forward
1451 cursor = next;
1452 forward = true;
1453 }
1454
1455 /**
1456 * Removes from the list the last element that was returned by the last
1457 * call to <code>next</code> or <code>previous</code>.
1458 */
1459 @Override
1460 public void remove() {
1461 checkConcurrent();
1462 if (!canremove)
1463 throw new IllegalStateException("Can not remove an "
1464 + "element unless either next() or previous() has been called "
1465 + "since the last remove()");
1466 // we are removing the last entry returned by either next() or
1467 // previous().
1468 // the idea is to remove it, and pretend that we used to be at the
1469 // entry that happened *after* the removed entry.
1470 // so, get what would be the next entry (set at tmpcursor).
1471 // so call nextIndex to set tmpcursor to what would come after.
1472 filterlist.remove(cursor);
1473 forward = false;
1474 expectedmod = getModCount();
1475
1476 canremove = false;
1477 canset = false;
1478 }
1479
1480 /**
1481 * Replaces the last element returned by <code>next</code> or
1482 * <code>previous</code> with the specified element.
1483 */
1484 @Override
1485 public void set(final F obj) {
1486 checkConcurrent();
1487 if (!canset) {
1488 throw new IllegalStateException("Can not set an element "
1489 + "unless either next() or previous() has been called since the "
1490 + "last remove() or set()");
1491 }
1492
1493 filterlist.set(cursor, obj);
1494 expectedmod = getModCount();
1495
1496 }
1497
1498 }
1499
1500 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 /**
57 * Thrown when a data conversion from a string to value type fails, such as
58 * can happen with the {@link Attribute} convenience getter functions.
59 *
60 * @author Brett McLaughlin
61 * @author Jason Hunter
62 */
63 public class DataConversionException extends JDOMException {
64
65 /**
66 * Standard JDOM2 Exception Serialization. Default.
67 */
68 private static final long serialVersionUID = 200L;
69
70 /**
71 * Constructs an exception where the named construct couldn't be converted
72 * to the named data type.
73 *
74 * @param name name of the construct whose value failed conversion
75 * @param dataType type the conversion was attempting to create
76 */
77 public DataConversionException(String name, String dataType) {
78 super(new StringBuilder()
79 .append("The XML construct ")
80 .append(name)
81 .append(" could not be converted to a ")
82 .append(dataType)
83 .toString());
84 }
85 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.*;
57
58 /**
59 * Creates the standard top-level JDOM classes (Element, Document, Comment,
60 * etc). A subclass of this factory might construct custom classes.
61 *
62 * @author Ken Rune Holland
63 * @author Phil Nelson
64 * @author Bradley S. Huffman
65 * @author Rolf Lear
66 */
67 public class DefaultJDOMFactory implements JDOMFactory {
68
69 /**
70 * Creates a new DefaultJDOMFactory instance.
71 */
72 public DefaultJDOMFactory() {
73 // do nothing special
74 }
75
76 // Allow Javadocs to inherit from JDOMFactory
77
78 @Override
79 public Attribute attribute(String name, String value, Namespace namespace) {
80 return new Attribute(name, value, namespace);
81 }
82
83 @Override
84 @Deprecated
85 public Attribute attribute(String name, String value, int type,
86 Namespace namespace) {
87 return new Attribute(name, value, AttributeType.byIndex(type),
88 namespace);
89 }
90
91 @Override
92 public Attribute attribute(String name, String value, AttributeType type,
93 Namespace namespace) {
94 return new Attribute(name, value, type, namespace);
95 }
96
97 @Override
98 public Attribute attribute(String name, String value) {
99 return new Attribute(name, value);
100 }
101
102 @Override
103 @Deprecated
104 public Attribute attribute(String name, String value, int type) {
105 return new Attribute(name, value, type);
106 }
107
108 @Override
109 public Attribute attribute(String name, String value, AttributeType type) {
110 return new Attribute(name, value, type);
111 }
112
113 @Override
114 public final CDATA cdata(String str) {
115 return cdata(-1, -1, str);
116 }
117
118 @Override
119 public CDATA cdata(final int line, final int col, final String text) {
120 return new CDATA(text);
121 }
122
123 @Override
124 public final Text text(String str) {
125 return text(-1, -1, str);
126 }
127
128 @Override
129 public Text text(final int line, final int col, final String text) {
130 return new Text(text);
131 }
132
133 @Override
134 public final Comment comment(String text) {
135 return comment(-1, -1, text);
136 }
137
138 @Override
139 public Comment comment(final int line, final int col, final String text) {
140 return new Comment(text);
141 }
142
143 @Override
144 public final DocType docType(String elementName, String publicID, String systemID) {
145 return docType(-1, -1, elementName, publicID, systemID);
146 }
147
148 @Override
149 public DocType docType(final int line, final int col,
150 final String elementName, String publicID, String systemID) {
151 return new DocType(elementName, publicID, systemID);
152 }
153
154 @Override
155 public final DocType docType(String elementName, String systemID) {
156 return docType(-1, -1, elementName, systemID);
157 }
158
159 @Override
160 public DocType docType(final int line, final int col,
161 final String elementName, String systemID) {
162 return new DocType(elementName, systemID);
163 }
164
165 @Override
166 public final DocType docType(String elementName) {
167 return docType(-1, -1, elementName);
168 }
169
170 @Override
171 public DocType docType(final int line, final int col,
172 final String elementName) {
173 return new DocType(elementName);
174 }
175
176 @Override
177 public Document document(Element rootElement, DocType docType) {
178 return new Document(rootElement, docType);
179 }
180
181 @Override
182 public Document document(Element rootElement, DocType docType,
183 String baseURI) {
184 return new Document(rootElement, docType, baseURI);
185 }
186
187 @Override
188 public Document document(Element rootElement) {
189 return new Document(rootElement);
190 }
191
192 @Override
193 public Element element(String name, Namespace namespace) {
194 return element(-1, -1, name, namespace);
195 }
196
197 @Override
198 public Element element(final int line, final int col, final String name,
199 Namespace namespace) {
200 return new Element(name, namespace);
201 }
202
203 @Override
204 public Element element(String name) {
205 return element(-1, -1, name);
206 }
207
208 @Override
209 public Element element(final int line, final int col, final String name) {
210 return new Element(name);
211 }
212
213 @Override
214 public Element element(String name, String uri) {
215 return element(-1, -1, name, uri);
216 }
217
218 @Override
219 public Element element(final int line, final int col, final String name,
220 String uri) {
221 return new Element(name, uri);
222 }
223
224 @Override
225 public Element element(String name, String prefix, String uri) {
226 return element(-1, -1, name, prefix, uri);
227 }
228
229 @Override
230 public Element element(final int line, final int col, final String name,
231 String prefix, String uri) {
232 return new Element(name, prefix, uri);
233 }
234
235 @Override
236 public final ProcessingInstruction processingInstruction(String target) {
237 return processingInstruction(-1, -1, target);
238 }
239
240 @Override
241 public ProcessingInstruction processingInstruction(final int line,
242 final int col, final String target) {
243 return new ProcessingInstruction(target);
244 }
245
246 @Override
247 public final ProcessingInstruction processingInstruction(String target,
248 Map<String, String> data) {
249 return processingInstruction(-1, -1, target, data);
250 }
251
252 @Override
253 public ProcessingInstruction processingInstruction(final int line,
254 final int col, final String target, Map<String, String> data) {
255 return new ProcessingInstruction(target, data);
256 }
257
258 @Override
259 public final ProcessingInstruction processingInstruction(String target,
260 String data) {
261 return processingInstruction(-1, -1, target, data);
262 }
263
264 @Override
265 public ProcessingInstruction processingInstruction(final int line,
266 final int col, final String target, String data) {
267 return new ProcessingInstruction(target, data);
268 }
269
270 @Override
271 public final EntityRef entityRef(String name) {
272 return entityRef(-1, -1, name);
273 }
274
275 @Override
276 public EntityRef entityRef(final int line, final int col, final String name) {
277 return new EntityRef(name);
278 }
279
280 @Override
281 public final EntityRef entityRef(String name, String publicID, String systemID) {
282 return entityRef(-1, -1, name, publicID, systemID);
283 }
284
285 @Override
286 public EntityRef entityRef(final int line, final int col,
287 final String name, String publicID, String systemID) {
288 return new EntityRef(name, publicID, systemID);
289 }
290
291 @Override
292 public final EntityRef entityRef(String name, String systemID) {
293 return entityRef(-1, -1, name, systemID);
294 }
295
296 @Override
297 public EntityRef entityRef(final int line, final int col,
298 final String name, String systemID) {
299 return new EntityRef(name, systemID);
300 }
301
302 // =====================================================================
303 // List manipulation
304 // =====================================================================
305
306 @Override
307 public void addContent(Parent parent, Content child) {
308 if (parent instanceof Document) {
309 ((Document) parent).addContent(child);
310 } else {
311 ((Element) parent).addContent(child);
312 }
313 }
314
315 @Override
316 public void setAttribute(Element parent, Attribute a) {
317 parent.setAttribute(a);
318 }
319
320 @Override
321 public void addNamespaceDeclaration(Element parent, Namespace additional) {
322 parent.addNamespaceDeclaration(additional);
323 }
324
325 @Override
326 public void setRoot(Document doc, Element root) {
327 doc.setRootElement(root);
328 }
329 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.*;
57
58 import org.jdom.internal.ArrayCopy;
59 import org.jdom.util.IteratorIterable;
60
61 /**
62 * Traverse all a parent's descendants (all children at any level below
63 * the parent - excludes the parent itself).
64 *
65 * @author Bradley S. Huffman
66 * @author Jason Hunter
67 * @author Rolf Lear
68 */
69 final class DescendantIterator implements IteratorIterable<Content> {
70
71 /** Needed to be Iterable! */
72 private final Parent parent;
73
74 /*
75 * Note, we use an Array of Object here, even through
76 * List<Iterator<Content>> would look neater, etc.
77 * Fact is, for 'hamlet', using a list for the stack takes about
78 * twice as long as using the Object[] array.
79 */
80 private Object[] stack = new Object[16];
81 private int ssize = 0;
82
83 /** The iterator that supplied to most recent next() */
84 private Iterator<Content> current = null;
85 /** The iterator going down the tree, null unless next() returned Parent */
86 private Iterator<Content> descending = null;
87 /** The iterator going up the tree, null unless next() returned dead-end */
88 private Iterator<Content> ascending = null;
89 /** what it says... */
90 private boolean hasnext = true;
91
92 /**
93 * Iterator for the descendants of the supplied object.
94 *
95 * @param parent document or element whose descendants will be iterated
96 */
97 DescendantIterator(Parent parent) {
98 this.parent = parent;
99 // can trust that parent is not null, DescendantIterator is package-private.
100 current = parent.getContent().iterator();
101 hasnext = current.hasNext();
102 }
103
104 @Override
105 public DescendantIterator iterator() {
106 // Implement the Iterable stuff.
107 return new DescendantIterator(parent);
108 }
109
110 /**
111 * Returns <b>true</b> if the iteration has more {@link Content} descendants.
112 *
113 * @return true is the iterator has more descendants
114 */
115 @Override
116 public boolean hasNext() {
117 return hasnext;
118 }
119
120 /**
121 * Returns the next {@link Content} descendant.
122 *
123 * @return the next descendant
124 */
125 @Override
126 public Content next() {
127 // set the 'current' if it needs changing.
128 if (descending != null) {
129 current = descending;
130 descending = null;
131 } else if (ascending != null) {
132 current = ascending;
133 ascending = null;
134 }
135
136 final Content ret = current.next();
137
138 // got an item to return.
139 // sort out the next state....
140 if ((ret instanceof Element) && ((Element)ret).getContentSize() > 0) {
141 // there is another descendant, and it has values.
142 // our next will be down....
143 descending = ((Element)ret).getContent().iterator();
144 if (ssize >= stack.length) {
145 stack = ArrayCopy.copyOf(stack, ssize + 16);
146 }
147 stack[ssize++] = current;
148 return ret;
149 }
150
151 if (current.hasNext()) {
152 // our next will be along....
153 return ret;
154 }
155
156 // our next will be up.
157 while (ssize > 0) {
158
159 // if the stack was generic, this would not be needed, but,
160 // the java.uti.* stack codes are too slow.
161 @SuppressWarnings("unchecked")
162 final Iterator<Content> subit = (Iterator<Content>)stack[--ssize];
163 ascending = subit;
164 stack[ssize] = null;
165 if (ascending.hasNext()) {
166 return ret;
167 }
168 }
169
170 ascending = null;
171 hasnext = false;
172 return ret;
173 }
174
175 /**
176 * Detaches the last {@link org.jdom.Content} returned by the last call to
177 * next from it's parent. <b>Note</b>: this <b>does not</b> affect
178 * iteration and all children, siblings, and any node following the
179 * removed node (in document order) will be visited.
180 */
181 @Override
182 public void remove() {
183 current.remove();
184 // if our next move was to go down, we can't.
185 // we can go along, or up.
186 descending = null;
187 if (current.hasNext() || ascending != null) {
188 // we have a next element, or our next move was up anyway.
189 return;
190 }
191 // our next move was going to be down, or accross, but those are not
192 // possible any more, need to check up.
193 // our next will be up.
194 while (ssize > 0) {
195 @SuppressWarnings("unchecked")
196 final Iterator<Content> subit = (Iterator<Content>)stack[--ssize];
197 stack[ssize] = null;
198 ascending = subit;
199 if (ascending.hasNext()) {
200 return;
201 }
202 }
203 ascending = null;
204 hasnext = false;
205 }
206
207 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import org.jdom.output.XMLOutputter2;
57
58 /**
59 * An XML DOCTYPE declaration. Method allow the user to get and set the
60 * root element name, public id, system id and internal subset.
61 *
62 * @author Brett McLaughlin
63 * @author Jason Hunter
64 */
65 public class DocType extends Content {
66
67 /**
68 * JDOM2 Serialization. In this case, DocType is simple.
69 */
70 private static final long serialVersionUID = 200L;
71
72 /**
73 * The element being constrained
74 * @serialField The root element name
75 */
76 protected String elementName;
77
78 /**
79 * The public ID of the DOCTYPE
80 * @serialField The PublicID, may be null
81 */
82 protected String publicID;
83
84 /**
85 * The system ID of the DOCTYPE
86 * @serialField The SystemID, may be null
87 */
88 protected String systemID;
89
90 /**
91 * The internal subset of the DOCTYPE
92 * @serialField The InternalSubset, may be null
93 */
94 protected String internalSubset;
95
96 /**
97 * Default, no-args constructor for implementations to use if needed.
98 */
99 protected DocType() {
100 super(CType.DocType);
101 }
102
103 /*
104 * XXX:
105 * We need to take care of entities and notations here.
106 */
107
108 /**
109 * This will create the <code>DocType</code> with
110 * the specified element name and a reference to an
111 * external DTD.
112 *
113 * @param elementName <code>String</code> name of
114 * element being constrained.
115 * @param publicID <code>String</code> public ID of
116 * referenced DTD
117 * @param systemID <code>String</code> system ID of
118 * referenced DTD
119 * @throws IllegalDataException if the given system ID is not a legal
120 * system literal or the public ID is not a legal public ID.
121 * @throws IllegalNameException if the given root element name is not a
122 * legal XML element name.
123 */
124 public DocType(String elementName, String publicID, String systemID) {
125 super(CType.DocType);
126 setElementName(elementName);
127 setPublicID(publicID);
128 setSystemID(systemID);
129 }
130
131 /**
132 * This will create the <code>DocType</code> with
133 * the specified element name and reference to an
134 * external DTD.
135 *
136 * @param elementName <code>String</code> name of
137 * element being constrained.
138 * @param systemID <code>String</code> system ID of
139 * referenced DTD
140 * @throws IllegalDataException if the given system ID is not a legal
141 * system literal.
142 * @throws IllegalNameException if the given root element name is not a
143 * legal XML element name.
144 */
145 public DocType(String elementName, String systemID) {
146 this(elementName, null, systemID);
147 }
148
149 /**
150 * This will create the <code>DocType</code> with
151 * the specified element name
152 *
153 * @param elementName <code>String</code> name of
154 * element being constrained.
155 * @throws IllegalNameException if the given root element name is not a
156 * legal XML element name.
157 */
158 public DocType(String elementName) {
159 this(elementName, null, null);
160 }
161
162 /**
163 * This will retrieve the element name being constrained.
164 *
165 * @return <code>String</code> - element name for DOCTYPE
166 */
167 public String getElementName() {
168 return elementName;
169 }
170
171 /**
172 * This will set the root element name declared by this
173 * DOCTYPE declaration.
174 *
175 * @return this <code>DocType</code> instance
176 * @param elementName <code>String</code> name of
177 * root element being constrained.
178 * @throws IllegalNameException if the given root element name is not a
179 * legal XML element name.
180 */
181 public DocType setElementName(String elementName) {
182 // This can contain a colon so we use checkXMLName()
183 // instead of checkElementName()
184 String reason = Verifier.checkXMLName(elementName);
185 if (reason != null) {
186 throw new IllegalNameException(elementName, "DocType", reason);
187 }
188 this.elementName = elementName;
189 return this;
190 }
191
192 /**
193 * This will retrieve the public ID of an externally
194 * referenced DTD, or an empty <code>String</code> if
195 * none is referenced.
196 *
197 * @return <code>String</code> - public ID of referenced DTD.
198 */
199 public String getPublicID() {
200 return publicID;
201 }
202
203 /**
204 * This will set the public ID of an externally
205 * referenced DTD.
206 *
207 * @param publicID id to set
208 * @return DocType <code>DocType</code> this DocType object
209 * @throws IllegalDataException if the given public ID is not a legal
210 * public ID.
211 */
212 public DocType setPublicID(String publicID) {
213 String reason = Verifier.checkPublicID(publicID);
214 if (reason != null) {
215 throw new IllegalDataException(publicID, "DocType", reason);
216 }
217 this.publicID = publicID;
218
219 return this;
220 }
221
222 /**
223 * This will retrieve the system ID of an externally
224 * referenced DTD, or an empty <code>String</code> if
225 * none is referenced.
226 *
227 * @return <code>String</code> - system ID of referenced DTD.
228 */
229 public String getSystemID() {
230 return systemID;
231 }
232
233 /**
234 * This will set the system ID of an externally
235 * referenced DTD.
236 *
237 * @param systemID id to set
238 * @return systemID <code>String</code> system ID of
239 * referenced DTD.
240 * @throws IllegalDataException if the given system ID is not a legal
241 * system literal.
242 */
243 public DocType setSystemID(String systemID) {
244 String reason = Verifier.checkSystemLiteral(systemID);
245 if (reason != null) {
246 throw new IllegalDataException(systemID, "DocType", reason);
247 }
248 this.systemID = systemID;
249
250 return this;
251 }
252
253 /**
254 * Returns the empty string since doctypes don't have an XPath
255 * 1.0 string value.
256 * @return the empty string
257 */
258 @Override
259 public String getValue() {
260 return ""; // doctypes don't have an XPath string value
261 }
262
263 /**
264 * This sets the data for the internal subset.
265 *
266 * @param newData data for the internal subset, as a
267 * <code>String</code>.
268 */
269 public void setInternalSubset(String newData) {
270 internalSubset = newData;
271 }
272
273 /**
274 * This returns the data for the internal subset.
275 *
276 * @return <code>String</code> - the internal subset
277 */
278 public String getInternalSubset() {
279 return internalSubset;
280 }
281
282 /**
283 * This returns a <code>String</code> representation of the
284 * <code>DocType</code>, suitable for debugging.
285 *
286 * @return <code>String</code> - information about the
287 * <code>DocType</code>
288 */
289 @Override
290 public String toString() {
291 return new StringBuilder()
292 .append("[DocType: ")
293 .append(new XMLOutputter2().outputString(this))
294 .append("]")
295 .toString();
296 }
297
298 @Override
299 public DocType clone() {
300 return (DocType)super.clone();
301 }
302
303 @Override
304 public DocType detach() {
305 return (DocType)super.detach();
306 }
307
308 @Override
309 protected DocType setParent(Parent parent) {
310 return (DocType)super.setParent(parent);
311 }
312
313 @Override
314 public Document getParent() {
315 // because DocType can only be attached to a Document.
316 return (Document)super.getParent();
317 }
318
319 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.io.IOException;
57 import java.io.ObjectInputStream;
58 import java.io.ObjectOutputStream;
59 import java.util.*;
60
61 import org.jdom.filter.AbstractFilter;
62 import org.jdom.filter.Filter;
63 import org.jdom.output.XMLOutputter2;
64 import org.jdom.util.IteratorIterable;
65
66 /**
67 * An XML document. Methods allow access to the root element as well as the
68 * {@link DocType} and other document-level information.
69 *
70 * @author Brett McLaughlin
71 * @author Jason Hunter
72 * @author Jools Enticknap
73 * @author Bradley S. Huffman
74 * @author Rolf Lear
75 */
76 public class Document extends CloneBase implements Parent {
77
78 /**
79 * This document's content including comments, PIs, a possible
80 * DocType, and a root element.
81 * Subclassers have to track content using their own
82 * mechanism.
83 */
84 transient ContentList content = new ContentList(this);
85
86 /**
87 * See http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/core.html#baseURIs-Considerations
88 */
89 protected String baseURI = null;
90
91 // Supports the setProperty/getProperty calls
92 private transient HashMap<String,Object> propertyMap = null;
93
94 /**
95 * Creates a new empty document. A document must have a root element,
96 * so this document will not be well-formed and accessor methods will
97 * throw an IllegalStateException if this document is accessed before a
98 * root element is added. This method is most useful for build tools.
99 */
100 public Document() {}
101
102 /**
103 * This will create a new <code>Document</code>,
104 * with the supplied <code>{@link Element}</code>
105 * as the root element, the supplied
106 * <code>{@link DocType}</code> declaration, and the specified
107 * base URI.
108 *
109 * @param rootElement <code>Element</code> for document root.
110 * @param docType <code>DocType</code> declaration.
111 * @param baseURI the URI from which this doucment was loaded.
112 * @throws IllegalAddException if the given docType object
113 * is already attached to a document or the given
114 * rootElement already has a parent
115 */
116 public Document(Element rootElement, DocType docType, String baseURI) {
117 if (rootElement != null) {
118 setRootElement(rootElement);
119 }
120 if (docType != null) {
121 setDocType(docType);
122 }
123 if (baseURI != null) {
124 setBaseURI(baseURI);
125 }
126 }
127
128 /**
129 * This will create a new <code>Document</code>,
130 * with the supplied <code>{@link Element}</code>
131 * as the root element and the supplied
132 * <code>{@link DocType}</code> declaration.
133 *
134 * @param rootElement <code>Element</code> for document root.
135 * @param docType <code>DocType</code> declaration.
136 * @throws IllegalAddException if the given DocType object
137 * is already attached to a document or the given
138 * rootElement already has a parent
139 */
140 public Document(Element rootElement, DocType docType) {
141 this(rootElement, docType, null);
142 }
143
144 /**
145 * This will create a new <code>Document</code>,
146 * with the supplied <code>{@link Element}</code>
147 * as the root element, and no <code>{@link DocType}</code>
148 * declaration.
149 *
150 * @param rootElement <code>Element</code> for document root
151 * @throws IllegalAddException if the given rootElement already has
152 * a parent.
153 */
154 public Document(Element rootElement) {
155 this(rootElement, null, null);
156 }
157
158 /**
159 * This will create a new <code>Document</code>,
160 * with the supplied list of content, and a
161 * <code>{@link DocType}</code> declaration only if the content
162 * contains a DocType instance. A null list is treated the
163 * same as the no-arg constructor.
164 *
165 * @param content <code>List</code> of starter content
166 * @throws IllegalAddException if the List contains more than
167 * one Element or objects of illegal types.
168 */
169 public Document(List<? extends Content> content) {
170 setContent(content);
171 }
172
173 @Override
174 public int getContentSize() {
175 return content.size();
176 }
177
178 @Override
179 public int indexOf(Content child) {
180 return content.indexOf(child);
181 }
182
183 // /**
184 // * Starting at the given index (inclusive), return the index of
185 // * the first child matching the supplied filter, or -1
186 // * if none is found.
187 // *
188 // * @return index of child, or -1 if none found.
189 // */
190 // private int indexOf(int start, Filter filter) {
191 // int size = getContentSize();
192 // for (int i = start; i < size; i++) {
193 // if (filter.matches(getContent(i))) {
194 // return i;
195 // }
196 // }
197 // return -1;
198 // }
199
200 /**
201 * This will return <code>true</code> if this document has a
202 * root element, <code>false</code> otherwise.
203 *
204 * @return <code>true</code> if this document has a root element,
205 * <code>false</code> otherwise.
206 */
207 public boolean hasRootElement() {
208 return (content.indexOfFirstElement() < 0) ? false : true;
209 }
210
211 /**
212 * This will return the root <code>Element</code>
213 * for this <code>Document</code>
214 *
215 * @return <code>Element</code> - the document's root element
216 * @throws IllegalStateException if the root element hasn't been set
217 */
218 public Element getRootElement() {
219 int index = content.indexOfFirstElement();
220 if (index < 0) {
221 throw new IllegalStateException("Root element not set");
222 }
223 return (Element) content.get(index);
224 }
225
226 /**
227 * This sets the root <code>{@link Element}</code> for the
228 * <code>Document</code>. If the document already has a root
229 * element, it is replaced.
230 *
231 * @param rootElement <code>Element</code> to be new root.
232 * @return <code>Document</code> - modified Document.
233 * @throws IllegalAddException if the given rootElement already has
234 * a parent.
235 */
236 public Document setRootElement(Element rootElement) {
237 int index = content.indexOfFirstElement();
238 if (index < 0) {
239 content.add(rootElement);
240 }
241 else {
242 content.set(index, rootElement);
243 }
244 return this;
245 }
246
247 /**
248 * Detach the root <code>{@link Element}</code> from this document.
249 *
250 * @return removed root <code>Element</code>
251 */
252 public Element detachRootElement() {
253 int index = content.indexOfFirstElement();
254 if (index < 0)
255 return null;
256 return (Element) removeContent(index);
257 }
258
259 /**
260 * This will return the <code>{@link DocType}</code>
261 * declaration for this <code>Document</code>, or
262 * <code>null</code> if none exists.
263 *
264 * @return <code>DocType</code> - the DOCTYPE declaration.
265 */
266 public DocType getDocType() {
267 int index = content.indexOfDocType();
268 if (index < 0) {
269 return null;
270 }
271 return (DocType) content.get(index);
272 }
273
274 /**
275 * This will set the <code>{@link DocType}</code>
276 * declaration for this <code>Document</code>. Note
277 * that a DocType can only be attached to one Document.
278 * Attempting to set the DocType to a DocType object
279 * that already belongs to a Document will result in an
280 * IllegalAddException being thrown.
281 *
282 * @param docType <code>DocType</code> declaration.
283 * @return object on which the method was invoked
284 * @throws IllegalAddException if the given docType is
285 * already attached to a Document.
286 */
287 public Document setDocType(DocType docType) {
288 if (docType == null) {
289 // Remove any existing doctype
290 int docTypeIndex = content.indexOfDocType();
291 if (docTypeIndex >= 0) content.remove(docTypeIndex);
292 return this;
293 }
294
295 if (docType.getParent() != null) {
296 throw new IllegalAddException(docType,
297 "The DocType already is attached to a document");
298 }
299
300 // Add DocType to head if new, replace old otherwise
301 int docTypeIndex = content.indexOfDocType();
302 if (docTypeIndex < 0) {
303 content.add(0, docType);
304 }
305 else {
306 content.set(docTypeIndex, docType);
307 }
308
309 return this;
310 }
311
312 /**
313 * Appends the child to the end of the content list.
314 *
315 * @param child child to append to end of content list
316 * @return the document on which the method was called
317 * @throws IllegalAddException if the given child already has a parent.
318 */
319 @Override
320 public Document addContent(Content child) {
321 content.add(child);
322 return this;
323 }
324
325 /**
326 * Appends all children in the given collection to the end of
327 * the content list. In event of an exception during add the
328 * original content will be unchanged and the objects in the supplied
329 * collection will be unaltered.
330 *
331 * @param c collection to append
332 * @return the document on which the method was called
333 * @throws IllegalAddException if any item in the collection
334 * already has a parent or is of an illegal type.
335 */
336 @Override
337 public Document addContent(Collection<? extends Content> c) {
338 content.addAll(c);
339 return this;
340 }
341
342 /**
343 * Inserts the child into the content list at the given index.
344 *
345 * @param index location for adding the collection
346 * @param child child to insert
347 * @return the parent on which the method was called
348 * @throws IndexOutOfBoundsException if index is negative or beyond
349 * the current number of children
350 * @throws IllegalAddException if the given child already has a parent.
351 */
352 @Override
353 public Document addContent(int index, Content child) {
354 content.add(index, child);
355 return this;
356 }
357
358 /**
359 * Inserts the content in a collection into the content list
360 * at the given index. In event of an exception the original content
361 * will be unchanged and the objects in the supplied collection will be
362 * unaltered.
363 *
364 * @param index location for adding the collection
365 * @param c collection to insert
366 * @return the parent on which the method was called
367 * @throws IndexOutOfBoundsException if index is negative or beyond
368 * the current number of children
369 * @throws IllegalAddException if any item in the collection
370 * already has a parent or is of an illegal type.
371 */
372 @Override
373 public Document addContent(int index, Collection<? extends Content> c) {
374 content.addAll(index, c);
375 return this;
376 }
377
378 @Override
379 public List<Content> cloneContent() {
380 int size = getContentSize();
381 List<Content> list = new ArrayList<Content>(size);
382 for (int i = 0; i < size; i++) {
383 Content child = getContent(i);
384 list.add(child.clone());
385 }
386 return list;
387 }
388
389 @Override
390 public Content getContent(int index) {
391 return content.get(index);
392 }
393
394 // public Content getChild(Filter filter) {
395 // int i = indexOf(0, filter);
396 // return (i < 0) ? null : getContent(i);
397 // }
398
399 /**
400 * This will return all content for the <code>Document</code>.
401 * The returned list is "live" in document order and changes to it
402 * affect the document's actual content.
403 *
404 * <p>
405 * Sequential traversal through the List is best done with a Iterator
406 * since the underlying implement of List.size() may require walking the
407 * entire list.
408 * </p>
409 *
410 * @return <code>List</code> - all Document content
411 * @throws IllegalStateException if the root element hasn't been set
412 */
413 @Override
414 public List<Content> getContent() {
415 if (!hasRootElement())
416 throw new IllegalStateException("Root element not set");
417 return content;
418 }
419
420 /**
421 * Return a filtered view of this <code>Document</code>'s content.
422 *
423 * <p>
424 * Sequential traversal through the List is best done with a Iterator
425 * since the underlying implement of List.size() may require walking the
426 * entire list.
427 * </p>
428 *
429 * @param filter <code>Filter</code> to apply
430 * Note that the {@link Filters} class has a number of predefined, useful
431 * filters.
432 * @return <code>List</code> - filtered Document content
433 * @throws IllegalStateException if the root element hasn't been set
434 */
435 @Override
436 public <F extends Content> List<F> getContent(Filter<F> filter) {
437 if (!hasRootElement())
438 throw new IllegalStateException("Root element not set");
439 return content.getView(filter);
440 }
441
442 /**
443 * Removes all child content from this parent.
444 *
445 * @return list of the old children detached from this parent
446 */
447 @Override
448 public List<Content> removeContent() {
449 List<Content> old = new ArrayList<Content>(content);
450 content.clear();
451 return old;
452 }
453
454 /**
455 * Remove all child content from this parent matching the supplied filter.
456 *
457 * @param filter filter to select which content to remove
458 * Note that the {@link Filters} class has a number of predefined, useful
459 * filters.
460 * @return list of the old children detached from this parent
461 */
462 @Override
463 public <F extends Content> List<F> removeContent(Filter<F> filter) {
464 List<F> old = new ArrayList<F>();
465 Iterator<F> itr = content.getView(filter).iterator();
466 while (itr.hasNext()) {
467 F child = itr.next();
468 old.add(child);
469 itr.remove();
470 }
471 return old;
472 }
473
474 /**
475 * This sets the content of the <code>Document</code>. The supplied
476 * List should contain only objects of type <code>Element</code>,
477 * <code>Comment</code>, and <code>ProcessingInstruction</code>.
478 *
479 * <p>
480 * When all objects in the supplied List are legal and before the new
481 * content is added, all objects in the old content will have their
482 * parentage set to null (no parent) and the old content list will be
483 * cleared. This has the effect that any active list (previously obtained
484 * with a call to {@link #getContent}) will also
485 * change to reflect the new content. In addition, all objects in the
486 * supplied List will have their parentage set to this document, but the
487 * List itself will not be "live" and further removals and additions will
488 * have no effect on this document content. If the user wants to continue
489 * working with a "live" list, then a call to setContent should be
490 * followed by a call to {@link #getContent} to
491 * obtain a "live" version of the content.
492 * </p>
493 *
494 * <p>
495 * Passing a null or empty List clears the existing content.
496 * </p>
497 *
498 * <p>
499 * In event of an exception the original content will be unchanged and
500 * the objects in the supplied content will be unaltered.
501 * </p>
502 *
503 * @param newContent <code>List</code> of content to set
504 * @return this document modified
505 * @throws IllegalAddException if the List contains objects of
506 * illegal types or with existing parentage.
507 */
508 public Document setContent(Collection<? extends Content> newContent) {
509 content.clearAndSet(newContent);
510 return this;
511 }
512
513 /**
514 *
515 * <p>
516 * Sets the effective URI from which this document was loaded,
517 * and against which relative URLs in this document will be resolved.
518 * </p>
519 *
520 * @param uri the base URI of this document
521 */
522 public final void setBaseURI(String uri) {
523 this.baseURI = uri; // XXX We don't check the URI
524 }
525
526 /**
527 * <p>
528 * Returns the URI from which this document was loaded,
529 * or null if this is not known.
530 * </p>
531 *
532 * @return the base URI of this document
533 */
534 public final String getBaseURI() {
535 return baseURI;
536 }
537
538 /**
539 * Replace the current child the given index with the supplied child.
540 * <p>
541 * In event of an exception the original content will be unchanged and
542 * the supplied child will be unaltered.
543 * </p>
544 *
545 * @param index - index of child to replace.
546 * @param child - child to add.
547 * @return this document instance
548 * @throws IllegalAddException if the supplied child is already attached
549 * or not legal content for this parent.
550 * @throws IndexOutOfBoundsException if index is negative or greater
551 * than the current number of children.
552 */
553 public Document setContent(int index, Content child) {
554 content.set(index, child);
555 return this;
556 }
557
558 /**
559 * Replace the child at the given index whith the supplied
560 * collection.
561 * <p>
562 * In event of an exception the original content will be unchanged and
563 * the content in the supplied collection will be unaltered.
564 * </p>
565 *
566 * @param index - index of child to replace.
567 * @param collection - collection of content to add.
568 * @return object on which the method was invoked
569 * @throws IllegalAddException if the collection contains objects of
570 * illegal types.
571 * @throws IndexOutOfBoundsException if index is negative or greater
572 * than the current number of children.
573 */
574 public Document setContent(int index, Collection<? extends Content> collection) {
575 content.remove(index);
576 content.addAll(index, collection);
577 return this;
578 }
579
580 @Override
581 public boolean removeContent(Content child) {
582 return content.remove(child);
583 }
584
585 @Override
586 public Content removeContent(int index) {
587 return content.remove(index);
588 }
589
590 /**
591 * Set this document's content to be the supplied child.
592 * <p>
593 * If the supplied child is legal content for a Document and before
594 * it is added, all content in the current content list will
595 * be cleared and all current children will have their parentage set to
596 * null.
597 * <p>
598 * This has the effect that any active list (previously obtained with
599 * a call to one of the {@link #getContent} methods will also change
600 * to reflect the new content. In addition, all content in the supplied
601 * collection will have their parentage set to this Document. If the user
602 * wants to continue working with a <b>"live"</b> list of this Document's
603 * child, then a call to setContent should be followed by a call to one
604 * of the {@link #getContent} methods to obtain a <b>"live"</b>
605 * version of the children.
606 * <p>
607 * Passing a null child clears the existing content.
608 * <p>
609 * In event of an exception the original content will be unchanged and
610 * the supplied child will be unaltered.
611 *
612 * @param child new content to replace existing content
613 * @return the parent on which the method was called
614 * @throws IllegalAddException if the supplied child is already attached
615 * or not legal content for this parent
616 */
617 public Document setContent(Content child) {
618 content.clear();
619 content.add(child);
620 return this;
621 }
622
623 /**
624 * This returns a <code>String</code> representation of the
625 * <code>Document</code>, suitable for debugging. If the XML
626 * representation of the <code>Document</code> is desired,
627 * {@link XMLOutputter2#outputString(Document)}
628 * should be used.
629 *
630 * @return <code>String</code> - information about the
631 * <code>Document</code>
632 */
633 @Override
634 public String toString() {
635 StringBuilder stringForm = new StringBuilder()
636 .append("[Document: ");
637
638 DocType docType = getDocType();
639 if (docType != null) {
640 stringForm.append(docType.toString())
641 .append(", ");
642 } else {
643 stringForm.append(" No DOCTYPE declaration, ");
644 }
645
646 Element rootElement = hasRootElement() ? getRootElement() : null ;
647 if (rootElement != null) {
648 stringForm.append("Root is ")
649 .append(rootElement.toString());
650 } else {
651 stringForm.append(" No root element"); // shouldn't happen
652 }
653
654 stringForm.append("]");
655
656 return stringForm.toString();
657 }
658
659 /**
660 * This tests for equality of this <code>Document</code> to the supplied
661 * <code>Object</code>.
662 *
663 * @param ob <code>Object</code> to compare to
664 * @return <code>boolean</code> whether the <code>Document</code> is
665 * equal to the supplied <code>Object</code>
666 */
667 @Override
668 public final boolean equals(Object ob) {
669 return (ob == this);
670 }
671
672 /**
673 * This returns the hash code for this <code>Document</code>.
674 *
675 * @return <code>int</code> hash code
676 */
677 @Override
678 public final int hashCode() {
679 return super.hashCode();
680 }
681
682 /**
683 * This will return a deep clone of this <code>Document</code>.
684 *
685 * @return <code>Object</code> clone of this <code>Document</code>
686 */
687 @Override
688 public Document clone() {
689 final Document doc = (Document) super.clone();
690
691 // The clone has a reference to this object's content list, so
692 // owerwrite with a empty list
693 doc.content = new ContentList(doc);
694
695 // Add the cloned content to clone
696
697 for (int i = 0; i < content.size(); i++) {
698 Object obj = content.get(i);
699 if (obj instanceof Element) {
700 Element element = ((Element)obj).clone();
701 doc.content.add(element);
702 }
703 else if (obj instanceof Comment) {
704 Comment comment = ((Comment)obj).clone();
705 doc.content.add(comment);
706 }
707 else if (obj instanceof ProcessingInstruction) {
708 ProcessingInstruction pi = ((ProcessingInstruction)obj).clone();
709 doc.content.add(pi);
710 }
711 else if (obj instanceof DocType) {
712 DocType dt = ((DocType)obj).clone();
713 doc.content.add(dt);
714 }
715 }
716
717 return doc;
718 }
719
720 /**
721 * Returns an iterator that walks over all descendants in document order.
722 *
723 * @return an iterator to walk descendants
724 */
725 @Override
726 public IteratorIterable<Content> getDescendants() {
727 return new DescendantIterator(this);
728 }
729
730 /**
731 * Returns an iterator that walks over all descendants in document order
732 * applying the Filter to return only elements that match the filter rule.
733 * With filters you can match only Elements, only Comments, Elements or
734 * Comments, only Elements with a given name and/or prefix, and so on.
735 *
736 * @param filter filter to select which descendants to see
737 * Note that the {@link Filters} class has a number of predefined, useful
738 * filters.
739 * @return an iterator to walk descendants within a filter
740 */
741 @Override
742 public <F extends Content> IteratorIterable<F> getDescendants(final Filter<F> filter) {
743 return new FilterIterator<F>(new DescendantIterator(this), AbstractFilter.toFilter2(filter));
744 }
745
746 /**
747 * Always returns null, Document cannot have a parent.
748 * @return null
749 */
750 @Override
751 public Parent getParent() {
752 return null; // documents never have parents
753 }
754
755
756
757 /**
758 * Always returns this Document Instance
759 * @return 'this' because this Document is it's own Document
760 */
761 @Override
762 public Document getDocument() {
763 return this;
764 }
765
766 /**
767 * Assigns an arbitrary object to be associated with this document under
768 * the given "id" string. Null values are permitted. 'id' Strings beginning
769 * with "http://www.jdom.org/ are reserved for JDOM use. Properties set with
770 * this method will not be serialized with the rest of this Document, should
771 * serialization need to be done.
772 *
773 * @param id the id of the stored <code>Object</code>
774 * @param value the <code>Object</code> to store
775 */
776 public void setProperty(String id, Object value) {
777 if (propertyMap == null) {
778 propertyMap = new HashMap<String, Object>();
779 }
780 propertyMap.put(id, value);
781 }
782
783 /**
784 * Returns the object associated with this document under the given "id"
785 * string, or null if there is no binding or if the binding explicitly
786 * stored a null value.
787 *
788 * @param id the id of the stored <code>Object</code> to return
789 * @return the <code>Object</code> associated with the given id
790 */
791 public Object getProperty(String id) {
792 if (propertyMap == null) {
793 return null;
794 }
795 return propertyMap.get(id);
796 }
797
798 @Override
799 public void canContainContent(Content child, int index, boolean replace) {
800 if (child instanceof Element) {
801 int cre = content.indexOfFirstElement();
802 if (replace && cre == index) {
803 return;
804 }
805 if (cre >= 0) {
806 throw new IllegalAddException(
807 "Cannot add a second root element, only one is allowed");
808 }
809 if (content.indexOfDocType() >= index) {
810 throw new IllegalAddException(
811 "A root element cannot be added before the DocType");
812 }
813 }
814 if (child instanceof DocType) {
815 int cdt = content.indexOfDocType();
816 if (replace && cdt == index) {
817 // It's OK to replace an existing DocType
818 return;
819 }
820 if (cdt >= 0) {
821 throw new IllegalAddException(
822 "Cannot add a second doctype, only one is allowed");
823 }
824 int firstElt = content.indexOfFirstElement();
825 if (firstElt != -1 && firstElt < index) {
826 throw new IllegalAddException(
827 "A DocType cannot be added after the root element");
828 }
829 }
830
831 if (child instanceof CDATA) {
832 throw new IllegalAddException("A CDATA is not allowed at the document root");
833 }
834
835 if (child instanceof Text) {
836 if(Verifier.isAllXMLWhitespace(((Text) child).getText())) {
837 // only whitespace, not a problem.
838 return;
839 }
840 throw new IllegalAddException("A Text is not allowed at the document root");
841 }
842
843 if (child instanceof EntityRef) {
844 throw new IllegalAddException("An EntityRef is not allowed at the document root");
845 }
846
847 }
848
849 /**
850 * Get the Namespaces that are in-scope on this Document.
851 * <p>
852 * Document always has exactly two Namespaces in-scope:
853 * {@link Namespace#NO_NAMESPACE} and {@link Namespace#XML_NAMESPACE}.
854 * <p>
855 * These namespaces are always introduced by the Document, and thus they are
856 * both returned by {@link #getNamespacesIntroduced()}, and additionally
857 * {@link #getNamespacesInherited()} will always be empty.
858 * <p>
859 * <strong>Description copied from</strong>
860 * {@link NamespaceAware#getNamespacesInScope()}:
861 * <p>
862 * {@inheritDoc}
863 */
864 @Override
865 public List<Namespace> getNamespacesInScope() {
866 return Collections.unmodifiableList(Arrays.asList(
867 new Namespace[] {Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE}));
868 }
869
870 @Override
871 public List<Namespace> getNamespacesIntroduced() {
872 return Collections.unmodifiableList(Arrays.asList(
873 new Namespace[] {Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE}));
874 }
875
876 @Override
877 public List<Namespace> getNamespacesInherited() {
878 return Collections.emptyList();
879 }
880
881
882 /**
883 * JDOM2 Serialization. In this case, DocType is simple.
884 */
885 private static final long serialVersionUID = 200L;
886
887 /**
888 * Serialize out the Element.
889 *
890 * @serialData
891 * <strong>Document Properties are not serialized!</strong>
892 * <p>
893 * The Stream protocol is:
894 * <ol>
895 * <li>The BaseURI using default Serialization.
896 * <li>The count of child Content
897 * <li>The actual Child Content.
898 * </ol>
899 *
900 * @param out where to write the Element to.
901 * @throws IOException if there is a writing problem.
902 */
903 private void writeObject(final ObjectOutputStream out) throws IOException {
904 out.defaultWriteObject();
905 final int cs = content.size();
906 out.writeInt(cs);
907 for (int i = 0; i < cs; i++) {
908 out.writeObject(getContent(i));
909 }
910 }
911
912 /**
913 * Read an Element off the ObjectInputStream.
914 *
915 * @see #writeObject(ObjectOutputStream)
916 * @param in where to read the Element from.
917 * @throws IOException if there is a reading problem.
918 * @throws ClassNotFoundException when a class cannot be found
919 */
920 private void readObject(final ObjectInputStream in)
921 throws IOException, ClassNotFoundException {
922
923 in.defaultReadObject();
924
925 content = new ContentList(this);
926
927 int cs = in.readInt();
928 while (--cs >= 0) {
929 addContent((Content)in.readObject());
930 }
931
932 }
933
934 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import static org.jdom.JDOMConstants.NS_PREFIX_DEFAULT;
57 import static org.jdom.JDOMConstants.NS_PREFIX_XML;
58
59 import java.io.IOException;
60 import java.io.ObjectInputStream;
61 import java.io.ObjectOutputStream;
62 import java.net.URI;
63 import java.net.URISyntaxException;
64 import java.util.ArrayList;
65 import java.util.Collection;
66 import java.util.Collections;
67 import java.util.Comparator;
68 import java.util.HashMap;
69 import java.util.Iterator;
70 import java.util.List;
71 import java.util.TreeMap;
72
73 import org.jdom.ContentList.FilterList;
74 import org.jdom.filter.AbstractFilter;
75 import org.jdom.filter.ElementFilter;
76 import org.jdom.filter.Filter;
77 import org.jdom.output.XMLOutputter2;
78
79 /**
80 * An XML element. Methods allow the user to get and manipulate its child
81 * elements and content, directly access the element's textual content,
82 * manipulate its attributes, and manage namespaces.
83 * <p>
84 * See {@link NamespaceAware} and {@link #getNamespacesInScope()} for more
85 * details on what the Namespace scope is and how it is managed in JDOM and
86 * specifically by this Element class.
87 *
88 * @see NamespaceAware
89 * @see Content
90 *
91 * @author Brett McLaughlin
92 * @author Jason Hunter
93 * @author Lucas Gonze
94 * @author Kevin Regan
95 * @author Dan Schaffer
96 * @author Yusuf Goolamabbas
97 * @author Kent C. Johnson
98 * @author Jools Enticknap
99 * @author Alex Rosen
100 * @author Bradley S. Huffman
101 * @author Victor Toni
102 * @author Rolf Lear
103 *
104 */
105 public class Element extends Content implements Parent {
106
107 private static final int INITIAL_ARRAY_SIZE = 5;
108
109 /** The local name of the element */
110 protected String name;
111
112 /** The namespace of the element */
113 protected Namespace namespace;
114
115 /** Additional namespace declarations to store on this element; useful
116 * during output */
117 transient List<Namespace> additionalNamespaces = null;
118
119 /**
120 * The attributes of the element. Subclassers have to
121 * track attributes using their own mechanism.
122 */
123 transient AttributeList attributes = null; // = new AttributeList(this);
124
125 /**
126 * The content of the element. Subclassers have to
127 * track content using their own mechanism.
128 */
129 transient ContentList content = new ContentList(this);
130
131 /**
132 * This protected constructor is provided in order to support an Element
133 * subclass that wants full control over variable initialization. It
134 * intentionally leaves all instance variables null, allowing a lightweight
135 * subclass implementation. The subclass is responsible for ensuring all the
136 * get and set methods on Element behave as documented.
137 * <p>
138 * When implementing an Element subclass which doesn't require full control
139 * over variable initialization, be aware that simply calling super() (or
140 * letting the compiler add the implicit super() call) will not initialize
141 * the instance variables which will cause many of the methods to throw a
142 * NullPointerException. Therefore, the constructor for these subclasses
143 * should call one of the public constructors so variable initialization is
144 * handled automatically.
145 */
146 protected Element() {
147 super(CType.Element);
148 }
149
150 /**
151 * Creates a new element with the supplied (local) name and namespace. If
152 * the provided namespace is null, the element will have no namespace.
153 *
154 * @param name local name of the element
155 * @param namespace namespace for the element
156 * @throws IllegalNameException if the given name is illegal as an element
157 * name
158 */
159 public Element(final String name, final Namespace namespace) {
160 super(CType.Element);
161 setName(name);
162 setNamespace(namespace);
163 }
164
165 /**
166 * Create a new element with the supplied (local) name and no namespace.
167 *
168 * @param name local name of the element
169 * @throws IllegalNameException if the given name is illegal as an element
170 * name.
171 */
172 public Element(final String name) {
173 this(name, (Namespace) null);
174 }
175
176 /**
177 * Creates a new element with the supplied (local) name and a namespace
178 * given by a URI. The element will be put into the unprefixed (default)
179 * namespace.
180 *
181 * @param name name of the element
182 * @param uri namespace URI for the element
183 * @throws IllegalNameException if the given name is illegal as an element
184 * name or the given URI is illegal as a
185 * namespace URI
186 */
187 public Element(final String name, final String uri) {
188 this(name, Namespace.getNamespace(NS_PREFIX_DEFAULT, uri));
189 }
190
191 /**
192 * Creates a new element with the supplied (local) name and a namespace
193 * given by the supplied prefix and URI combination.
194 *
195 * @param name local name of the element
196 * @param prefix namespace prefix
197 * @param uri namespace URI for the element
198 * @throws IllegalNameException if the given name is illegal as an element
199 * name, the given prefix is illegal as a
200 * namespace prefix, or the given URI is
201 * illegal as a namespace URI
202 */
203 public Element(final String name, final String prefix, final String uri) {
204 this(name, Namespace.getNamespace(prefix, uri));
205 }
206
207 /**
208 * Returns the (local) name of the element (without any namespace prefix).
209 *
210 * @return local element name
211 */
212 public String getName() {
213 return name;
214 }
215
216 /**
217 * Sets the (local) name of the element.
218 *
219 * @param name the new (local) name of the element
220 * @return the target element
221 * @throws IllegalNameException if the given name is illegal as an Element
222 * name
223 */
224 public Element setName(final String name) {
225 final String reason = Verifier.checkElementName(name);
226 if (reason != null) {
227 throw new IllegalNameException(name, "element", reason);
228 }
229 this.name = name;
230 return this;
231 }
232
233 /**
234 * Returns the element's {@link Namespace}.
235 *
236 * @return the element's namespace
237 */
238 public Namespace getNamespace() {
239 return namespace;
240 }
241
242 /**
243 * Sets the element's {@link Namespace}. If the provided namespace is null,
244 * the element will have no namespace.
245 *
246 * @param namespace the new namespace. A null implies Namespace.NO_NAMESPACE.
247 * @return the target element
248 * @throws IllegalAddException if there is a Namespace conflict
249 */
250 public Element setNamespace(Namespace namespace) {
251 if (namespace == null) {
252 namespace = Namespace.NO_NAMESPACE;
253 }
254
255 if (additionalNamespaces != null) {
256 final String reason = Verifier.checkNamespaceCollision(namespace,
257 getAdditionalNamespaces());
258 if (reason != null) {
259 throw new IllegalAddException(this, namespace, reason);
260 }
261 }
262 if (hasAttributes()) {
263 for (Attribute a : getAttributes()) {
264 final String reason =
265 Verifier.checkNamespaceCollision(namespace, a);
266 if (reason != null) {
267 throw new IllegalAddException(this, namespace, reason);
268 }
269 }
270 }
271
272 this.namespace = namespace;
273 return this;
274 }
275
276 /**
277 * Returns the namespace prefix of the element or an empty string if none
278 * exists.
279 *
280 * @return the namespace prefix
281 */
282 public String getNamespacePrefix() {
283 return namespace.getPrefix();
284 }
285
286 /**
287 * Returns the namespace URI mapped to this element's prefix (or the
288 * in-scope default namespace URI if no prefix). If no mapping is found, an
289 * empty string is returned.
290 *
291 * @return the namespace URI for this element
292 */
293 public String getNamespaceURI() {
294 return namespace.getURI();
295 }
296
297 /**
298 * Returns the {@link Namespace} corresponding to the given prefix in scope
299 * for this element. This involves searching up the tree, so the results
300 * depend on the current location of the element. Returns null if there is
301 * no namespace in scope with the given prefix at this point in the
302 * document.
303 *
304 * @param prefix namespace prefix to look up
305 * @return the Namespace for this prefix at this
306 * location, or null if none
307 */
308 public Namespace getNamespace(final String prefix) {
309 if (prefix == null) {
310 return null;
311 }
312
313 if (NS_PREFIX_XML.equals(prefix)) {
314 // Namespace "xml" is always bound.
315 return Namespace.XML_NAMESPACE;
316 }
317
318 // Check if the prefix is the prefix for this element
319 if (prefix.equals(getNamespacePrefix())) {
320 return getNamespace();
321 }
322
323 // Scan the additional namespaces
324 if (additionalNamespaces != null) {
325 for (int i = 0; i < additionalNamespaces.size(); i++) {
326 final Namespace ns = additionalNamespaces.get(i);
327 if (prefix.equals(ns.getPrefix())) {
328 return ns;
329 }
330 }
331 }
332
333 if (attributes != null) {
334 for (final Attribute a : attributes) {
335 if (prefix.equals(a.getNamespacePrefix())) {
336 return a.getNamespace();
337 }
338 }
339 }
340
341 // If we still don't have a match, ask the parent
342 if (parent instanceof Element) {
343 return ((Element)parent).getNamespace(prefix);
344 }
345
346 return null;
347 }
348
349 /**
350 * Returns the full name of the element, in the form
351 * [namespacePrefix]:[localName]. If the element does not have a namespace
352 * prefix, then the local name is returned.
353 *
354 * @return qualified name of the element (including
355 * namespace prefix)
356 */
357 public String getQualifiedName() {
358 // Note: Any changes here should be reflected in
359 // XMLOutputter.printQualifiedName()
360 if ("".equals(namespace.getPrefix())) {
361 return getName();
362 }
363
364 return new StringBuilder(namespace.getPrefix())
365 .append(':')
366 .append(name)
367 .toString();
368 }
369
370 /**
371 * Adds a namespace declarations to this element. This should <i>not</i> be
372 * used to add the declaration for this element itself; that should be
373 * assigned in the construction of the element. Instead, this is for adding
374 * namespace declarations on the element not relating directly to itself.
375 * It's used during output to for stylistic reasons move namespace
376 * declarations higher in the tree than they would have to be.
377 *
378 * @param additionalNamespace namespace to add
379 * @return true if the namespace is added (false if it was previously added)
380 * @throws IllegalAddException if the namespace prefix collides with another
381 * namespace prefix on the element
382 */
383 public void addNamespaceDeclaration(final Namespace additionalNamespace) {
384
385 if (additionalNamespaces == null) {
386 additionalNamespaces = new ArrayList<Namespace>(INITIAL_ARRAY_SIZE);
387 }
388
389 for (Namespace ns : additionalNamespaces) {
390 if (ns == additionalNamespace) {
391 return;
392 }
393 }
394
395 // Verify the new namespace prefix doesn't collide with another
396 // declared namespace, an attribute prefix, or this element's prefix
397 final String reason = Verifier.checkNamespaceCollision(additionalNamespace, this);
398 if (reason != null) {
399 throw new IllegalAddException(this, additionalNamespace, reason);
400 }
401
402 additionalNamespaces.add(additionalNamespace);
403 }
404
405 /**
406 * Removes an additional namespace declarations from this element. This
407 * should <i>not</i> be used to remove the declaration for this element
408 * itself; that should be handled in the construction of the element.
409 * Instead, this is for removing namespace declarations on the element not
410 * relating directly to itself. If the declaration is not present, this
411 * method does nothing.
412 *
413 * @param additionalNamespace namespace to remove. A null Namespace does nothing.
414 */
415 public void removeNamespaceDeclaration(final Namespace additionalNamespace) {
416 if (additionalNamespaces == null) {
417 return;
418 }
419 additionalNamespaces.remove(additionalNamespace);
420 }
421
422 /**
423 * Returns a list of the additional namespace declarations on this element.
424 * This includes only additional namespace, not the namespace of the element
425 * itself, which can be obtained through {@link #getNamespace()}. If there
426 * are no additional declarations, this returns an empty list. Note, the
427 * returned list is unmodifiable.
428 *
429 * @return a List of the additional namespace
430 * declarations
431 */
432 public List<Namespace> getAdditionalNamespaces() {
433 // Not having the returned list be live allows us to avoid creating a
434 // new list object when XMLOutputter calls this method on an element
435 // with an empty list.
436 if (additionalNamespaces == null) {
437 return Collections.emptyList();
438 }
439 return Collections.unmodifiableList(additionalNamespaces);
440 }
441
442 /**
443 * Returns the XPath 1.0 string value of this element, which is the
444 * complete, ordered content of all text node descendants of this element
445 * (i&#46;e&#46; the text that's left after all references are resolved
446 * and all other markup is stripped out.)
447 *
448 * @return a concatentation of all text node descendants
449 */
450 @Override
451 public String getValue() {
452 final StringBuilder buffer = new StringBuilder();
453
454 for (Content child : getContent()) {
455 if (child instanceof Element || child instanceof Text) {
456 buffer.append(child.getValue());
457 }
458 }
459 return buffer.toString();
460 }
461
462 /**
463 * Returns whether this element is a root element. This can be used in
464 * tandem with {@link #getParent} to determine if an element has any
465 * "attachments" to a parent element or document.
466 * <p>
467 * An element is a root element when it has a parent and that parent is a
468 * Document. In particular, this means that detatched Elements are <b>not</b>
469 * root elements.
470 *
471 * @return whether this is a root element
472 */
473 public boolean isRootElement() {
474 return parent instanceof Document;
475 }
476
477 @Override
478 public int getContentSize() {
479 return content.size();
480 }
481
482 @Override
483 public int indexOf(final Content child) {
484 return content.indexOf(child);
485 }
486
487 // private int indexOf(int start, Filter filter) {
488 // int size = getContentSize();
489 // for (int i = start; i < size; i++) {
490 // if (filter.matches(getContent(i))) {
491 // return i;
492 // }
493 // }
494 // return -1;
495 // }
496
497
498 /**
499 * Returns the textual content directly held under this element as a string.
500 * This includes all text within this single element, including whitespace
501 * and CDATA sections if they exist. It's essentially the concatenation of
502 * all {@link Text} and {@link CDATA} nodes returned by {@link #getContent}.
503 * The call does not recurse into child elements. If no textual value exists
504 * for the element, an empty string is returned.
505 *
506 * @return text content for this element, or empty
507 * string if none
508 */
509 public String getText() {
510 if (content.size() == 0) {
511 return "";
512 }
513
514 // If we hold only a Text or CDATA, return it directly
515 if (content.size() == 1) {
516 final Object obj = content.get(0);
517 if (obj instanceof Text) {
518 return ((Text) obj).getText();
519 }
520 return "";
521 }
522
523 // Else build String up
524 final StringBuilder textContent = new StringBuilder();
525 boolean hasText = false;
526
527 for (int i = 0; i < content.size(); i++) {
528 final Object obj = content.get(i);
529 if (obj instanceof Text) {
530 textContent.append(((Text) obj).getText());
531 hasText = true;
532 }
533 }
534
535 if (!hasText) {
536 return "";
537 }
538 return textContent.toString();
539 }
540
541 /**
542 * Returns the textual content of this element with all surrounding
543 * whitespace removed. If no textual value exists for the element, or if
544 * only whitespace exists, the empty string is returned.
545 *
546 * @return trimmed text content for this element, or
547 * empty string if none
548 */
549 public String getTextTrim() {
550 return getText().trim();
551 }
552
553 /**
554 * Returns the textual content of this element with all surrounding
555 * whitespace removed and internal whitespace normalized to a single space.
556 * If no textual value exists for the element, or if only whitespace exists,
557 * the empty string is returned.
558 *
559 * @return normalized text content for this element, or
560 * empty string if none
561 */
562 public String getTextNormalize() {
563 return Text.normalizeString(getText());
564 }
565
566 /**
567 * Returns the textual content of the named child element, or null if
568 * there's no such child. This method is a convenience because calling
569 * <code>getChild().getText()</code> can throw a NullPointerException.
570 *
571 * @param cname the name of the child
572 * @return text content for the named child, or null if
573 * no such child
574 */
575 public String getChildText(final String cname) {
576 final Element child = getChild(cname);
577 if (child == null) {
578 return null;
579 }
580 return child.getText();
581 }
582
583 /**
584 * Returns the trimmed textual content of the named child element, or null
585 * if there's no such child. See <code>{@link #getTextTrim()}</code> for
586 * details of text trimming.
587 *
588 * @param cname the name of the child
589 * @return trimmed text content for the named child, or
590 * null if no such child
591 */
592 public String getChildTextTrim(final String cname) {
593 final Element child = getChild(cname);
594 if (child == null) {
595 return null;
596 }
597 return child.getTextTrim();
598 }
599
600 /**
601 * Returns the normalized textual content of the named child element, or
602 * null if there's no such child. See <code>{@link
603 * #getTextNormalize()}</code> for details of text normalizing.
604 *
605 * @param cname the name of the child
606 * @return normalized text content for the named child,
607 * or null if no such child
608 */
609 public String getChildTextNormalize(final String cname) {
610 final Element child = getChild(cname);
611 if (child == null) {
612 return null;
613 }
614 return child.getTextNormalize();
615 }
616
617 /**
618 * Returns the textual content of the named child element, or null if
619 * there's no such child.
620 *
621 * @param cname
622 * the name of the child
623 * @param ns
624 * the namespace of the child. A null implies Namespace.NO_NAMESPACE.
625 * @return text content for the named child, or null if no such child
626 */
627 public String getChildText(final String cname, final Namespace ns) {
628 final Element child = getChild(cname, ns);
629 if (child == null) {
630 return null;
631 }
632 return child.getText();
633 }
634
635 /**
636 * Returns the trimmed textual content of the named child element, or null
637 * if there's no such child.
638 *
639 * @param cname
640 * the name of the child
641 * @param ns
642 * the namespace of the child. A null implies Namespace.NO_NAMESPACE.
643 * @return trimmed text content for the named child, or null if no such
644 * child
645 */
646 public String getChildTextTrim(final String cname, final Namespace ns) {
647 final Element child = getChild(cname, ns);
648 if (child == null) {
649 return null;
650 }
651 return child.getTextTrim();
652 }
653
654 /**
655 * Returns the normalized textual content of the named child element, or
656 * null if there's no such child.
657 *
658 * @param cname
659 * the name of the child
660 * @param ns
661 * the namespace of the child. A null implies Namespace.NO_NAMESPACE.
662 * @return normalized text content for the named child, or null if no such
663 * child
664 */
665 public String getChildTextNormalize(final String cname, final Namespace ns) {
666 final Element child = getChild(cname, ns);
667 if (child == null) {
668 return null;
669 }
670 return child.getTextNormalize();
671 }
672
673 /**
674 * Sets the content of the element to be the text given. All existing text
675 * content and non-text context is removed. If this element should have both
676 * textual content and nested elements, use <code>{@link #setContent}</code>
677 * instead. Setting a null text value is equivalent to setting an empty
678 * string value.
679 *
680 * @param text new text content for the element
681 * @return the target element
682 * @throws IllegalDataException if the assigned text contains an illegal
683 * character such as a vertical tab (as
684 * determined by {@link
685 * org.jdom.Verifier#checkCharacterData})
686 */
687 public Element setText(final String text) {
688 content.clear();
689
690 if (text != null) {
691 addContent(new Text(text));
692 }
693
694 return this;
695 }
696
697 /**
698 * Adjacent Text content is merged into the first Text in document order,
699 * and the redundant Text items are removed (including any empty Text).
700 *
701 * @param recursively
702 * true if you want the text of child elements coalesced too. False
703 * if you only want to coalesce this Element's Text.
704 * @return true if any content was changed by this operation.
705 */
706 public boolean coalesceText(boolean recursively) {
707 final Iterator<Content> it = recursively ? getDescendants()
708 : content.iterator();
709 Text tfirst = null;
710 boolean changed = false;
711 while (it.hasNext()) {
712 final Content c = it.next();
713 if (c.getCType() == CType.Text) {
714 // Text, and no CDATA!
715 final Text text = (Text)c;
716 if ("".equals(text.getValue())) {
717 it.remove();
718 changed = true;
719 } else if (tfirst == null ||
720 tfirst.getParent() != text.getParent()) {
721 // previous item in the iterator was not text, or
722 // we are the next Text item after coming up the tree.
723 tfirst = text;
724 } else {
725 // add our text to the first in the sequence
726 tfirst.append(text.getValue());
727 // remove us from the sequence
728 it.remove();
729 changed = true;
730 }
731 } else {
732 // the end of the sequence
733 tfirst = null;
734 }
735 }
736 return changed;
737 }
738
739 /**
740 * This returns the full content of the element as a List which
741 * may contain objects of type <code>Text</code>, <code>Element</code>,
742 * <code>Comment</code>, <code>ProcessingInstruction</code>,
743 * <code>CDATA</code>, and <code>EntityRef</code>.
744 * The List returned is "live" in document order and modifications
745 * to it affect the element's actual contents. Whitespace content is
746 * returned in its entirety.
747 *
748 * <p>
749 * Sequential traversal through the List is best done with an Iterator
750 * since the underlying implement of List.size() may require walking the
751 * entire list.
752 * </p>
753 *
754 * @return a <code>List</code> containing the mixed content of the
755 * element: may contain <code>Text</code>,
756 * <code>{@link Element}</code>, <code>{@link Comment}</code>,
757 * <code>{@link ProcessingInstruction}</code>,
758 * <code>{@link CDATA}</code>, and
759 * <code>{@link EntityRef}</code> objects.
760 */
761 @Override
762 public List<Content> getContent() {
763 return content;
764 }
765
766 /**
767 * Return a filter view of this <code>Element</code>'s content.
768 *
769 * <p>
770 * Sequential traversal through the List is best done with a Iterator
771 * since the underlying implement of List.size() may require walking the
772 * entire list.
773 * </p>
774 *
775 * @param filter <code>Filter</code> to apply
776 * Note that the {@link Filters} class has a number of predefined, useful
777 * filters.
778 * @return <code>List</code> - filtered Element content
779 */
780 @Override
781 public <E extends Content> List<E> getContent(final Filter<E> filter) {
782 return content.getView(filter);
783 }
784
785 /**
786 * Removes all child content from this parent.
787 *
788 * @return list of the old children detached from this parent
789 */
790 @Override
791 public List<Content> removeContent() {
792 final List<Content> old = new ArrayList<Content>(content);
793 content.clear();
794 return old;
795 }
796
797 /**
798 * Remove all child content from this parent matching the supplied filter.
799 *
800 * @param filter filter to select which content to remove
801 * Note that the {@link Filters} class has a number of predefined, useful
802 * filters.
803 * @return list of the old children detached from this parent
804 */
805 @Override
806 public <F extends Content> List<F> removeContent(final Filter<F> filter) {
807 final List<F> old = new ArrayList<F>();
808 final Iterator<F> iter = content.getView(filter).iterator();
809 while (iter.hasNext()) {
810 final F child = iter.next();
811 old.add(child);
812 iter.remove();
813 }
814 return old;
815 }
816
817 /**
818 * This sets the content of the element. The supplied List should
819 * contain only objects of type <code>Element</code>, <code>Text</code>,
820 * <code>CDATA</code>, <code>Comment</code>,
821 * <code>ProcessingInstruction</code>, and <code>EntityRef</code>.
822 *
823 * <p>
824 * When all objects in the supplied List are legal and before the new
825 * content is added, all objects in the old content will have their
826 * parentage set to null (no parent) and the old content list will be
827 * cleared. This has the effect that any active list (previously obtained
828 * with a call to {@link #getContent} or {@link #getChildren}) will also
829 * change to reflect the new content. In addition, all objects in the
830 * supplied List will have their parentage set to this element, but the
831 * List itself will not be "live" and further removals and additions will
832 * have no effect on this elements content. If the user wants to continue
833 * working with a "live" list, then a call to setContent should be
834 * followed by a call to {@link #getContent} or {@link #getChildren} to
835 * obtain a "live" version of the content.
836 * </p>
837 *
838 * <p>
839 * Passing a null or empty List clears the existing content.
840 * </p>
841 *
842 * <p>
843 * In event of an exception the original content will be unchanged and
844 * the objects in the supplied content will be unaltered.
845 * </p>
846 *
847 * @param newContent <code>Collection</code> of content to set
848 * @return this element modified
849 * @throws IllegalAddException if the List contains objects of
850 * illegal types or with existing parentage.
851 */
852 public Element setContent(final Collection<? extends Content> newContent) {
853 content.clearAndSet(newContent);
854 return this;
855 }
856
857 /**
858 * Replace the current child the given index with the supplied child.
859 * <p>
860 * In event of an exception the original content will be unchanged and
861 * the supplied child will be unaltered.
862 * </p>
863 *
864 * @param index - index of child to replace.
865 * @param child - child to add.
866 * @return element on which this method was invoked
867 * @throws IllegalAddException if the supplied child is already attached
868 * or not legal content for this parent.
869 * @throws IndexOutOfBoundsException if index is negative or greater
870 * than the current number of children.
871 */
872 public Element setContent(final int index, final Content child) {
873 content.set(index, child);
874 return this;
875 }
876
877 /**
878 * Replace the child at the given index whith the supplied
879 * collection.
880 * <p>
881 * In event of an exception the original content will be unchanged and
882 * the content in the supplied collection will be unaltered.
883 * </p>
884 *
885 * @param index - index of child to replace.
886 * @param newContent - <code>Collection</code> of content to replace child.
887 * @return object on which this method was invoked
888 * @throws IllegalAddException if the collection contains objects of
889 * illegal types.
890 * @throws IndexOutOfBoundsException if index is negative or greater
891 * than the current number of children.
892 */
893 public Parent setContent(final int index, final Collection<? extends Content> newContent) {
894 content.remove(index);
895 content.addAll(index, newContent);
896 return this;
897 }
898
899 /**
900 * This adds text content to this element. It does not replace the
901 * existing content as does <code>setText()</code>.
902 *
903 * @param str <code>String</code> to add
904 * @return this element modified
905 * @throws IllegalDataException if <code>str</code> contains an
906 * illegal character such as a vertical tab (as determined
907 * by {@link org.jdom.Verifier#checkCharacterData})
908 */
909 public Element addContent(final String str) {
910 return addContent(new Text(str));
911 }
912
913 /**
914 * Appends the child to the end of the element's content list.
915 *
916 * @param child child to append to end of content list
917 * @return the element on which the method was called
918 * @throws IllegalAddException if the given child already has a parent. */
919 @Override
920 public Element addContent(final Content child) {
921 content.add(child);
922 return this;
923 }
924
925 /**
926 * The same as {@link #addContent(Content)}, added to keep binary compatibility.
927 */
928 public Element addContent(Element child) {
929 content.add(child);
930 return this;
931 }
932
933
934 /**
935 * Appends all children in the given collection to the end of
936 * the content list. In event of an exception during add the
937 * original content will be unchanged and the objects in the supplied
938 * collection will be unaltered.
939 *
940 * @param newContent <code>Collection</code> of content to append
941 * @return the element on which the method was called
942 * @throws IllegalAddException if any item in the collection
943 * already has a parent or is of an inappropriate type.
944 */
945 @Override
946 public Element addContent(final Collection<? extends Content> newContent) {
947 content.addAll(newContent);
948 return this;
949 }
950
951 /**
952 * Inserts the child into the content list at the given index.
953 *
954 * @param index location for adding the collection
955 * @param child child to insert
956 * @return the parent on which the method was called
957 * @throws IndexOutOfBoundsException if index is negative or beyond
958 * the current number of children
959 * @throws IllegalAddException if the given child already has a parent.
960 */
961 @Override
962 public Element addContent(final int index, final Content child) {
963 content.add(index, child);
964 return this;
965 }
966
967 /**
968 * Inserts the content in a collection into the content list
969 * at the given index. In event of an exception the original content
970 * will be unchanged and the objects in the supplied collection will be
971 * unaltered.
972 *
973 * @param index location for adding the collection
974 * @param newContent <code>Collection</code> of content to insert
975 * @return the parent on which the method was called
976 * @throws IndexOutOfBoundsException if index is negative or beyond
977 * the current number of children
978 * @throws IllegalAddException if any item in the collection
979 * already has a parent or is of an inappropriate type.
980 */
981 @Override
982 public Element addContent(final int index, final Collection<? extends Content> newContent) {
983 content.addAll(index, newContent);
984 return this;
985 }
986
987 @Override
988 public List<Content> cloneContent() {
989 final int size = getContentSize();
990 final List<Content> list = new ArrayList<Content>(size);
991 for (int i = 0; i < size; i++) {
992 final Content child = getContent(i);
993 list.add(child.clone());
994 }
995 return list;
996 }
997
998 @Override
999 public Content getContent(final int index) {
1000 return content.get(index);
1001 }
1002
1003 // public Content getChild(Filter filter) {
1004 // int i = indexOf(0, filter);
1005 // return (i < 0) ? null : getContent(i);
1006 // }
1007
1008 @Override
1009 public boolean removeContent(final Content child) {
1010 return content.remove(child);
1011 }
1012
1013 @Override
1014 public Content removeContent(final int index) {
1015 return content.remove(index);
1016 }
1017
1018 /**
1019 * Set this element's content to be the supplied child.
1020 * <p>
1021 * If the supplied child is legal content for this parent and before
1022 * it is added, all content in the current content list will
1023 * be cleared and all current children will have their parentage set to
1024 * null.
1025 * <p>
1026 * This has the effect that any active list (previously obtained with
1027 * a call to one of the {@link #getContent} methods will also change
1028 * to reflect the new content. In addition, all content in the supplied
1029 * collection will have their parentage set to this parent. If the user
1030 * wants to continue working with a <b>"live"</b> list of this parent's
1031 * child, then a call to setContent should be followed by a call to one
1032 * of the {@link #getContent} methods to obtain a <b>"live"</b>
1033 * version of the children.
1034 * <p>
1035 * Passing a null child clears the existing content.
1036 * <p>
1037 * In event of an exception the original content will be unchanged and
1038 * the supplied child will be unaltered.
1039 *
1040 * @param child new content to replace existing content
1041 * @return the parent on which the method was called
1042 * @throws IllegalAddException if the supplied child is already attached
1043 * or not legal content for an Element
1044 */
1045 public Element setContent(final Content child) {
1046 content.clear();
1047 content.add(child);
1048 return this;
1049 }
1050
1051
1052 /**
1053 * Determines if this element is the ancestor of another element.
1054 *
1055 * @param element <code>Element</code> to check against
1056 * @return <code>true</code> if this element is the ancestor of the
1057 * supplied element
1058 */
1059 public boolean isAncestor(final Element element) {
1060 Parent p = element.getParent();
1061 while (p instanceof Element) {
1062 if (p == this) {
1063 return true;
1064 }
1065 p = p.getParent();
1066 }
1067 return false;
1068 }
1069
1070 /**
1071 * Indicate whether this Element has any attributes.
1072 * Where possible you should call this method before calling getAttributes()
1073 * because calling getAttributes() will create the necessary Attribute List
1074 * memory structures, even if there are no Attributes attached to the
1075 * Element. Calling hasAttributes() first can save memory.
1076 * @return true if this Element has attributes.
1077 */
1078 public boolean hasAttributes() {
1079 return attributes != null && !attributes.isEmpty();
1080 }
1081
1082 /**
1083 * Indicate whether this Element has any additional Namespace declarations.
1084 * Where possible you should call this method before calling
1085 * {@link #getAdditionalNamespaces()} because calling getAttributes() will
1086 * create an unnecessary List even if there are no Additional Namespaces
1087 * attached to the Element. Calling this method first can save memory and
1088 * time.
1089 * @return true if this Element has additional Namespaces.
1090 */
1091 public boolean hasAdditionalNamespaces() {
1092 return additionalNamespaces != null && !additionalNamespaces.isEmpty();
1093 }
1094
1095 /**
1096 * Lazy initialiser for the Attribute list.
1097 * @return this Element's Attribute List (creating it if necessary).
1098 */
1099 AttributeList getAttributeList() {
1100 if (attributes == null) {
1101 attributes = new AttributeList(this);
1102 }
1103 return attributes;
1104 }
1105
1106 /**
1107 * <p>
1108 * This returns the complete set of attributes for this element, as a
1109 * <code>List</code> of <code>Attribute</code> objects in no particular
1110 * order, or an empty list if there are none.
1111 * The returned list is "live" and changes to it affect the
1112 * element's actual attributes.
1113 * </p>
1114 *
1115 * @return attributes for the element
1116 */
1117 public List<Attribute> getAttributes() {
1118 return getAttributeList();
1119 }
1120
1121 /**
1122 * <p>
1123 * This returns the attribute for this element with the given name
1124 * and within no namespace, or null if no such attribute exists.
1125 * </p>
1126 *
1127 * @param attname name of the attribute to return
1128 * @return attribute for the element
1129 */
1130 public Attribute getAttribute(final String attname) {
1131 return getAttribute(attname, Namespace.NO_NAMESPACE);
1132 }
1133
1134 /**
1135 * <p>
1136 * This returns the attribute for this element with the given name
1137 * and within the given Namespace, or null if no such attribute exists.
1138 * </p>
1139 *
1140 * @param attname name of the attribute to return
1141 * @param ns <code>Namespace</code> to search within. A null implies Namespace.NO_NAMESPACE.
1142 * @return attribute for the element
1143 */
1144 public Attribute getAttribute(final String attname, final Namespace ns) {
1145 if (attributes == null) {
1146 return null;
1147 }
1148 return getAttributeList().get(attname, ns);
1149 }
1150
1151 /**
1152 * <p>
1153 * This returns the attribute value for the attribute with the given name
1154 * and within no namespace, null if there is no such attribute, and the
1155 * empty string if the attribute value is empty.
1156 * </p>
1157 *
1158 * @param attname name of the attribute whose value to be returned
1159 * @return the named attribute's value, or null if no such attribute
1160 */
1161 public String getAttributeValue(final String attname) {
1162 if (attributes == null) {
1163 return null;
1164 }
1165 return getAttributeValue(attname, Namespace.NO_NAMESPACE);
1166 }
1167
1168 /**
1169 * <p>
1170 * This returns the attribute value for the attribute with the given name
1171 * and within no namespace, or the passed-in default if there is no
1172 * such attribute.
1173 * </p>
1174 *
1175 * @param attname name of the attribute whose value to be returned
1176 * @param def a default value to return if the attribute does not exist
1177 * @return the named attribute's value, or the default if no such attribute
1178 */
1179 public String getAttributeValue(final String attname, final String def) {
1180 if (attributes == null) {
1181 return def;
1182 }
1183 return getAttributeValue(attname, Namespace.NO_NAMESPACE, def);
1184 }
1185
1186 /**
1187 * <p>
1188 * This returns the attribute value for the attribute with the given name
1189 * and within the given Namespace, null if there is no such attribute, and
1190 * the empty string if the attribute value is empty.
1191 * </p>
1192 *
1193 * @param attname name of the attribute whose valud is to be returned
1194 * @param ns <code>Namespace</code> to search within. A null implies Namespace.NO_NAMESPACE.
1195 * @return the named attribute's value, or null if no such attribute
1196 */
1197 public String getAttributeValue(final String attname, final Namespace ns) {
1198 if (attributes == null) {
1199 return null;
1200 }
1201 return getAttributeValue(attname, ns, null);
1202 }
1203
1204 /**
1205 * <p>
1206 * This returns the attribute value for the attribute with the given name
1207 * and within the given Namespace, or the passed-in default if there is no
1208 * such attribute.
1209 * </p>
1210 *
1211 * @param attname name of the attribute whose valud is to be returned
1212 * @param ns <code>Namespace</code> to search within. A null implies Namespace.NO_NAMESPACE.
1213 * @param def a default value to return if the attribute does not exist
1214 * @return the named attribute's value, or the default if no such attribute
1215 */
1216 public String getAttributeValue(final String attname, final Namespace ns, final String def) {
1217 if (attributes == null) {
1218 return def;
1219 }
1220 final Attribute attribute = getAttributeList().get(attname, ns);
1221 if (attribute == null) {
1222 return def;
1223 }
1224
1225 return attribute.getValue();
1226 }
1227
1228 /**
1229 * <p>
1230 * This sets the attributes of the element. The supplied Collection should
1231 * contain only objects of type <code>Attribute</code>.
1232 * </p>
1233 *
1234 * <p>
1235 * When all objects in the supplied List are legal and before the new
1236 * attributes are added, all old attributes will have their
1237 * parentage set to null (no parent) and the old attribute list will be
1238 * cleared. This has the effect that any active attribute list (previously
1239 * obtained with a call to {@link #getAttributes}) will also change to
1240 * reflect the new attributes. In addition, all attributes in the supplied
1241 * List will have their parentage set to this element, but the List itself
1242 * will not be "live" and further removals and additions will have no
1243 * effect on this elements attributes. If the user wants to continue
1244 * working with a "live" attribute list, then a call to setAttributes
1245 * should be followed by a call to {@link #getAttributes} to obtain a
1246 * "live" version of the attributes.
1247 * </p>
1248 *
1249 * <p>
1250 * Passing a null or empty List clears the existing attributes.
1251 * </p>
1252 *
1253 * <p>
1254 * In cases where the List contains duplicate attributes, only the last
1255 * one will be retained. This has the same effect as calling
1256 * {@link #setAttribute(Attribute)} sequentially.
1257 * </p>
1258 *
1259 * <p>
1260 * In event of an exception the original attributes will be unchanged and
1261 * the attributes in the supplied attributes will be unaltered.
1262 * </p>
1263 *
1264 * @param newAttributes <code>Collection</code> of attributes to set
1265 * @return this element modified
1266 * @throws IllegalAddException if the List contains objects
1267 * that are not instances of <code>Attribute</code>,
1268 * or if any of the <code>Attribute</code> objects have
1269 * conflicting namespace prefixes.
1270 */
1271 public Element setAttributes(final Collection<? extends Attribute> newAttributes) {
1272 getAttributeList().clearAndSet(newAttributes);
1273 return this;
1274 }
1275
1276 /**
1277 * The same as {@link #setAttributes(Collection)}, added to keep binary compatibility.
1278 */
1279 public Element setAttributes(final List<? extends Attribute> newAttributes) {
1280 return setAttributes((Collection<? extends Attribute>) newAttributes);
1281 }
1282
1283 /**
1284 * <p>
1285 * This sets an attribute value for this element. Any existing attribute
1286 * with the same name and namespace URI is removed.
1287 * </p>
1288 *
1289 * @param name name of the attribute to set
1290 * @param value value of the attribute to set
1291 * @return this element modified
1292 * @throws IllegalNameException if the given name is illegal as an
1293 * attribute name.
1294 * @throws IllegalDataException if the given attribute value is
1295 * illegal character data (as determined by
1296 * {@link org.jdom.Verifier#checkCharacterData}).
1297 */
1298 public Element setAttribute(final String name, final String value) {
1299 final Attribute attribute = getAttribute(name);
1300 if (attribute == null) {
1301 final Attribute newAttribute = new Attribute(name, value);
1302 setAttribute(newAttribute);
1303 } else {
1304 attribute.setValue(value);
1305 }
1306
1307 return this;
1308 }
1309
1310 /**
1311 * <p>
1312 * This sets an attribute value for this element. Any existing attribute
1313 * with the same name and namespace URI is removed.
1314 * </p>
1315 *
1316 * @param name name of the attribute to set
1317 * @param value value of the attribute to set
1318 * @param ns namespace of the attribute to set. A null implies Namespace.NO_NAMESPACE.
1319 * @return this element modified
1320 * @throws IllegalNameException if the given name is illegal as an
1321 * attribute name, or if the namespace is an unprefixed default
1322 * namespace
1323 * @throws IllegalDataException if the given attribute value is
1324 * illegal character data (as determined by
1325 * {@link org.jdom.Verifier#checkCharacterData}).
1326 * @throws IllegalAddException if the attribute namespace prefix
1327 * collides with another namespace prefix on the element.
1328 */
1329 public Element setAttribute(final String name, final String value, final Namespace ns) {
1330 final Attribute attribute = getAttribute(name, ns);
1331 if (attribute == null) {
1332 final Attribute newAttribute = new Attribute(name, value, ns);
1333 setAttribute(newAttribute);
1334 } else {
1335 attribute.setValue(value);
1336 }
1337
1338 return this;
1339 }
1340
1341 /**
1342 * <p>
1343 * This sets an attribute value for this element. Any existing attribute
1344 * with the same name and namespace URI is removed.
1345 * </p>
1346 *
1347 * @param attribute <code>Attribute</code> to set
1348 * @return this element modified
1349 * @throws IllegalAddException if the attribute being added already has a
1350 * parent or if the attribute namespace prefix collides with another
1351 * namespace prefix on the element.
1352 */
1353 public Element setAttribute(final Attribute attribute) {
1354 getAttributeList().add(attribute);
1355 return this;
1356 }
1357
1358 /**
1359 * <p>
1360 * This removes the attribute with the given name and within no
1361 * namespace. If no such attribute exists, this method does nothing.
1362 * </p>
1363 *
1364 * @param attname name of attribute to remove
1365 * @return whether the attribute was removed
1366 */
1367 public boolean removeAttribute(final String attname) {
1368 return removeAttribute(attname, Namespace.NO_NAMESPACE);
1369 }
1370
1371 /**
1372 * <p>
1373 * This removes the attribute with the given name and within the
1374 * given Namespace. If no such attribute exists, this method does
1375 * nothing.
1376 * </p>
1377 *
1378 * @param attname name of attribute to remove
1379 * @param ns namespace URI of attribute to remove. A null implies Namespace.NO_NAMESPACE.
1380 * @return whether the attribute was removed
1381 */
1382 public boolean removeAttribute(final String attname, final Namespace ns) {
1383 if (attributes == null) {
1384 return false;
1385 }
1386 return getAttributeList().remove(attname, ns);
1387 }
1388
1389 /**
1390 * <p>
1391 * This removes the supplied Attribute should it exist.
1392 * </p>
1393 *
1394 * @param attribute Reference to the attribute to be removed.
1395 * @return whether the attribute was removed
1396 */
1397 public boolean removeAttribute(final Attribute attribute) {
1398 if (attributes == null) {
1399 return false;
1400 }
1401 return getAttributeList().remove(attribute);
1402 }
1403
1404 /**
1405 * <p>
1406 * This returns a <code>String</code> representation of the
1407 * <code>Element</code>, suitable for debugging. If the XML
1408 * representation of the <code>Element</code> is desired,
1409 * {@link XMLOutputter2#outputString(Element)}
1410 * should be used.
1411 * </p>
1412 *
1413 * @return <code>String</code> - information about the
1414 * <code>Element</code>
1415 */
1416 @Override
1417 public String toString() {
1418 final StringBuilder stringForm = new StringBuilder(64)
1419 .append("[Element: <")
1420 .append(getQualifiedName());
1421
1422 final String nsuri = getNamespaceURI();
1423 if (!"".equals(nsuri)) {
1424 stringForm
1425 .append(" [Namespace: ")
1426 .append(nsuri)
1427 .append("]");
1428 }
1429 stringForm.append("/>]");
1430
1431 return stringForm.toString();
1432 }
1433
1434 /**
1435 * <p>
1436 * This returns a deep clone of this element.
1437 * The new element is detached from its parent, and getParent()
1438 * on the clone will return null.
1439 * </p>
1440 *
1441 * @return the clone of this element
1442 */
1443 @Override
1444 public Element clone() {
1445
1446 // Ken Rune Helland <kenh@csc.no> is our local clone() guru
1447
1448 final Element element = (Element) super.clone();
1449
1450 // name and namespace are references to immutable objects
1451 // so super.clone() handles them ok
1452
1453 // Reference to parent is copied by super.clone()
1454 // (Object.clone()) so we have to remove it
1455 // Actually, super is a Content, which has already detached in the
1456 // clone().
1457 // element.parent = null;
1458
1459 // Reference to content list and attribute lists are copyed by
1460 // super.clone() so we set it new lists if the original had lists
1461 element.content = new ContentList(element);
1462 element.attributes = attributes == null ? null : new AttributeList(element);
1463
1464 // Cloning attributes
1465 if (attributes != null) {
1466 for(int i = 0; i < attributes.size(); i++) {
1467 final Attribute attribute = attributes.get(i);
1468 element.attributes.add(attribute.clone());
1469 }
1470 }
1471
1472 // Cloning additional namespaces
1473 if (additionalNamespaces != null) {
1474 element.additionalNamespaces = new ArrayList<Namespace>(additionalNamespaces);
1475 }
1476
1477 // Cloning content
1478 for(int i = 0; i < content.size(); i++) {
1479 final Content c = content.get(i);
1480 element.content.add(c.clone());
1481 }
1482
1483 return element;
1484 }
1485
1486
1487 /**
1488 * Returns an iterator that walks over all descendants in document order.
1489 *
1490 * @return an iterator to walk descendants
1491 */
1492 @Override
1493 public Iterator<Content> getDescendants() {
1494 return new DescendantIterator(this);
1495 }
1496
1497 /**
1498 * Returns an iterator that walks over all descendants in document order
1499 * applying the Filter to return only content that match the filter rule.
1500 * With filters you can match only Elements, only Comments, Elements or
1501 * Comments, only Elements with a given name and/or prefix, and so on.
1502 *
1503 * @param filter filter to select which descendants to see
1504 * Note that the {@link Filters} class has a number of predefined, useful
1505 * filters.
1506 * @return an iterator to walk descendants within a filter
1507 */
1508 @Override
1509 public <F extends Content> Iterator<F> getDescendants(final Filter<F> filter) {
1510 return new FilterIterator<F>(new DescendantIterator(this), AbstractFilter.toFilter2(filter));
1511 }
1512
1513
1514
1515 /**
1516 * This returns a <code>List</code> of all the child elements
1517 * nested directly (one level deep) within this element, as
1518 * <code>Element</code> objects. If this target element has no nested
1519 * elements, an empty List is returned. The returned list is "live"
1520 * in document order and changes to it affect the element's actual
1521 * contents.
1522 *
1523 * <p>
1524 * Sequential traversal through the List is best done with a Iterator
1525 * since the underlying implement of List.size() may not be the most
1526 * efficient.
1527 * </p>
1528 *
1529 * <p>
1530 * No recursion is performed, so elements nested two levels deep
1531 * would have to be obtained with:
1532 * <pre>
1533 * <code>
1534 * for(Element oneLevelDeep : topElement.getChildren()) {
1535 * List&lt;Element&gt; twoLevelsDeep = oneLevelDeep.getChildren();
1536 * // Do something with these children
1537 * }
1538 * </code>
1539 * </pre>
1540 * </p>
1541 *
1542 * @return list of child <code>Element</code> objects for this element
1543 */
1544 public List<Element> getChildren() {
1545 return content.getView(new ElementFilter());
1546 }
1547
1548 /**
1549 * This returns a <code>List</code> of all the child elements
1550 * nested directly (one level deep) within this element with the given
1551 * local name and belonging to no namespace, returned as
1552 * <code>Element</code> objects. If this target element has no nested
1553 * elements with the given name outside a namespace, an empty List
1554 * is returned. The returned list is "live" in document order
1555 * and changes to it affect the element's actual contents.
1556 * <p>
1557 * Please see the notes for <code>{@link #getChildren}</code>
1558 * for a code example.
1559 * </p>
1560 *
1561 * @param cname local name for the children to match
1562 * @return all matching child elements
1563 */
1564 public List<Element> getChildren(final String cname) {
1565 return getChildren(cname, Namespace.NO_NAMESPACE);
1566 }
1567
1568 /**
1569 * This returns a <code>List</code> of all the child elements
1570 * nested directly (one level deep) within this element with the given
1571 * local name and belonging to the given Namespace, returned as
1572 * <code>Element</code> objects. If this target element has no nested
1573 * elements with the given name in the given Namespace, an empty List
1574 * is returned. The returned list is "live" in document order
1575 * and changes to it affect the element's actual contents.
1576 * <p>
1577 * Please see the notes for <code>{@link #getChildren}</code>
1578 * for a code example.
1579 * </p>
1580 *
1581 * @param cname local name for the children to match
1582 * @param ns <code>Namespace</code> to search within. A null implies Namespace.NO_NAMESPACE.
1583 * @return all matching child elements
1584 */
1585 public List<Element> getChildren(final String cname, final Namespace ns) {
1586 return content.getView(new ElementFilter(cname, ns));
1587 }
1588
1589 /**
1590 * This returns the first child element within this element with the
1591 * given local name and belonging to the given namespace.
1592 * If no elements exist for the specified name and namespace, null is
1593 * returned.
1594 *
1595 * @param cname local name of child element to match
1596 * @param ns <code>Namespace</code> to search within. A null implies Namespace.NO_NAMESPACE.
1597 * @return the first matching child element, or null if not found
1598 */
1599 public Element getChild(final String cname, final Namespace ns) {
1600 final List<Element> elements = content.getView(new ElementFilter(cname, ns));
1601 final Iterator<Element> iter = elements.iterator();
1602 if (iter.hasNext()) {
1603 return iter.next();
1604 }
1605 return null;
1606 }
1607
1608 /**
1609 * This returns the first child element within this element with the
1610 * given local name and belonging to no namespace.
1611 * If no elements exist for the specified name and namespace, null is
1612 * returned.
1613 *
1614 * @param cname local name of child element to match
1615 * @return the first matching child element, or null if not found
1616 */
1617 public Element getChild(final String cname) {
1618 return getChild(cname, Namespace.NO_NAMESPACE);
1619 }
1620
1621 /**
1622 * <p>
1623 * This removes the first child element (one level deep) with the
1624 * given local name and belonging to no namespace.
1625 * Returns true if a child was removed.
1626 * </p>
1627 *
1628 * @param cname the name of child elements to remove
1629 * @return whether deletion occurred
1630 */
1631 public boolean removeChild(final String cname) {
1632 return removeChild(cname, Namespace.NO_NAMESPACE);
1633 }
1634
1635 /**
1636 * <p>
1637 * This removes the first child element (one level deep) with the
1638 * given local name and belonging to the given namespace.
1639 * Returns true if a child was removed.
1640 * </p>
1641 *
1642 * @param cname the name of child element to remove
1643 * @param ns <code>Namespace</code> to search within. A null implies Namespace.NO_NAMESPACE.
1644 * @return whether deletion occurred
1645 */
1646 public boolean removeChild(final String cname, final Namespace ns) {
1647 final ElementFilter filter = new ElementFilter(cname, ns);
1648 final List<Element> old = content.getView(filter);
1649 final Iterator<Element> iter = old.iterator();
1650 if (iter.hasNext()) {
1651 iter.next();
1652 iter.remove();
1653 return true;
1654 }
1655
1656 return false;
1657 }
1658
1659 /**
1660 * <p>
1661 * This removes all child elements (one level deep) with the
1662 * given local name and belonging to no namespace.
1663 * Returns true if any were removed.
1664 * </p>
1665 *
1666 * @param cname the name of child elements to remove
1667 * @return whether deletion occurred
1668 */
1669 public boolean removeChildren(final String cname) {
1670 return removeChildren(cname, Namespace.NO_NAMESPACE);
1671 }
1672
1673 /**
1674 * <p>
1675 * This removes all child elements (one level deep) with the
1676 * given local name and belonging to the given namespace.
1677 * Returns true if any were removed.
1678 * </p>
1679 *
1680 * @param cname the name of child elements to remove
1681 * @param ns <code>Namespace</code> to search within. A null implies Namespace.NO_NAMESPACE.
1682 * @return whether deletion occurred
1683 */
1684 public boolean removeChildren(final String cname, final Namespace ns) {
1685 boolean deletedSome = false;
1686
1687 final ElementFilter filter = new ElementFilter(cname, ns);
1688 final List<Element> old = content.getView(filter);
1689 final Iterator<Element> iter = old.iterator();
1690 while (iter.hasNext()) {
1691 iter.next();
1692 iter.remove();
1693 deletedSome = true;
1694 }
1695
1696 return deletedSome;
1697 }
1698
1699 /**
1700 * Get the Namespaces that are in-scope on this Element. Element has the
1701 * most complex rules for the namespaces-in-scope.
1702 * <p>
1703 * The scope is built up from a number of sources following the rules of
1704 * XML namespace inheritence as follows:
1705 * <ul>
1706 * <li>The {@link Namespace#XML_NAMESPACE} is added
1707 * <li>The element's namespace is added (commonly
1708 * {@link Namespace#NO_NAMESPACE})
1709 * <li>All the attributes are inspected and their Namespaces are included
1710 * <li>All Namespaces declared on this Element using
1711 * {@link #addNamespaceDeclaration(Namespace)} are included.
1712 * <li>If the element has a parent then the parent's Namespace scope is
1713 * inspected, and any prefixes in the parent scope that are not yet bound
1714 * in this Element's scope are included.
1715 * <li>If the default Namespace (the no-prefix namespace) has not been
1716 * encountered for this Element then {@link Namespace#NO_NAMESPACE} is
1717 * included.
1718 * </ul>
1719 * The Element's Namespace scope consist of it's inherited Namespaces and
1720 * any modifications to that scope derived from the Element itself. If the
1721 * element is detached then it's inherited scope consists of just
1722 * If an element has no parent then
1723 * <p>
1724 * Note that the Element's Namespace will always be reported first.
1725 * <p>
1726 * <strong>Description copied from</strong>
1727 * {@link NamespaceAware#getNamespacesInScope()}:
1728 * <p>
1729 * {@inheritDoc}
1730 *
1731 * @see NamespaceAware
1732 */
1733 @Override
1734 public List<Namespace> getNamespacesInScope() {
1735 // The assumption here is that all namespaces are valid,
1736 // that there are no namespace collisions on this element
1737
1738 // This method is also the 'anchor' of the three getNamespaces*() methods
1739 // It does not make reference to this Element instance's other
1740 // getNamespace*() methods
1741
1742 TreeMap<String,Namespace> namespaces = new TreeMap<String, Namespace>();
1743 namespaces.put(Namespace.XML_NAMESPACE.getPrefix(), Namespace.XML_NAMESPACE);
1744 namespaces.put(getNamespacePrefix(), getNamespace());
1745 if (additionalNamespaces != null) {
1746 for (Namespace ns : getAdditionalNamespaces()) {
1747 if (!namespaces.containsKey(ns.getPrefix())) {
1748 namespaces.put(ns.getPrefix(), ns);
1749 }
1750 }
1751 }
1752 if (attributes != null) {
1753 for (Attribute att : getAttributes()) {
1754 Namespace ns = att.getNamespace();
1755 if (!namespaces.containsKey(ns.getPrefix())) {
1756 namespaces.put(ns.getPrefix(), ns);
1757 }
1758 }
1759 }
1760 // Right, we now have all the namespaces that are current on this ELement.
1761 // Include any other namespaces that are inherited.
1762 final Element pnt = getParentElement();
1763 if (pnt != null) {
1764 for (Namespace ns : pnt.getNamespacesInScope()) {
1765 if (!namespaces.containsKey(ns.getPrefix())) {
1766 namespaces.put(ns.getPrefix(), ns);
1767 }
1768 }
1769 }
1770
1771 if (pnt == null && !namespaces.containsKey("")) {
1772 // we are the root element, and there is no 'default' namespace.
1773 namespaces.put(Namespace.NO_NAMESPACE.getPrefix(), Namespace.NO_NAMESPACE);
1774 }
1775
1776 ArrayList<Namespace> al = new ArrayList<Namespace>(namespaces.size());
1777 al.add(getNamespace());
1778 namespaces.remove(getNamespacePrefix());
1779 al.addAll(namespaces.values());
1780
1781 return Collections.unmodifiableList(al);
1782 }
1783
1784 @Override
1785 public List<Namespace> getNamespacesInherited() {
1786 if (getParentElement() == null) {
1787 ArrayList<Namespace> ret = new ArrayList<Namespace>(getNamespacesInScope());
1788 for (Iterator<Namespace> it = ret.iterator(); it.hasNext();) {
1789 Namespace ns = it.next();
1790 if (ns == Namespace.NO_NAMESPACE || ns == Namespace.XML_NAMESPACE) {
1791 continue;
1792 }
1793 it.remove();
1794 }
1795 return Collections.unmodifiableList(ret);
1796 }
1797
1798 // OK, the things we inherit are the prefixes we have in scope that
1799 // are also in our parent's scope.
1800 HashMap<String,Namespace> parents = new HashMap<String, Namespace>();
1801 for (Namespace ns : getParentElement().getNamespacesInScope()) {
1802 parents.put(ns.getPrefix(), ns);
1803 }
1804
1805 ArrayList<Namespace> al = new ArrayList<Namespace>();
1806 for (Namespace ns : getNamespacesInScope()) {
1807 if (ns == parents.get(ns.getPrefix())) {
1808 // inherited
1809 al.add(ns);
1810 }
1811 }
1812
1813 return Collections.unmodifiableList(al);
1814 }
1815
1816 @Override
1817 public List<Namespace> getNamespacesIntroduced() {
1818 if (getParentElement() == null) {
1819 // we introduce everything... except Namespace.XML_NAMESPACE
1820 List<Namespace> ret = new ArrayList<Namespace>(getNamespacesInScope());
1821 for (Iterator<Namespace> it = ret.iterator(); it.hasNext(); ) {
1822 Namespace ns = it.next();
1823 if (ns == Namespace.XML_NAMESPACE || ns == Namespace.NO_NAMESPACE) {
1824 it.remove();
1825 }
1826 }
1827 return Collections.unmodifiableList(ret);
1828 }
1829
1830 // OK, the things we introduce are the prefixes we have in scope that
1831 // are *not* in our parent's scope.
1832 HashMap<String,Namespace> parents = new HashMap<String, Namespace>();
1833 for (Namespace ns : getParentElement().getNamespacesInScope()) {
1834 parents.put(ns.getPrefix(), ns);
1835 }
1836
1837 ArrayList<Namespace> al = new ArrayList<Namespace>();
1838 for (Namespace ns : getNamespacesInScope()) {
1839 if (!parents.containsKey(ns.getPrefix()) || ns != parents.get(ns.getPrefix())) {
1840 // introduced
1841 al.add(ns);
1842 }
1843 }
1844
1845 return Collections.unmodifiableList(al);
1846 }
1847
1848 @Override
1849 public Element detach() {
1850 return (Element)super.detach();
1851 }
1852
1853 @Override
1854 public void canContainContent(Content child, int index, boolean replace) throws IllegalAddException {
1855 if (child instanceof DocType) {
1856 throw new IllegalAddException(
1857 "A DocType is not allowed except at the document level");
1858 }
1859 }
1860
1861 /**
1862 * Sort the contents of this Element using a mechanism that is safe for JDOM
1863 * content. See the notes on {@link #sortContent(Filter, Comparator)} for
1864 * how the algorithm works.
1865 * <p>
1866 * {@link Collections#sort(List, Comparator)} is not appropriate for sorting
1867 * the Lists returned from {@link Element#getContent()} because those are
1868 * 'live' lists, and the Collections.sort() method uses an algorithm that
1869 * adds the content in the new location before removing it from the old.
1870 * That creates validation issues with content attempting to attach to a
1871 * parent before detaching first.
1872 * <p>
1873 * This method provides a safe means to conveniently sort the content.
1874 *
1875 * @param comparator The Comparator to use for the sorting.
1876 */
1877 public void sortContent(Comparator<? super Content> comparator) {
1878 content.sort(comparator);
1879 }
1880
1881 /**
1882 * Sort the child Elements of this Element using a mechanism that is safe
1883 * for JDOM content. Other child content will be unaffected. See the notes
1884 * on {@link #sortContent(Filter, Comparator)} for how the algorithm works.
1885 * <p>
1886 * {@link Collections#sort(List, Comparator)} is not appropriate for sorting
1887 * the Lists returned from {@link Element#getContent()} because those are
1888 * 'live' lists, and the Collections.sort() method uses an algorithm that
1889 * adds the content in the new location before removing it from the old.
1890 * This creates validation issues with content attempting to attach to a
1891 * parent before detaching first.
1892 * <p>
1893 * This method provides a safe means to conveniently sort the content.
1894 *
1895 * @param comparator The Comparator to use for the sorting.
1896 */
1897 public void sortChildren(Comparator <? super Element> comparator) {
1898 ((FilterList<Element>)getChildren()).sort(comparator);
1899 }
1900
1901 /**
1902 * Sort the Attributes of this Element using a mechanism that is safe
1903 * for JDOM. Other child content will be unaffected. See the notes
1904 * on {@link #sortContent(Filter, Comparator)} for how the algorithm works.
1905 * <p>
1906 * {@link Collections#sort(List, Comparator)} is not appropriate for sorting
1907 * the Lists returned from {@link Element#getContent()} because those are
1908 * 'live' lists, and the Collections.sort() method uses an algorithm that
1909 * adds the content in the new location before removing it from the old.
1910 * This creates validation issues with content attempting to attach to a
1911 * parent before detaching first.
1912 * <p>
1913 * This method provides a safe means to conveniently sort the content.
1914 * <p>
1915 * A null comparator will sort the Attributes alphabetically first by prefix,
1916 * then by name
1917 *
1918 * @param comparator The Comparator to use for the sorting.
1919 */
1920 public void sortAttributes(Comparator <? super Attribute> comparator) {
1921 if (attributes != null) {
1922 attributes.sort(comparator);
1923 }
1924 }
1925
1926 /**
1927 * Sort the child content of this Element that matches the Filter, using a
1928 * mechanism that is safe for JDOM content. Other child content (that does
1929 * not match the filter) will be unaffected.
1930 * <p>
1931 * The algorithm used for sorting affects the child content in the following
1932 * ways:
1933 * <ol>
1934 * <li>Items not matching the Filter will be unchanged. This includes the
1935 * absolute position of that content in this Element. i.e. if child content
1936 * <code>cc</code> does not match the Filter, then <code>indexOf(cc)</code>
1937 * will not be changed by this sort.
1938 * <li>Items matching the Filter will be reordered according to the
1939 * comparator. Only the relative order of the Filtered data will change.
1940 * <li>Items that compare as 'equals' using the comparator will keep the
1941 * the same relative order as before the sort.
1942 * </ol>
1943 * <p>
1944 * {@link Collections#sort(List, Comparator)} is not appropriate for sorting
1945 * the Lists returned from {@link Element#getContent()} because those are
1946 * 'live' lists, and the Collections.sort() method uses an algorithm that
1947 * adds the content in the new location before removing it from the old.
1948 * This creates validation issues with content attempting to attach to a
1949 * parent before detaching first.
1950 * <p>
1951 * This method provides a safe means to conveniently sort the content.
1952 * @param <E> The generic type of the Filter used to select the content to
1953 * sort.
1954 * @param filter The Filter used to select which child content to sort.
1955 * Note that the {@link Filters} class has a number of predefined, useful
1956 * filters.
1957 * @param comparator The Comparator to use for the sorting.
1958 */
1959 public <E extends Content> void sortContent(Filter<E> filter, Comparator <? super E> comparator) {
1960 final FilterList<E> list = (FilterList<E>)getContent(filter);
1961 list.sort(comparator);
1962
1963 }
1964
1965
1966 /**
1967 * Simple method that supports getXMLBaseURI().
1968 * @param uri 'currently' URI as a string
1969 * @param relative the relative URI we are trying to make absolute
1970 * @return the resulting URI, may be null.
1971 * @throws URISyntaxException for URI problems.
1972 */
1973 private final URI resolve(String uri, URI relative)
1974 throws URISyntaxException {
1975 if (uri == null) {
1976 return relative;
1977 }
1978 final URI n = new URI(uri);
1979 if (relative == null) {
1980 return n;
1981 }
1982 return n.resolve(relative);
1983 }
1984
1985 /**
1986 * Calculate the XMLBase URI for this Element using the rules defined in the
1987 * XMLBase specification, as well as the values supplied in the xml:base
1988 * attributes on this Element and its ancestry.
1989 * <p>
1990 * This method assumes that all values in <code>xml:base</code> attributes
1991 * are valid URI values according to the <code>java.net.URI</code>
1992 * implementation. The same implementation is used to resolve relative URI
1993 * values, and thus this code follows the assumptions in java.net.URI.
1994 * <p>
1995 * This technically deviates from the XMLBase spec because to fully support
1996 * legacy HTML the xml:base attribute could contain what is called a 'LIERI'
1997 * which is a superset of true URI values, but for practical purposes JDOM
1998 * users should never encounter such values because they are not processing
1999 * raw HTML (but xhtml maybe).
2000 *
2001 * @return a URI representing the XMLBase value for the supplied Element, or
2002 * null if one could not be calculated.
2003 * @throws URISyntaxException
2004 * if it is not possible to create java.net.URI values from the data
2005 * in the <code>xml:base</code> attributes.
2006 */
2007 public URI getXMLBaseURI() throws URISyntaxException {
2008 Parent p = this;
2009 URI ret = null;
2010 while (p != null) {
2011 if (p instanceof Element) {
2012 ret = resolve(((Element) p).getAttributeValue("base",
2013 Namespace.XML_NAMESPACE), ret);
2014 } else {
2015 ret = resolve(((Document) p).getBaseURI(), ret);
2016 }
2017 if (ret != null && ret.isAbsolute()) {
2018 return ret;
2019 }
2020 p = p.getParent();
2021 }
2022 return ret;
2023 }
2024
2025
2026
2027 /**
2028 * JDOM2 Serialization. In this case, DocType is simple.
2029 */
2030 private static final long serialVersionUID = 200L;
2031
2032 /**
2033 * Serialize out the Element.
2034 *
2035 * @serialData
2036 * The Stream protocol is:
2037 * <ol>
2038 * <li>The Element name and Namespace using default Serialization.
2039 * <li>The count of additional Namespace Declarations.
2040 * <li>The actual additional Namespace Declarations.
2041 * <li>The count of Attributes.
2042 * <li>The actual Attributes.
2043 * <li>The count of child Content
2044 * <li>The actual Child Content.
2045 * </ol>
2046 *
2047 * @param out where to write the Element to.
2048 * @throws IOException if there is a writing problem.
2049 */
2050 private void writeObject(final ObjectOutputStream out) throws IOException {
2051 // sends out the name and namespace.
2052 out.defaultWriteObject();
2053 if (hasAdditionalNamespaces()) {
2054 final int ans = additionalNamespaces.size();
2055 out.writeInt(ans);
2056 for (int i = 0; i < ans; i++) {
2057 out.writeObject(additionalNamespaces.get(i));
2058 }
2059 } else {
2060 out.writeInt(0);
2061 }
2062 if (hasAttributes()) {
2063 final int ans = attributes.size();
2064 out.writeInt(ans);
2065 for (int i = 0; i < ans; i++) {
2066 out.writeObject(attributes.get(i));
2067 }
2068 } else {
2069 out.writeInt(0);
2070 }
2071
2072 final int cs = content.size();
2073 out.writeInt(cs);
2074 for (int i = 0; i < cs; i++) {
2075 out.writeObject(content.get(i));
2076 }
2077
2078 }
2079
2080 /**
2081 * Read an Element off the ObjectInputStream.
2082 *
2083 * @see #writeObject(ObjectOutputStream)
2084 * @param in where to read the Element from.
2085 * @throws IOException if there is a reading problem.
2086 * @throws ClassNotFoundException when a class cannot be found
2087 */
2088 private void readObject(final ObjectInputStream in)
2089 throws IOException, ClassNotFoundException {
2090
2091 in.defaultReadObject();
2092
2093 content = new ContentList(this);
2094
2095 int nss = in.readInt();
2096
2097 while (--nss >= 0) {
2098 addNamespaceDeclaration((Namespace)in.readObject());
2099 }
2100
2101 int ats = in.readInt();
2102 while (--ats >= 0) {
2103 setAttribute((Attribute)in.readObject());
2104 }
2105
2106 int cs = in.readInt();
2107 while (--cs >= 0) {
2108 addContent((Content)in.readObject());
2109 }
2110
2111 }
2112
2113 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 /**
57 * An XML entity reference. Methods allow the user to manage its name, public
58 * id, and system id.
59 *
60 * @author Brett McLaughlin
61 * @author Jason Hunter
62 * @author Philip Nelson
63 * @author Rolf Lear
64 */
65 public class EntityRef extends Content {
66
67 /**
68 * JDOM2 Serialization. In this case, EntityRef is simple.
69 */
70 private static final long serialVersionUID = 200L;
71
72 /** The name of the <code>EntityRef</code> */
73 protected String name;
74
75 /** The PublicID of the <code>EntityRef</code> */
76 protected String publicID;
77
78 /** The SystemID of the <code>EntityRef</code> */
79 protected String systemID;
80
81 /**
82 * Default, no-args constructor for implementations to use if needed.
83 */
84 protected EntityRef() {
85 super(CType.EntityRef);
86 }
87
88 /**
89 * This will create a new <code>EntityRef</code> with the supplied name.
90 *
91 * @param name <code>String</code> name of element.
92 * @throws IllegalNameException if the given name is not a legal
93 * XML name.
94 */
95 public EntityRef(String name) {
96 this(name, null, null);
97 }
98
99 /**
100 * This will create a new <code>EntityRef</code>
101 * with the supplied name and system id.
102 *
103 * @param name <code>String</code> name of element.
104 * @param systemID system id of the entity reference being constructed
105 * @throws IllegalNameException if the given name is not a legal
106 * XML name.
107 * @throws IllegalDataException if the given system ID is not a legal
108 * system literal.
109 */
110 public EntityRef(String name, String systemID) {
111 this(name, null, systemID);
112 }
113
114 /**
115 * This will create a new <code>EntityRef</code>
116 * with the supplied name, public id, and system id.
117 *
118 * @param name <code>String</code> name of element.
119 * @param publicID public id of the entity reference being constructed
120 * @param systemID system id of the entity reference being constructed
121 * @throws IllegalDataException if the given system ID is not a legal
122 * system literal or the the given public ID is not a
123 * legal public ID
124 * @throws IllegalNameException if the given name is not a legal
125 * XML name.
126 */
127 public EntityRef(String name, String publicID, String systemID) {
128 super(CType.EntityRef);
129 setName(name);
130 setPublicID(publicID);
131 setSystemID(systemID);
132 }
133
134 /**
135 * This returns the name of the <code>EntityRef</code>.
136 *
137 * @return <code>String</code> - entity name.
138 */
139 public String getName() {
140 return name;
141 }
142
143 /**
144 * Returns the empty string since entity references don't have an XPath
145 * 1.0 string value.
146 * @return the empty string
147 */
148 @Override
149 public String getValue() {
150 return ""; // entity references don't have XPath string values
151 }
152
153 /**
154 * This will return the publid ID of this <code>EntityRef</code>.
155 * If there is no public ID, then this returns <code>null</code>.
156 *
157 * @return public ID of this <code>EntityRef</code>
158 */
159 public String getPublicID() {
160 return publicID;
161 }
162
163 /**
164 * This will return the system ID of this <code>EntityRef</code>.
165 * If there is no system ID, then this returns <code>null</code>.
166 *
167 * @return system ID of this <code>EntityRef</code>
168 */
169 public String getSystemID() {
170 return systemID;
171 }
172
173 /**
174 * This will set the name of this <code>EntityRef</code>.
175 *
176 * @param name new name of the entity
177 * @return this <code>EntityRef</code> modified.
178 * @throws IllegalNameException if the given name is not a legal
179 * XML name.
180 */
181 public EntityRef setName(String name) {
182 // This can contain a colon so we use checkXMLName()
183 // instead of checkElementName()
184 String reason = Verifier.checkXMLName(name);
185 if (reason != null) {
186 throw new IllegalNameException(name, "EntityRef", reason);
187 }
188 this.name = name;
189 return this;
190 }
191
192 /**
193 * This will set the public ID of this <code>EntityRef</code>.
194 *
195 * @param publicID new public id
196 * @return this <code>EntityRef</code> modified.
197 * @throws IllegalDataException if the given public ID is not a legal
198 * public ID.
199 */
200 public EntityRef setPublicID(String publicID) {
201 String reason = Verifier.checkPublicID(publicID);
202 if (reason != null) {
203 throw new IllegalDataException(publicID, "EntityRef", reason);
204 }
205 this.publicID = publicID;
206 return this;
207 }
208
209 /**
210 * This will set the system ID of this <code>EntityRef</code>.
211 *
212 * @param systemID new system id
213 * @throws IllegalDataException if the given system ID is not a legal
214 * system literal.
215 * @return this <code>EntityRef</code> modified.
216 */
217 public EntityRef setSystemID(String systemID) {
218 String reason = Verifier.checkSystemLiteral(systemID);
219 if (reason != null) {
220 throw new IllegalDataException(systemID, "EntityRef", reason);
221 }
222 this.systemID = systemID;
223 return this;
224 }
225
226 /**
227 * This returns a <code>String</code> representation of the
228 * <code>EntityRef</code>, suitable for debugging.
229 *
230 * @return <code>String</code> - information about the
231 * <code>EntityRef</code>
232 */
233 @Override
234 public String toString() {
235 return new StringBuilder()
236 .append("[EntityRef: ")
237 .append("&")
238 .append(name)
239 .append(";")
240 .append("]")
241 .toString();
242 }
243
244 @Override
245 public EntityRef detach() {
246 return (EntityRef)super.detach();
247 }
248
249 @Override
250 protected EntityRef setParent(Parent parent) {
251 return (EntityRef)super.setParent(parent);
252 }
253
254 @Override
255 public Element getParent() {
256 // because DocType can only be attached to a Document.
257 return (Element)super.getParent();
258 }
259
260 @Override
261 public EntityRef clone() {
262 return (EntityRef)super.clone();
263 }
264 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.*;
57
58 import org.jdom.filter2.*;
59 import org.jdom.util.IteratorIterable;
60
61 /**
62 * Traverse a parent's children that match the supplied filter.
63 *
64 * @author Bradley S. Huffman
65 * @author Rolf Lear
66 * @param <T> The Generic type of content returned by this FilterIterator.
67 */
68 final class FilterIterator<T> implements IteratorIterable<T> {
69
70 private final DescendantIterator iterator;
71 private final Filter<T> filter;
72 private T nextObject;
73 private boolean canremove = false;
74
75 public FilterIterator(DescendantIterator iterator, Filter<T> filter) {
76 // can trust that iterator is not null, but filter may be.
77 if (filter == null) {
78 throw new NullPointerException("Cannot specify a null Filter " +
79 "for a FilterIterator");
80 }
81 this.iterator = iterator;
82 this.filter = filter;
83 }
84
85 @Override
86 public Iterator<T> iterator() {
87 return new FilterIterator<T>(iterator.iterator(), filter);
88 }
89
90 @Override
91 public boolean hasNext() {
92
93 canremove = false;
94
95 if (nextObject != null) {
96 return true;
97 }
98
99 while (iterator.hasNext()) {
100 final Object obj = iterator.next();
101 final T f = filter.filter(obj);
102 if (f != null) {
103 nextObject = f;
104 return true;
105 }
106 }
107 return false;
108 }
109
110 @Override
111 public T next() {
112 if (!hasNext()) {
113 throw new NoSuchElementException();
114 }
115
116 final T obj = nextObject;
117 nextObject = null;
118 canremove = true;
119 return obj;
120 }
121
122 @Override
123 public void remove() {
124 if (!canremove) {
125 throw new IllegalStateException("remove() can only be called " +
126 "on the FilterIterator immediately after a successful " +
127 "call to next(). A call to remove() immediately after " +
128 "a call to hasNext() or remove() will also fail.");
129 }
130 canremove = false;
131 iterator.remove();
132 }
133 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 /**
57 * Thrown when trying to add an illegal object to a JDOM construct.
58 *
59 * @author Brett McLaughlin
60 * @author Jason Hunter
61 */
62 public class IllegalAddException extends IllegalArgumentException {
63
64 /**
65 * Standard JDOM2 Exception Serialization. Default.
66 */
67 private static final long serialVersionUID = 200L;
68
69 /**
70 * This will create an <code>Exception</code> indicating
71 * that the addition of the <code>{@link Attribute}</code>
72 * to the <code>{@link Element}</code> is illegal.
73 *
74 * @param base <code>Element</code> that <code>Attribute</code>
75 * couldn't be added to
76 * @param added <code>Attribute</code> that could not be added
77 * @param reason cause of the problem
78 */
79 IllegalAddException(Element base, Attribute added, String reason) {
80 super(new StringBuilder()
81 .append("The attribute \"")
82 .append(added.getQualifiedName())
83 .append("\" could not be added to the element \"")
84 .append(base.getQualifiedName())
85 .append("\": ")
86 .append(reason)
87 .toString());
88 }
89
90 /**
91 * This will create an <code>Exception</code> indicating
92 * that the addition of the <code>{@link Element}</code>
93 * to parent is illegal.
94 *
95 * @param base <code>Element</code> that the child
96 * couldn't be added to
97 * @param added <code>Element</code> that could not be added
98 * @param reason cause of the problem
99 */
100 IllegalAddException(Element base, Element added, String reason) {
101 super(new StringBuilder()
102 .append("The element \"")
103 .append(added.getQualifiedName())
104 .append("\" could not be added as a child of \"")
105 .append(base.getQualifiedName())
106 .append("\": ")
107 .append(reason)
108 .toString());
109 }
110
111 /**
112 * This will create an <code>Exception</code> indicating
113 * that the addition of the <code>{@link Element}</code>
114 * to the <code>{@link Document}</code> is illegal.
115 *
116 * @param added <code>Element</code> that could not be added
117 * @param reason cause of the problem
118 */
119 IllegalAddException(Element added, String reason) {
120 super(new StringBuilder()
121 .append("The element \"")
122 .append(added.getQualifiedName())
123 .append("\" could not be added as the root of the document: ")
124 .append(reason)
125 .toString());
126 }
127
128 /**
129 * This will create an <code>Exception</code> indicating
130 * that the addition of the <code>{@link ProcessingInstruction}</code>
131 * to the <code>{@link Element}</code> is illegal.
132 *
133 * @param base <code>Element</code> that the
134 * <code>ProcessingInstruction</code> couldn't be added to
135 * @param added <code>ProcessingInstruction</code> that could not be added
136 * @param reason cause of the problem
137 */
138 IllegalAddException(Element base, ProcessingInstruction added,
139 String reason) {
140 super(new StringBuilder()
141 .append("The PI \"")
142 .append(added.getTarget())
143 .append("\" could not be added as content to \"")
144 .append(base.getQualifiedName())
145 .append("\": ")
146 .append(reason)
147 .toString());
148 }
149
150 /**
151 * This will create an <code>Exception</code> indicating
152 * that the addition of the <code>{@link ProcessingInstruction}</code>
153 * to the <code>{@link Document}</code> is illegal.
154 *
155 * @param added <code>ProcessingInstruction</code> that could not be added
156 * @param reason cause of the problem
157 */
158 IllegalAddException(ProcessingInstruction added,
159 String reason) {
160 super(new StringBuilder()
161 .append("The PI \"")
162 .append(added.getTarget())
163 .append("\" could not be added to the top level of the document: ")
164 .append(reason)
165 .toString());
166 }
167
168 /**
169 * This will create an <code>Exception</code> indicating
170 * that the addition of the <code>{@link Comment}</code>
171 * to the <code>{@link Element}</code> is illegal.
172 *
173 * @param base <code>Element</code> that the <code>Comment</code>
174 * couldn't be added to
175 * @param added <code>Comment</code> that could not be added
176 * @param reason cause of the problem
177 */
178 IllegalAddException(Element base, Comment added, String reason) {
179 super(new StringBuilder()
180 .append("The comment \"")
181 .append(added.getText())
182 .append("\" could not be added as content to \"")
183 .append(base.getQualifiedName())
184 .append("\": ")
185 .append(reason)
186 .toString());
187 }
188
189
190 /**
191 * This will create an <code>Exception</code> indicating
192 * that the addition of the <code>{@link CDATA}</code>
193 *
194 * @param base <code>Element</code> that the <code>CDATA</code>
195 * couldn't be added to
196 * @param added <code>CDATA</code> that could not be added
197 * @param reason cause of the problem
198 */
199 IllegalAddException(Element base, CDATA added, String reason) {
200 super(new StringBuilder()
201 .append("The CDATA \"")
202 .append(added.getText())
203 .append("\" could not be added as content to \"")
204 .append(base.getQualifiedName())
205 .append("\": ")
206 .append(reason)
207 .toString());
208 }
209
210
211 /**
212 * This will create an <code>Exception</code> indicating
213 * that the addition of the <code>{@link Text}</code>
214 * to the <code>{@link Element}</code> is illegal.
215 *
216 * @param base <code>Element</code> that the <code>Comment</code>
217 * couldn't be added to
218 * @param added <code>Text</code> that could not be added
219 * @param reason cause of the problem
220 */
221 IllegalAddException(Element base, Text added, String reason) {
222 super(new StringBuilder()
223 .append("The Text \"")
224 .append(added.getText())
225 .append("\" could not be added as content to \"")
226 .append(base.getQualifiedName())
227 .append("\": ")
228 .append(reason)
229 .toString());
230 }
231
232 /**
233 * This will create an <code>Exception</code> indicating
234 * that the addition of the <code>{@link Comment}</code>
235 * to the <code>{@link Document}</code> is illegal.
236 *
237 * @param added <code>Comment</code> that could not be added
238 * @param reason cause of the problem
239 */
240 IllegalAddException(Comment added, String reason) {
241 super(new StringBuilder()
242 .append("The comment \"")
243 .append(added.getText())
244 .append("\" could not be added to the top level of the document: ")
245 .append(reason)
246 .toString());
247 }
248
249 /**
250 * This will create an <code>Exception</code> indicating
251 * that the addition of the <code>{@link EntityRef}</code>
252 * to the <code>{@link Element}</code> is illegal.
253 *
254 * @param base <code>Element</code> that the <code>EntityRef</code>
255 * couldn't be added to
256 * @param added <code>EntityRef</code> reference that could not be added
257 * @param reason cause of the problem
258 */
259 IllegalAddException(Element base, EntityRef added, String reason) {
260 super(new StringBuilder()
261 .append("The entity reference\"")
262 .append(added.getName())
263 .append("\" could not be added as content to \"")
264 .append(base.getQualifiedName())
265 .append("\": ")
266 .append(reason)
267 .toString());
268 }
269
270 /**
271 * This will create an <code>Exception</code> indicating
272 * that the addition of the <code>{@link Namespace}</code>
273 * to the <code>{@link Element}</code> is illegal.
274 *
275 * @param base <code>Element</code> that the <code>Namespace</code>
276 * couldn't be added to
277 * @param added <code>Namespace</code> that could not be added
278 * @param reason cause of the problem
279 */
280 IllegalAddException(Element base, Namespace added, String reason) {
281 super(new StringBuilder()
282 .append("The namespace xmlns")
283 .append(added.getPrefix().equals("") ? "="
284 : ":" + added.getPrefix() + "=")
285 .append("\"")
286 .append(added.getURI())
287 .append("\" could not be added as a namespace to \"")
288 .append(base.getQualifiedName())
289 .append("\": ")
290 .append(reason)
291 .toString());
292 }
293
294 /**
295 * This will create an <code>Exception</code> indicating
296 * that the addition of the <code>{@link DocType}</code>
297 * to the <code>{@link Document}</code> is illegal.
298 *
299 * @param added <code>DocType</code> that could not be added
300 * @param reason cause of the problem
301 */
302 IllegalAddException(DocType added, String reason) {
303 super(new StringBuilder()
304 .append("The DOCTYPE ")
305 .append(added.toString())
306 .append(" could not be added to the document: ")
307 .append(reason)
308 .toString());
309 }
310
311 /**
312 * This will create an <code>Exception</code> with the specified
313 * error message.
314 *
315 * @param reason cause of the problem
316 */
317 public IllegalAddException(String reason) {
318 super(reason);
319 }
320 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 /**
57 * Thrown when illegal text is supplied to a JDOM construct.
58 *
59 * @author Brett McLaughlin
60 * @author Elliotte Rusty Harold
61 */
62 public class IllegalDataException extends IllegalArgumentException {
63
64 /**
65 * Standard JDOM2 Exception Serialization. Default.
66 */
67 private static final long serialVersionUID = 200L;
68
69 /**
70 * This will create an <code>Exception</code> indicating
71 * that the specified data is illegal for the construct
72 * it was supplied to.
73 *
74 * @param data <code>String</code> data that breaks rules.
75 * @param construct <code>String</code> construct that data is illegal for.
76 * @param reason <code>String</code> message or reason data is illegal.
77 */
78 IllegalDataException(String data, String construct, String reason) {
79 super(new StringBuilder()
80 .append("The data \"")
81 .append(data)
82 .append("\" is not legal for a JDOM ")
83 .append(construct)
84 .append(": ")
85 .append(reason)
86 .append(".")
87 .toString());
88 }
89
90 /**
91 * This will create an <code>Exception</code> indicating
92 * that the specified data is illegal for the construct
93 * it was supplied to.
94 *
95 * @param data <code>String</code> data that breaks rules.
96 * @param construct <code>String</code> construct that data is illegal for.
97 */
98 IllegalDataException(String data, String construct) {
99 super(new StringBuilder()
100 .append("The data \"")
101 .append(data)
102 .append("\" is not legal for a JDOM ")
103 .append(construct)
104 .append(".")
105 .toString());
106 }
107
108 /**
109 * This will create an exceptoin with the specified error message.
110 *
111 * @param reason cause of the problem
112 */
113 public IllegalDataException(String reason) {
114 super(reason);
115 }
116 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 /**
57 * Thrown when a name is supplied in construction of a JDOM construct whose
58 * where the name breaks XML naming conventions.
59 *
60 * @author Brett McLaughlin
61 * @author Elliotte Rusty Harold
62 */
63 public class IllegalNameException extends IllegalArgumentException {
64
65 /**
66 * Standard JDOM2 Exception Serialization. Default.
67 */
68 private static final long serialVersionUID = 200L;
69
70 /**
71 * This will create an <code>Exception</code> indicating
72 * that the specified name is illegal for the construct
73 * it was supplied to.
74 *
75 * @param name <code>String</code> name that breaks rules.
76 * @param construct <code>String</code> name of JDOM construct
77 * that <code>name</code> was supplied to.
78 * @param reason <code>String</code> message or reason name is illegal.
79 */
80 IllegalNameException(String name, String construct, String reason) {
81 super(new StringBuilder()
82 .append("The name \"")
83 .append(name)
84 .append("\" is not legal for JDOM/XML ")
85 .append(construct)
86 .append("s: ")
87 .append(reason)
88 .append(".")
89 .toString());
90 }
91
92 /**
93 * This will create an <code>Exception</code> indicating
94 * that the specified name is illegal for the construct
95 * it was supplied to.
96 *
97 * @param name <code>String</code> name that breaks rules.
98 * @param construct <code>String</code> name of JDOM construct
99 * that <code>name</code> was supplied to.
100 */
101 IllegalNameException(String name, String construct) {
102 super(new StringBuilder()
103 .append("The name \"")
104 .append(name)
105 .append("\" is not legal for JDOM/XML ")
106 .append(construct)
107 .append("s.")
108 .toString());
109 }
110
111 /**
112 * Creates an exception with the specified error message.
113 *
114 * @param reason cause of the problem
115 */
116 public IllegalNameException(String reason) {
117 super(reason);
118 }
119 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 /**
57 * Thrown when a target is supplied in construction of a JDOM {@link
58 * ProcessingInstruction}, and that name breaks XML naming conventions.
59 *
60 * @author Brett McLaughlin
61 */
62 public class IllegalTargetException extends IllegalArgumentException {
63
64 /**
65 * Standard JDOM2 Exception Serialization. Default.
66 */
67 private static final long serialVersionUID = 200L;
68
69 /**
70 * This will create an <code>Exception</code> indicating
71 * that the specified target is illegal for the
72 * <code>{@link ProcessingInstruction}</code> it was supplied to.
73 *
74 * @param target <code>String</code> target that breaks rules.
75 * @param reason <code>String</code> message or reason target is illegal.
76 */
77 IllegalTargetException(String target, String reason) {
78 super(new StringBuilder()
79 .append("The target \"")
80 .append(target)
81 .append("\" is not legal for JDOM/XML Processing Instructions: ")
82 .append(reason)
83 .append(".")
84 .toString());
85 }
86
87 /**
88 * Creates an exception with the specified error message.
89 *
90 * @param reason cause of the problem
91 */
92 public IllegalTargetException(String reason) {
93 super(reason);
94 }
95 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import javax.xml.transform.TransformerFactory;
57
58 import org.jdom.output.LineSeparator;
59 import org.jdom.transform.JDOMResult;
60 import org.jdom.transform.JDOMSource;
61 import org.jdom.xpath.XPathFactory;
62
63
64 /**
65 * A collection of constants that may be useful to JDOM users.
66 * <p>
67 * JDOM attempts to make knowing these 'magic' constants unnecessary, but it is
68 * not always possible. In an attempt to make it easier though, common constants
69 * are defined here. This is not a comprehensive list of all the constants that
70 * may be useful when processing XML, but it should cover most of those occasions
71 * where JDOM does not automatically do the 'right thing'.
72 * <p>
73 * Many of these constants are already referenced inside the JDOM code.
74 *
75 * @author Rolf Lear
76 *
77 */
78 public final class JDOMConstants {
79
80 /**
81 * Keep out of public reach.
82 */
83 private JDOMConstants () {
84 // private default constructor.
85 }
86
87 /*
88 * XML Namespace constants
89 */
90
91 /** Defined as {@value} */
92 public static final String NS_PREFIX_DEFAULT = "";
93 /** Defined as {@value} */
94 public static final String NS_URI_DEFAULT = "";
95
96 /** Defined as {@value} */
97 public static final String NS_PREFIX_XML = "xml";
98 /** Defined as {@value} */
99 public static final String NS_URI_XML = "http://www.w3.org/XML/1998/namespace";
100
101 /** Defined as {@value} */
102 public static final String NS_PREFIX_XMLNS = "xmlns";
103 /** Defined as {@value} */
104 public static final String NS_URI_XMLNS = "http://www.w3.org/2000/xmlns/";
105
106
107 /** Defined as {@value} */
108 public static final String SAX_PROPERTY_DECLARATION_HANDLER =
109 "http://xml.org/sax/properties/declaration-handler";
110
111 /** Defined as {@value} */
112 public static final String SAX_PROPERTY_DECLARATION_HANDLER_ALT =
113 "http://xml.org/sax/handlers/DeclHandler";
114
115 /** Defined as {@value} */
116 public static final String SAX_PROPERTY_LEXICAL_HANDLER =
117 "http://xml.org/sax/properties/lexical-handler";
118
119 /** Defined as {@value} */
120 public static final String SAX_PROPERTY_LEXICAL_HANDLER_ALT =
121 "http://xml.org/sax/handlers/LexicalHandler";
122
123
124
125 /** Defined as {@value} */
126 public static final String SAX_FEATURE_EXTERNAL_ENT =
127 "http://xml.org/sax/features/external-general-entities";
128
129 /** Defined as {@value} */
130 public static final String SAX_FEATURE_VALIDATION =
131 "http://xml.org/sax/features/validation";
132
133 /** Defined as {@value} */
134 public static final String SAX_FEATURE_NAMESPACES =
135 "http://xml.org/sax/features/namespaces";
136
137 /** Defined as {@value} */
138 public static final String SAX_FEATURE_NAMESPACE_PREFIXES =
139 "http://xml.org/sax/features/namespace-prefixes";
140
141
142 /**
143 * Constant used to define the {@link JDOMSource} with JAXP.
144 * Defined as {@value}
145 * @see JDOMSource
146 */
147 public static final String JDOM2_FEATURE_JDOMSOURCE =
148 "http://jdom.org/jdom2/transform/JDOMSource/feature";
149
150 /**
151 * Constant used to define the {@link JDOMResult} with {@link TransformerFactory}.
152 * Defined as {@value}
153 * @see JDOMResult
154 */
155 public static final String JDOM2_FEATURE_JDOMRESULT =
156 "http://jdom.org/jdom2/transform/JDOMResult/feature";
157
158 /**
159 * System Property queried to obtain an alternate default XPathFactory.
160 * Defined as {@value}
161 * @see XPathFactory
162 */
163 public static final String JDOM2_PROPERTY_XPATH_FACTORY =
164 "org.jdom.xpath.XPathFactory";
165
166 /**
167 * System Property queried to obtain an alternate default Line Separator.
168 * <p>
169 * Defined as {@value}
170 * @see LineSeparator
171 */
172 public static final String JDOM2_PROPERTY_LINE_SEPARATOR =
173 "org.jdom.output.LineSeparator";
174
175 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 /**
57 * The top level 'checked' exception that JDOM classes can throw. JDOM does
58 * throw a number of unchecked exceptions, but all the checked exceptions are
59 * descendants of this class.
60 *
61 * @author Brett McLaughlin
62 * @author Jason Hunter
63 */
64 public class JDOMException extends Exception {
65
66 /**
67 * Standard JDOM2 Exception Serialization. Default.
68 */
69 private static final long serialVersionUID = 200L;
70
71 /**
72 * This will create an <code>Exception</code>.
73 */
74 public JDOMException() {
75 super("Error occurred in JDOM application.");
76 }
77
78 /**
79 * This will create an <code>Exception</code> with the given message.
80 *
81 * @param message <code>String</code> message indicating
82 * the problem that occurred.
83 */
84 public JDOMException(String message) {
85 super(message);
86 }
87
88 /**
89 * This will create an <code>Exception</code> with the given message
90 * and wrap another <code>Exception</code>. This is useful when
91 * the originating <code>Exception</code> should be held on to.
92 *
93 * @param message <code>String</code> message indicating
94 * the problem that occurred.
95 * @param cause <code>Throwable</code> that caused this
96 * to be thrown.
97 */
98 public JDOMException(String message, Throwable cause) {
99 super(message, cause);
100 }
101
102 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.*;
57
58 /**
59 * An interface to be used by builders when constructing JDOM objects. The
60 * <code>DefaultJDOMFactory</code> creates the standard top-level JDOM classes
61 * (Element, Document, Comment, etc). Another implementation of this factory
62 * could be used to create custom classes.
63 *
64 * @author Ken Rune Holland
65 * @author Phil Nelson
66 * @author Bradley S. Huffman
67 * @author Rolf Lear
68 */
69 public interface JDOMFactory {
70
71 // **** constructing Attributes ****
72
73 /**
74 * <p>
75 * This will create a new <code>Attribute</code> with the
76 * specified (local) name and value, and in the provided
77 * <code>{@link org.jdom.Namespace}</code>.
78 * </p>
79 *
80 * @param name <code>String</code> name of <code>Attribute</code>.
81 * @param value <code>String</code> value for new attribute.
82 * @param namespace <code>Namespace</code> of the new Attribute
83 * @return the created Attribute instance
84 */
85 public Attribute attribute(String name, String value, Namespace namespace);
86
87 /**
88 * This will create a new <code>Attribute</code> with the
89 * specified (local) name, value, and type, and in the provided
90 * <code>{@link org.jdom.Namespace}</code>.
91 *
92 * @param name <code>String</code> name of <code>Attribute</code>.
93 * @param value <code>String</code> value for new attribute.
94 * @param type <code>int</code> type for new attribute.
95 * @param namespace <code>Namespace</code> namespace for new attribute.
96 * @return the created Attribute instance
97 * @deprecated Use {@link #attribute(String, String, AttributeType, Namespace)}
98 */
99 @Deprecated
100 public Attribute attribute(String name, String value,
101 int type, Namespace namespace);
102
103 /**
104 * This will create a new <code>Attribute</code> with the
105 * specified (local) name, value, and type, and in the provided
106 * <code>{@link org.jdom.Namespace}</code>.
107 *
108 * @param name <code>String</code> name of <code>Attribute</code>.
109 * @param value <code>String</code> value for new attribute.
110 * @param type <code>AttributeType</code> type for new attribute.
111 * @param namespace <code>Namespace</code> namespace for new attribute.
112 * @return the created Attribute instance
113 */
114 public Attribute attribute(String name, String value,
115 AttributeType type, Namespace namespace);
116
117 /**
118 * This will create a new <code>Attribute</code> with the
119 * specified (local) name and value, and does not place
120 * the attribute in a <code>{@link org.jdom.Namespace}</code>.
121 * <p>
122 * <b>Note</b>: This actually explicitly puts the
123 * <code>Attribute</code> in the "empty" <code>Namespace</code>
124 * (<code>{@link org.jdom.Namespace#NO_NAMESPACE}</code>).
125 * </p>
126 *
127 * @param name <code>String</code> name of <code>Attribute</code>.
128 * @param value <code>String</code> value for new attribute.
129 * @return the created Attribute instance
130 */
131 public Attribute attribute(String name, String value);
132
133 /**
134 * This will create a new <code>Attribute</code> with the
135 * specified (local) name, value and type, and does not place
136 * the attribute in a <code>{@link org.jdom.Namespace}</code>.
137 * <p>
138 * <b>Note</b>: This actually explicitly puts the
139 * <code>Attribute</code> in the "empty" <code>Namespace</code>
140 * (<code>{@link org.jdom.Namespace#NO_NAMESPACE}</code>).
141 * </p>
142 *
143 * @param name <code>String</code> name of <code>Attribute</code>.
144 * @param value <code>String</code> value for new attribute.
145 * @param type <code>int</code> type for new attribute.
146 * @return the created Attribute instance
147 * @deprecated use {@link #attribute(String, String, AttributeType)}
148 */
149 @Deprecated
150 public Attribute attribute(String name, String value, int type);
151
152 /**
153 * This will create a new <code>Attribute</code> with the
154 * specified (local) name, value and type, and does not place
155 * the attribute in a <code>{@link org.jdom.Namespace}</code>.
156 * <p>
157 * <b>Note</b>: This actually explicitly puts the
158 * <code>Attribute</code> in the "empty" <code>Namespace</code>
159 * (<code>{@link org.jdom.Namespace#NO_NAMESPACE}</code>).
160 * </p>
161 *
162 * @param name <code>String</code> name of <code>Attribute</code>.
163 * @param value <code>String</code> value for new attribute.
164 * @param type <code>AttributeType</code> type for new attribute.
165 * @return the created Attribute instance
166 */
167 public Attribute attribute(String name, String value, AttributeType type);
168
169 // **** constructing CDATA ****
170
171 /**
172 * This creates the CDATA with the supplied text.
173 *
174 * @param str <code>String</code> content of CDATA.
175 * @return the created CDATA instance
176 */
177 public CDATA cdata(String str);
178
179 /**
180 * This creates the CDATA with the supplied text.
181 *
182 * @param line The line on which this content begins.
183 * @param col The column on the line at which this content begins.
184 * @param str <code>String</code> content of CDATA.
185 * @return the created CDATA instance
186 * @since JDOM2
187 */
188 public CDATA cdata(int line, int col, String str);
189
190 // **** constructing Text ****
191
192 /**
193 * This creates the Text with the supplied text.
194 *
195 * @param line The line on which this content begins.
196 * @param col The column on the line at which this content begins.
197 * @param str <code>String</code> content of Text.
198 * @return the created Text instance
199 * @since JDOM2
200 */
201 public Text text(int line, int col, String str);
202
203 // **** constructing Text ****
204
205 /**
206 * This creates the Text with the supplied text.
207 *
208 * @param str <code>String</code> content of Text.
209 * @return the created Text instance
210 */
211 public Text text(String str);
212
213 // **** constructing Comment ****
214
215 /**
216 * This creates the comment with the supplied text.
217 *
218 * @param text <code>String</code> content of comment.
219 * @return the created Comment instance
220 */
221 public Comment comment(String text);
222
223 /**
224 * This creates the comment with the supplied text.
225 *
226 * @param line The line on which this content begins.
227 * @param col The column on the line at which this content begins.
228 * @param text <code>String</code> content of comment.
229 * @return the created Comment instance
230 * @since JDOM2
231 */
232 public Comment comment(int line, int col, String text);
233
234 // **** constructing DocType
235
236 /**
237 * This will create the <code>DocType</code> with
238 * the specified element name and a reference to an
239 * external DTD.
240 *
241 * @param elementName <code>String</code> name of
242 * element being constrained.
243 * @param publicID <code>String</code> public ID of
244 * referenced DTD
245 * @param systemID <code>String</code> system ID of
246 * referenced DTD
247 * @return the created DocType instance
248 */
249 public DocType docType(String elementName,
250 String publicID, String systemID);
251
252 /**
253 * This will create the <code>DocType</code> with
254 * the specified element name and reference to an
255 * external DTD.
256 *
257 * @param elementName <code>String</code> name of
258 * element being constrained.
259 * @param systemID <code>String</code> system ID of
260 * referenced DTD
261 * @return the created DocType instance
262 */
263 public DocType docType(String elementName, String systemID);
264
265 /**
266 * This will create the <code>DocType</code> with
267 * the specified element name
268 *
269 * @param elementName <code>String</code> name of
270 * element being constrained.
271 * @return the created DocType instance
272 */
273 public DocType docType(String elementName);
274
275 /**
276 * This will create the <code>DocType</code> with
277 * the specified element name and a reference to an
278 * external DTD.
279 *
280 * @param line The line on which this content begins.
281 * @param col The column on the line at which this content begins.
282 * @param elementName <code>String</code> name of
283 * element being constrained.
284 * @param publicID <code>String</code> public ID of
285 * referenced DTD
286 * @param systemID <code>String</code> system ID of
287 * referenced DTD
288 * @return the created DocType instance
289 * @since JDOM2
290 */
291 public DocType docType(int line, int col, String elementName,
292 String publicID, String systemID);
293
294 /**
295 * This will create the <code>DocType</code> with
296 * the specified element name and reference to an
297 * external DTD.
298 *
299 * @param line The line on which this content begins.
300 * @param col The column on the line at which this content begins.
301 * @param elementName <code>String</code> name of
302 * element being constrained.
303 * @param systemID <code>String</code> system ID of
304 * referenced DTD
305 * @return the created DocType instance
306 * @since JDOM2
307 */
308 public DocType docType(int line, int col, String elementName, String systemID);
309
310 /**
311 * This will create the <code>DocType</code> with
312 * the specified element name
313 *
314 * @param line The line on which this content begins.
315 * @param col The column on the line at which this content begins.
316 * @param elementName <code>String</code> name of
317 * element being constrained.
318 * @return the created DocType instance
319 * @since JDOM2
320 */
321 public DocType docType(int line, int col, String elementName);
322
323 // **** constructing Document
324
325 /**
326 * This will create a new <code>Document</code>,
327 * with the supplied <code>{@link org.jdom.Element}</code>
328 * as the root element and the supplied
329 * <code>{@link org.jdom.DocType}</code> declaration.
330 *
331 * @param rootElement <code>Element</code> for document root.
332 * @param docType <code>DocType</code> declaration.
333 * @return the created Document instance
334 */
335 public Document document(Element rootElement, DocType docType);
336
337 /**
338 * This will create a new <code>Document</code>,
339 * with the supplied <code>{@link org.jdom.Element}</code>
340 * as the root element and the supplied
341 * <code>{@link org.jdom.DocType}</code> declaration.
342 *
343 * @param rootElement <code>Element</code> for document root.
344 * @param docType <code>DocType</code> declaration.
345 * @param baseURI the URI from which this doucment was loaded.
346 * @return the created Document instance
347 */
348 public Document document(Element rootElement, DocType docType, String baseURI);
349
350 /**
351 * This will create a new <code>Document</code>,
352 * with the supplied <code>{@link org.jdom.Element}</code>
353 * as the root element, and no <code>{@link org.jdom.DocType}</code>
354 * declaration.
355 *
356 * @param rootElement <code>Element</code> for document root
357 * @return the created Document instance
358 */
359 public Document document(Element rootElement);
360
361 // **** constructing Elements ****
362
363 /**
364 * This will create a new <code>Element</code>
365 * with the supplied (local) name, and define
366 * the <code>{@link org.jdom.Namespace}</code> to be used.
367 *
368 * @param name <code>String</code> name of element.
369 * @param namespace <code>Namespace</code> to put element in.
370 * @return the created Element instance
371 */
372 public Element element(String name, Namespace namespace);
373
374 /**
375 * This will create an <code>Element</code> in no
376 * <code>{@link org.jdom.Namespace}</code>.
377 *
378 * @param name <code>String</code> name of element.
379 * @return the created Element instance
380 */
381 public Element element(String name);
382
383 /**
384 * This will create a new <code>Element</code> with
385 * the supplied (local) name, and specifies the URI
386 * of the <code>{@link org.jdom.Namespace}</code> the <code>Element</code>
387 * should be in, resulting it being unprefixed (in the default
388 * namespace).
389 *
390 * @param name <code>String</code> name of element.
391 * @param uri <code>String</code> URI for <code>Namespace</code> element
392 * should be in.
393 * @return the created Element instance
394 */
395 public Element element(String name, String uri);
396
397 /**
398 * This will create a new <code>Element</code> with
399 * the supplied (local) name, and specifies the prefix and URI
400 * of the <code>{@link org.jdom.Namespace}</code> the <code>Element</code>
401 * should be in.
402 *
403 * @param name <code>String</code> name of element.
404 * @param prefix the NamespacePrefic to use for this Element
405 * @param uri <code>String</code> URI for <code>Namespace</code> element
406 * should be in.
407 * @return the created Element instance
408 */
409 public Element element(String name, String prefix, String uri);
410
411 /**
412 * This will create a new <code>Element</code>
413 * with the supplied (local) name, and define
414 * the <code>{@link org.jdom.Namespace}</code> to be used.
415 *
416 * @param line The line on which this content begins.
417 * @param col The column on the line at which this content begins.
418 * @param name <code>String</code> name of element.
419 * @param namespace <code>Namespace</code> to put element in.
420 * @return the created Element instance
421 * @since JDOM2
422 */
423 public Element element(int line, int col, String name, Namespace namespace);
424
425 /**
426 * This will create an <code>Element</code> in no
427 * <code>{@link org.jdom.Namespace}</code>.
428 *
429 * @param line The line on which this content begins.
430 * @param col The column on the line at which this content begins.
431 * @param name <code>String</code> name of element.
432 * @return the created Element instance
433 * @since JDOM2
434 */
435 public Element element(int line, int col, String name);
436
437 /**
438 * This will create a new <code>Element</code> with
439 * the supplied (local) name, and specifies the URI
440 * of the <code>{@link org.jdom.Namespace}</code> the <code>Element</code>
441 * should be in, resulting it being unprefixed (in the default
442 * namespace).
443 *
444 * @param line The line on which this content begins.
445 * @param col The column on the line at which this content begins.
446 * @param name <code>String</code> name of element.
447 * @param uri <code>String</code> URI for <code>Namespace</code> element
448 * should be in.
449 * @return the created Element instance
450 * @since JDOM2
451 */
452 public Element element(int line, int col, String name, String uri);
453
454 /**
455 * This will create a new <code>Element</code> with
456 * the supplied (local) name, and specifies the prefix and URI
457 * of the <code>{@link org.jdom.Namespace}</code> the <code>Element</code>
458 * should be in.
459 *
460 * @param line The line on which this content begins.
461 * @param col The column on the line at which this content begins.
462 * @param name <code>String</code> name of element.
463 * @param prefix the NamespacePrefic to use for this Element
464 * @param uri <code>String</code> URI for <code>Namespace</code> element
465 * should be in.
466 * @return the created Element instance
467 * @since JDOM2
468 */
469 public Element element(int line, int col, String name, String prefix, String uri);
470
471 // **** constructing ProcessingInstruction ****
472
473 /**
474 * This will create a new <code>ProcessingInstruction</code>
475 * with the specified target and data.
476 *
477 * @param target <code>String</code> target of PI.
478 * @param data <code>Map</code> data for PI, in
479 * name/value pairs
480 * @return the created ProcessingInstruction instance
481 */
482 public ProcessingInstruction processingInstruction(String target,
483 Map<String,String> data);
484
485 /**
486 * This will create a new <code>ProcessingInstruction</code>
487 * with the specified target and data.
488 *
489 * @param target <code>String</code> target of PI.
490 * @param data <code>String</code> data for PI.
491 * @return the created ProcessingInstruction instance
492 */
493 public ProcessingInstruction processingInstruction(String target,
494 String data);
495
496 /**
497 * This will create a new <code>ProcessingInstruction</code>
498 * with the specified target and no data.
499 *
500 * @param target <code>String</code> target of PI.
501 * @return the created ProcessingInstruction instance
502 */
503 public ProcessingInstruction processingInstruction(String target);
504
505 /**
506 * This will create a new <code>ProcessingInstruction</code>
507 * with the specified target and data.
508 *
509 * @param line The line on which this content begins.
510 * @param col The column on the line at which this content begins.
511 * @param target <code>String</code> target of PI.
512 * @param data <code>Map</code> data for PI, in
513 * name/value pairs
514 * @return the created ProcessingInstruction instance
515 * @since JDOM2
516 */
517 public ProcessingInstruction processingInstruction(int line, int col, String target,
518 Map<String,String> data);
519
520 /**
521 * This will create a new <code>ProcessingInstruction</code>
522 * with the specified target and data.
523 *
524 * @param line The line on which this content begins.
525 * @param col The column on the line at which this content begins.
526 * @param target <code>String</code> target of PI.
527 * @param data <code>String</code> data for PI.
528 * @return the created ProcessingInstruction instance
529 * @since JDOM2
530 */
531 public ProcessingInstruction processingInstruction(int line, int col, String target,
532 String data);
533
534 /**
535 * This will create a new <code>ProcessingInstruction</code>
536 * with the specified target and no data.
537 *
538 * @param line The line on which this content begins.
539 * @param col The column on the line at which this content begins.
540 * @param target <code>String</code> target of PI.
541 * @return the created ProcessingInstruction instance
542 * @since JDOM2
543 */
544 public ProcessingInstruction processingInstruction(int line, int col, String target);
545
546 // **** constructing EntityRef ****
547
548 /**
549 * This will create a new <code>EntityRef</code>
550 * with the supplied name.
551 *
552 * @param name <code>String</code> name of element.
553 * @return the created EntityRef instance
554 */
555 public EntityRef entityRef(String name);
556
557 /**
558 * This will create a new <code>EntityRef</code>
559 * with the supplied name, public ID, and system ID.
560 *
561 * @param name <code>String</code> name of element.
562 * @param publicID <code>String</code> public ID of element.
563 * @param systemID <code>String</code> system ID of element.
564 * @return the created EntityRef instance
565 */
566 public EntityRef entityRef(String name, String publicID, String systemID);
567
568 /**
569 * This will create a new <code>EntityRef</code>
570 * with the supplied name and system ID.
571 *
572 * @param name <code>String</code> name of element.
573 * @param systemID <code>String</code> system ID of element.
574 * @return the created EntityRef instance
575 */
576 public EntityRef entityRef(String name, String systemID);
577
578 /**
579 * This will create a new <code>EntityRef</code>
580 * with the supplied name.
581 *
582 * @param line The line on which this content begins.
583 * @param col The column on the line at which this content begins.
584 * @param name <code>String</code> name of element.
585 * @return the created EntityRef instance
586 * @since JDOM2
587 */
588 public EntityRef entityRef(int line, int col, String name);
589
590 /**
591 * This will create a new <code>EntityRef</code>
592 * with the supplied name, public ID, and system ID.
593 *
594 * @param line The line on which this content begins.
595 * @param col The column on the line at which this content begins.
596 * @param name <code>String</code> name of element.
597 * @param publicID <code>String</code> public ID of element.
598 * @param systemID <code>String</code> system ID of element.
599 * @return the created EntityRef instance
600 * @since JDOM2
601 */
602 public EntityRef entityRef(int line, int col, String name, String publicID, String systemID);
603
604 /**
605 * This will create a new <code>EntityRef</code>
606 * with the supplied name and system ID.
607 *
608 * @param line The line on which this content begins.
609 * @param col The column on the line at which this content begins.
610 * @param name <code>String</code> name of element.
611 * @param systemID <code>String</code> system ID of element.
612 * @return the created EntityRef instance
613 * @since JDOM2
614 */
615 public EntityRef entityRef(int line, int col, String name, String systemID);
616
617 // =====================================================================
618 // List manipulation
619 // =====================================================================
620
621 /**
622 * This will add the specified content to the specified parent instance
623 * @param parent The {@link Parent} to add the content to.
624 * @param content The {@link Content} to add
625 */
626 public void addContent(Parent parent, Content content);
627
628 /**
629 * Sets a specific Attribute on an Element
630 * @param element The {@link Element} to set the Attribute on
631 * @param a The {@link Attribute} to set
632 */
633 public void setAttribute(Element element, Attribute a);
634
635 /**
636 * Adds a namespace declaration to an Element
637 * @param element The {@link Element} to add the Namespace to
638 * @param additional The {@link Namespace} to add.
639 */
640 public void addNamespaceDeclaration(Element element, Namespace additional);
641
642 /**
643 * Sets the 'root' Element for a Document.
644 * @param doc The {@link Document} to set the Root Element of.
645 * @param root The {@link Element} to set as the root.
646 */
647 public void setRoot(Document doc, Element root);
648 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import static org.jdom.JDOMConstants.*;
57
58 import java.io.InvalidObjectException;
59 import java.io.Serializable;
60 import java.util.concurrent.ConcurrentHashMap;
61 import java.util.concurrent.ConcurrentMap;
62
63 /**
64 * An XML namespace representation, as well as a factory for creating XML
65 * namespace objects. All methods on Namespace (including
66 * {@link #getNamespace(String)} and {@link #getNamespace(String, String)})
67 * are thread-safe.
68 *
69 * <p>
70 * See {@link NamespaceAware} for additional notes on how Namespaces are
71 * 'in-scope' in JDOM content, and how those in-scope Namespaces are accessed.
72 *
73 * @see NamespaceAware
74 * @author Brett McLaughlin
75 * @author Elliotte Rusty Harold
76 * @author Jason Hunter
77 * @author Wesley Biggs
78 * @author Rolf Lear
79 */
80 public final class Namespace implements Serializable {
81
82 /**
83 * Factory list of namespaces.
84 * Keys are <i>URI</i>&amp;<i>prefix</i>.
85 * Values are Namespace objects
86 */
87
88 private static final ConcurrentMap<String, ConcurrentMap<String, Namespace>>
89 namespacemap = new ConcurrentHashMap
90 <String, ConcurrentMap<String,Namespace>>(512, 0.75f, 64);
91
92 /** Define a <code>Namespace</code> for when <i>not</i> in a namespace */
93 public static final Namespace NO_NAMESPACE = new Namespace(NS_PREFIX_DEFAULT,
94 NS_URI_DEFAULT);
95
96 /** Define a <code>Namespace</code> for the standard xml prefix. */
97 public static final Namespace XML_NAMESPACE = new Namespace(NS_PREFIX_XML,
98 NS_URI_XML);
99
100 private static final Namespace XMLNS_NAMESPACE = new Namespace(NS_PREFIX_XMLNS,
101 NS_URI_XMLNS);
102
103 static {
104 // pre-populate the map with the constant namespaces that would
105 // otherwise fail validation
106 final ConcurrentMap<String,Namespace> nmap =
107 new ConcurrentHashMap<String, Namespace>();
108 nmap.put(NO_NAMESPACE.getPrefix(), NO_NAMESPACE);
109 namespacemap.put(NO_NAMESPACE.getURI(), nmap);
110
111 final ConcurrentMap<String,Namespace> xmap =
112 new ConcurrentHashMap<String, Namespace>();
113 xmap.put(XML_NAMESPACE.getPrefix(), XML_NAMESPACE);
114 namespacemap.put(XML_NAMESPACE.getURI(), xmap);
115
116 final ConcurrentMap<String,Namespace> xnsmap =
117 new ConcurrentHashMap<String, Namespace>();
118 xnsmap.put(XMLNS_NAMESPACE.getPrefix(), XMLNS_NAMESPACE);
119 namespacemap.put(XMLNS_NAMESPACE.getURI(), xnsmap);
120 }
121
122 /**
123 * This will retrieve (if in existence) or create (if not) a
124 * <code>Namespace</code> for the supplied <i>prefix</i> and <i>uri</i>.
125 * This method is thread-safe.
126 *
127 * @param prefix <code>String</code> prefix to map to
128 * <code>Namespace</code>.
129 * @param uri <code>String</code> URI of new <code>Namespace</code>.
130 * @return <code>Namespace</code> - ready to use namespace.
131 * @throws IllegalNameException if the given prefix and uri make up
132 * an illegal namespace name.
133 * @see Verifier#checkNamespacePrefix(String)
134 * @see Verifier#checkNamespaceURI(String)
135 */
136 public static Namespace getNamespace(final String prefix, final String uri) {
137
138 // This is a rewrite of the JDOM 1 getNamespace() to use
139 // java.util.concurrent. The motivation is:
140 // 1. avoid having to create a new NamespaceKey for each query.
141 // 2. avoid a 'big' synchronisation bottleneck in the Namespace class.
142 // 3. no-memory-lookup for pre-existing Namespaces... (avoid 'new' and
143 // most String methods that allocte memory (like trim())
144
145 if (uri == null) {
146 if (prefix == null || NS_PREFIX_DEFAULT.equals(prefix)) {
147 return NO_NAMESPACE;
148 }
149 // we have an attempt for some prefix
150 // (not "" or it would have found NO_NAMESPACE) on the null URI
151 throw new IllegalNameException("", "namespace",
152 "Namespace URIs must be non-null and non-empty Strings");
153 }
154
155 // must have checked for 'null' uri else namespacemap throws NPE
156 // do not 'trim' uri's any more see issue #50
157 ConcurrentMap<String, Namespace> urimap = namespacemap.get(uri);
158 if (urimap == null) {
159 // no Namespaces yet with that URI.
160 // Ensure proper naming
161 String reason;
162 if ((reason = Verifier.checkNamespaceURI(uri)) != null) {
163 throw new IllegalNameException(uri, "Namespace URI", reason);
164 }
165
166 urimap = new ConcurrentHashMap<String, Namespace>();
167 final ConcurrentMap<String, Namespace> xmap =
168 namespacemap.putIfAbsent(uri, urimap);
169
170 if (xmap != null) {
171 // some other thread registered this URI between when we
172 // first checked, and when we got a new map created.
173 // we must use the already-registered value.
174 urimap = xmap;
175 }
176 }
177
178 // OK, we have a container for the URI, let's search on the prefix.
179
180 Namespace ns = urimap.get(prefix == null ? NS_PREFIX_DEFAULT : prefix);
181 if (ns != null) {
182 // got one.
183 return ns;
184 }
185
186 // OK, no namespace yet for that uri/prefix
187 // validate the prefix (the uri is already validated).
188
189 if (NS_URI_DEFAULT.equals(uri)) {
190 // we have an attempt for some prefix
191 // (not "" or it would have found NO_NAMESPACE) on the "" URI
192 // note, we have already done this check for 'null' uri above.
193 throw new IllegalNameException("", "namespace",
194 "Namespace URIs must be non-null and non-empty Strings");
195 }
196
197 // http://www.w3.org/TR/REC-xml-names/#xmlReserved
198 // The erratum to Namespaces in XML 1.0 that suggests this
199 // next check is controversial. Not everyone accepts it.
200 if (NS_URI_XML.equals(uri)) {
201 throw new IllegalNameException(uri, "Namespace URI",
202 "The " + NS_URI_XML + " must be bound to " +
203 "only the '" + NS_PREFIX_XML + "' prefix.");
204 }
205
206 // http://www.w3.org/TR/REC-xml-names/#xmlReserved
207 if (NS_URI_XMLNS.equals(uri)) {
208 throw new IllegalNameException(uri, "Namespace URI",
209 "The " + NS_URI_XMLNS + " must be bound to " +
210 "only the '" + NS_PREFIX_XMLNS + "' prefix.");
211 }
212
213 // no namespace found, we validate the prefix
214 final String pfx = prefix == null ? NS_PREFIX_DEFAULT : prefix;
215
216 String reason;
217
218 // http://www.w3.org/TR/REC-xml-names/#xmlReserved
219 // checkNamespacePrefix no longer checks for xml prefix
220 if (NS_PREFIX_XML.equals(pfx)) {
221 // The xml namespace prefix was in the map. attempts to rebind it are illegal
222 throw new IllegalNameException(uri, "Namespace prefix",
223 "The prefix " + NS_PREFIX_XML + " (any case) can only be bound to " +
224 "only the '" + NS_URI_XML + "' uri.");
225 }
226
227 // http://www.w3.org/TR/REC-xml-names/#xmlReserved
228 // checkNamespacePrefix no longer checks for xmlns prefix
229 if (NS_PREFIX_XMLNS.equals(pfx)) {
230 // The xml namespace prefix was in the map. attempts to rebind it are illegal
231 throw new IllegalNameException(uri, "Namespace prefix",
232 "The prefix " + NS_PREFIX_XMLNS + " (any case) can only be bound to " +
233 "only the '" + NS_URI_XMLNS + "' uri.");
234 }
235
236 if ((reason = Verifier.checkNamespacePrefix(pfx)) != null) {
237 throw new IllegalNameException(pfx, "Namespace prefix", reason);
238 }
239
240 // OK, good bet that we have a new Namespace.
241 ns = new Namespace(pfx, uri);
242 final Namespace prev = urimap.putIfAbsent(pfx, ns);
243 if (prev != null) {
244 // someone registered the same namespace as us while we were busy
245 // validating. Use their registered copy.
246 ns = prev;
247 }
248 return ns;
249 }
250
251 /** The prefix mapped to this namespace */
252 private final transient String prefix;
253
254 /** The URI for this namespace */
255 private final transient String uri;
256
257 /**
258 * This will retrieve (if in existence) or create (if not) a
259 * <code>Namespace</code> for the supplied URI, and make it usable
260 * as a default namespace, as no prefix is supplied.
261 * This method is thread-safe.
262 *
263 * @param uri <code>String</code> URI of new <code>Namespace</code>.
264 * @return <code>Namespace</code> - ready to use namespace.
265 */
266 public static Namespace getNamespace(final String uri) {
267 return getNamespace(NS_PREFIX_DEFAULT, uri);
268 }
269
270 /**
271 * This constructor handles creation of a <code>Namespace</code> object
272 * with a prefix and URI; it is intentionally left <code>private</code>
273 * so that it cannot be invoked by external programs/code.
274 *
275 * @param prefix <code>String</code> prefix to map to this namespace.
276 * @param uri <code>String</code> URI for namespace.
277 */
278 private Namespace(final String prefix, final String uri) {
279 this.prefix = prefix;
280 this.uri = uri;
281 }
282
283 /**
284 * This returns the prefix mapped to this <code>Namespace</code>.
285 *
286 * @return <code>String</code> - prefix for this <code>Namespace</code>.
287 */
288 public String getPrefix() {
289 return prefix;
290 }
291
292 /**
293 * This returns the namespace URI for this <code>Namespace</code>.
294 *
295 * @return <code>String</code> - URI for this <code>Namespace</code>.
296 */
297 public String getURI() {
298 return uri;
299 }
300
301 /**
302 * This tests for equality - Two <code>Namespaces</code>
303 * are equal if and only if their URIs are byte-for-byte equals.
304 *
305 * @param ob <code>Object</code> to compare to this <code>Namespace</code>.
306 * @return <code>boolean</code> - whether the supplied object is equal to
307 * this <code>Namespace</code>.
308 */
309 @Override
310 public boolean equals(final Object ob) {
311 if (this == ob) {
312 return true;
313 }
314 if (ob instanceof Namespace) { // instanceof returns false if null
315 return uri.equals(((Namespace)ob).uri);
316 }
317 return false;
318 }
319
320 /**
321 * This returns a <code>String</code> representation of this
322 * <code>Namespace</code>, suitable for use in debugging.
323 *
324 * @return <code>String</code> - information about this instance.
325 */
326 @Override
327 public String toString() {
328 return "[Namespace: prefix \"" + prefix + "\" is mapped to URI \"" +
329 uri + "\"]";
330 }
331
332 /**
333 * This returns the hash code for the <code>Namespace</code> that conforms
334 * to the 'equals()' contract.
335 * <p>
336 * If two namespaces have the same URI, they are equal and have the same
337 * hash code, even if they have different prefixes.
338 *
339 * @return <code>int</code> - hash code for this <code>Namespace</code>.
340 */
341 @Override
342 public int hashCode() {
343 return uri.hashCode();
344 }
345
346
347 /* *****************************************
348 * Serialization
349 * ***************************************** */
350
351 /**
352 * JDOM 2.0.0 Serialization version
353 */
354 private static final long serialVersionUID = 200L;
355
356 private static final class NamespaceSerializationProxy
357 implements Serializable {
358
359 private static final long serialVersionUID = 200L;
360 private final String pprefix, puri;
361 public NamespaceSerializationProxy(String pprefix, String puri) {
362 this.pprefix = pprefix;
363 this.puri = puri;
364 }
365
366 private Object readResolve() {
367 return Namespace.getNamespace(pprefix, puri);
368 }
369
370 }
371
372 /**
373 * Serializes Namespace by using a proxy serialization instance.
374 * @serialData The proxy deals with the protocol.
375 * @return the Namespace proxy instance.
376 */
377 private Object writeReplace() {
378 return new NamespaceSerializationProxy(prefix, uri);
379 }
380
381 /**
382 * Because Namespace is serialized by proxy, the reading of direct Namespace
383 * instances is illegal and prohibited.
384 * @return nothing.
385 * @throws InvalidObjectException always
386 */
387 private Object readResolve() throws InvalidObjectException {
388 throw new InvalidObjectException(
389 "Namespace is serialized through a proxy");
390 }
391
392 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.List;
57
58 /**
59 * Classes implementing this interface are all sensitive to their
60 * {@link Namespace} context. All the core JDOM classes are NamespaceAware
61 * ({@link Parent} and subtypes, {@link Content} and subtypes, and
62 * {@link Attribute}). You can use the methods that this interface provides
63 * to query the Namespace context.
64 * <p>
65 * JDOM2 introduces a consistency in reporting Namespace context. XML standards
66 * do not dictate any conditions on Namespace reporting or ordering, but
67 * consistency is valuable for user-friendliness. As a result JDOM2 imposes a
68 * useful order on the Namespace context for XML content.
69 * <p>
70 * The order for Namespace reporting is:
71 * <ol>
72 * <li>If the item 'has' a Namespace (Element, Attribute) then that Namespace is
73 * reported.
74 * <li>The remaining Namespaces are reported in alphabetical order by prefix.
75 * </ol>
76 * <p>
77 * The XML namespace (bound to the prefix "xml" - see
78 * {@link Namespace#XML_NAMESPACE} ) is always in every scope. It is always
79 * introduced in {@link Document}, and in all other NamespaceAware instances it
80 * is introduced if that content is detached.
81 * <p>
82 * See the individualised documentation for each implementing type for
83 * additional specific details. The following section is a description of how
84 * Namespaces are managed in the Element class.
85 * <p>
86 * <h2>The Element Namespace Scope</h2>
87 * The 'default' Namespace is a source of confusion, but it is simply the
88 * Namespace which is in-scope for an Element that has no Namespace prefix
89 * (prefix is "" but it could have any Namespace URI). There will always be
90 * exactly one Namespace that is in-scope for an element that has no prefix.
91 * <p>
92 * All Elements are in a Namespace. Elements will be in
93 * {@link Namespace#NO_NAMESPACE} unless a different Namespace was supplied as
94 * part of the Element Constructor, or later modified by the
95 * {@link Element#setNamespace(Namespace)} method.
96 * <p>
97 * In addition to the Element's Namespace, there could be other Namespaces that
98 * are 'in scope' for the Element. The set of Namespaces that are in scope for
99 * an Element is the union of five sets:
100 * <table>
101 * <tr>
102 * <th valign="top">XML</th>
103 * <td>
104 * There is always exactly one member of this set,
105 * {@link Namespace#XML_NAMESPACE}.
106 * <br>
107 * This set cannot be changed.
108 * </td>
109 * </tr>
110 * <tr>
111 * <th valign="top">Element</th>
112 * <td>
113 * There is always exactly one member of this set, and it can be retrieved
114 * or set with the methods {@link Element#getNamespace()} and
115 * {@link Element#setNamespace(Namespace)} respectively.
116 * </td>
117 * </tr>
118 * <tr>
119 * <th valign="top">Attribute</th>
120 * <td>
121 * This is the set of distinct Namespaces that are used on Attributes. You
122 * can modify the set by adding and removing Attributes to the Element.
123 * <p>
124 * <b>NOTE:</b>
125 * The {@link Namespace#NO_NAMESPACE Namespace.NO_NAMESPACE} Namespace is always the
126 * <i>default</i> Namespace for attributes (the Namespace that has no
127 * prefix). Thus there may be a special case with this Namespace, because
128 * if there is a different <i>default</i> Namespace for the Element, then
129 * the Namespace.NO_NAMESPACE Namespace is not part of the Element's in-scope
130 * Namespace set (the Element cannot have two Namespaces in scope with the
131 * same prefix - "").
132 * </td>
133 * </tr>
134 * <tr>
135 * <th valign="top">Additional</th>
136 * <td>
137 * This set is maintained by the two methods {@link Element#addNamespaceDeclaration(Namespace)}
138 * and {@link Element#removeNamespaceDeclaration(Namespace)}. You can get the full set
139 * of additional Namespaces with {@link Element#getAdditionalNamespaces()}
140 * </td>
141 * </tr>
142 * <tr>
143 * <th valign="top">Inherited</th>
144 * <td>
145 * This last set is somewhat dynamic because only those Namespaces on the
146 * parent Element which are not re-defined by this Element will be
147 * inherited. A Namespace is redefined by setting a new Namespace with the
148 * same prefix, but a different URI. If you set a Namespace on the Element
149 * (or add a Namespace declaration or set an Attribute) with the same
150 * prefix as another Namespace that would have been otherwise inherited,
151 * then that other Namespace will no longer be inherited.
152 * </td>
153 * </tr>
154 * </table>
155 *
156 * <p>
157 * Since you cannot change the Namespace.XML_NAMESPACE, and the 'inherited' Namespace set
158 * is dynamic, the remaining Namespace sets are the most interesting from a JDOM
159 * perspective. JDOM validates all modifications that affect the Namespaces in
160 * scope for an Element. An IllegalAddException will be thrown if you attempt to
161 * add a new Namespace to the in-scope set if a different Namespace with the
162 * same prefix is already part of one of these three sets (Element, Attribute,
163 * or Additional).
164 *
165 *
166 * @author Rolf Lear
167 * @since JDOM2
168 */
169 public interface NamespaceAware {
170
171 /**
172 * Obtain a list of all namespaces that are in scope for the current
173 * content.
174 * <p>
175 * The contents of this list will always be the combination of
176 * getNamespacesIntroduced() and getNamespacesInherited().
177 * <p>
178 * See {@link NamespaceAware} documentation for details on what the order of the
179 * Namespaces will be in the returned list.
180 *
181 * @return a read-only list of Namespaces.
182 */
183 public List<Namespace> getNamespacesInScope();
184
185 /**
186 * Obtain a list of all namespaces that are introduced to the XML tree by
187 * this node. Only Elements and Attributes can introduce namespaces, so all
188 * other Content types will return an empty list.
189 * <p>
190 * The contents of this list will always be a subset (but in the same order)
191 * of getNamespacesInScope(), and will never intersect
192 * getNamspacesInherited()
193 *
194 * @return a read-only list of Namespaces.
195 */
196 public List<Namespace> getNamespacesIntroduced();
197
198 /**
199 * Obtain a list of all namespaces that are in scope for this content, but
200 * were not introduced by this content.
201 * <p>
202 * The contents of this list will always be a subset (but in the same order)
203 * of getNamespacesInScope(), and will never intersect
204 * getNamspacesIntroduced()
205 *
206 * @return a read-only list of Namespaces.
207 */
208 public List<Namespace> getNamespacesInherited();
209 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import org.jdom.filter.Filter;
57
58 import java.io.Serializable;
59 import java.util.*;
60
61 /**
62 * Interface for JDOM objects which are allowed to contain
63 * {@link Content} content - {@link Element} and {@link Document}.
64 *
65 * @see org.jdom.Content
66 * @see org.jdom.Document
67 * @see org.jdom.Element
68 *
69 * @author Bradley S. Huffman
70 * @author Jason Hunter
71 * @author Rolf Lear
72 */
73 public interface Parent extends Cloneable, NamespaceAware, Serializable {
74
75 /**
76 * Returns the number of children in this parent's content list.
77 * Children may be any {@link Content} type.
78 *
79 * @return number of children
80 */
81 int getContentSize();
82
83 /**
84 * Returns the index of the supplied child in the content list,
85 * or -1 if not a child of this parent.
86 *
87 * @param child child to search for
88 * @return index of child, or -1 if not found
89 */
90 int indexOf(Content child);
91
92 // /**
93 // * Starting at the given index (inclusive), returns the index of
94 // * the first child matching the supplied filter, or -1
95 // * if none is found.
96 // *
97 // * @return index of child, or -1 if none found
98 // */
99 // int indexOf(int index, Filter filter);
100
101 /**
102 * Returns a list containing detached clones of this parent's content list.
103 *
104 * @return list of cloned child content
105 */
106 List<Content> cloneContent();
107
108 /**
109 * Returns the child at the given index.
110 *
111 * @param index location of desired child
112 * @return child at the given index
113 * @throws IndexOutOfBoundsException if index is negative or beyond
114 * the current number of children
115 * @throws IllegalStateException if parent is a Document
116 * and the root element is not set
117 */
118 Content getContent(int index);
119
120 /**
121 * Returns the full content of this parent as a {@link java.util.List}
122 * which contains objects of type {@link Content}. The returned list is
123 * <b>"live"</b> and in document order. Any modifications
124 * to it affect the element's actual contents. Modifications are checked
125 * for conformance to XML 1.0 rules.
126 * <p>
127 * Sequential traversal through the List is best done with an Iterator
128 * since the underlying implement of {@link java.util.List#size} may
129 * require walking the entire list and indexed lookups may require
130 * starting at the beginning each time.
131 *
132 * @return a list of the content of the parent
133 * @throws IllegalStateException if parent is a Document
134 * and the root element is not set
135 */
136 List<Content> getContent();
137
138 /**
139 * Returns as a {@link java.util.List} the content of
140 * this parent that matches the supplied filter. The returned list is
141 * <b>"live"</b> and in document order. Any modifications to it affect
142 * the element's actual contents. Modifications are checked for
143 * conformance to XML 1.0 rules.
144 * <p>
145 * Sequential traversal through the List is best done with an Iterator
146 * since the underlying implement of {@link java.util.List#size} may
147 * require walking the entire list and indexed lookups may require
148 * starting at the beginning each time.
149 * @param <E> The Generic type of the returned content (the Filter's type)
150 *
151 * @param filter filter to apply.
152 * Note that the {@link Filters} class has a number of predefined, useful
153 * filters.
154 * @return a list of the content of the parent matching the filter
155 * @throws IllegalStateException if parent is a Document
156 * and the root element is not set
157 */
158 <E extends Content> List<E> getContent(Filter<E> filter);
159
160 /**
161 * Removes all content from this parent and returns the detached
162 * children.
163 *
164 * @return list of the old content detached from this parent
165 */
166 List<Content> removeContent();
167
168 /**
169 * Removes from this parent all child content matching the given filter
170 * and returns a list of the detached children.
171 * @param <E> The Generic type of the content to remove.
172 *
173 * @param filter filter to apply
174 * Note that the {@link Filters} class has a number of predefined, useful
175 * filters.
176 * @return list of the detached children matching the filter
177 */
178 <E extends Content> List<E> removeContent(Filter<E> filter);
179
180 /**
181 * Removes a single child node from the content list.
182 *
183 * @param child child to remove
184 * @return whether the removal occurred
185 */
186 boolean removeContent(Content child);
187
188 /**
189 * Removes and returns the child at the given
190 * index, or returns null if there's no such child.
191 *
192 * @param index index of child to remove
193 * @return detached child at given index or null if no
194 * @throws IndexOutOfBoundsException if index is negative or beyond
195 * the current number of children
196 */
197 Content removeContent(int index);
198
199 /**
200 * Obtain a deep, unattached copy of this parent and it's children.
201 *
202 * @return a deep copy of this parent and it's children.
203 */
204 Parent clone();
205
206 /**
207 * Returns an {@link java.util.Iterator} that walks over all descendants
208 * in document order.
209 * <p>
210 * Note that this method returns an IteratorIterable instance, which means
211 * that you can use it either as an Iterator, or an Iterable, allowing both:
212 * <p>
213 * <pre>
214 * for (Iterator<Content> it = parent.getDescendants();
215 * it.hasNext();) {
216 * Content c = it.next();
217 * ....
218 * }
219 * </pre>
220 * and
221 * <pre>
222 * for (Content c : parent.getDescendants()) {
223 * ....
224 * }
225 * </pre>
226 * The Iterator version is most useful if you need to do list modification
227 * on the iterator (using remove()), and for compatibility with JDOM 1.x
228 *
229 * @return an iterator to walk descendants
230 */
231 Iterator<Content> getDescendants();
232
233 /**
234 * Returns an {@link java.util.Iterator} that walks over all descendants
235 * in document order applying the Filter to return only content that
236 * match the filter rule. With filters you can match only Elements,
237 * only Comments, Elements or Comments, only Elements with a given name
238 * and/or prefix, and so on.
239 * <p>
240 * Note that this method returns an IteratorIterable instance, which means
241 * that you can use it either as an Iterator, or an Iterable, allowing both:
242 * <p>
243 * <pre>
244 * for (Iterator<Element> it = parent.getDescendants(Filters.element());
245 * it.hasNext();) {
246 * Element e = it.next();
247 * ....
248 * }
249 * </pre>
250 * and
251 * <pre>
252 * for (Element e : parent.getDescendants(Filters.element())) {
253 * ....
254 * }
255 * </pre>
256 * The Iterator version is most useful if you need to do list modification
257 * on the iterator (using remove()), and for compatibility with JDOM 1.x
258 *
259 * @param <E> The generic type of the returned descendant data
260 * @param filter filter to select which descendants to see
261 * Note that the {@link Filters} class has a number of predefined, useful
262 * filters.
263 * @return an iterator to walk descendants that match a filter
264 */
265 <E extends Content> Iterator<E> getDescendants(Filter<E> filter);
266
267 /**
268 * Return this parent's parent, or null if this parent is currently
269 * not attached to another parent. This is the same method as in Content but
270 * also added to Parent to allow more easy up-the-tree walking.
271 *
272 * @return this parent's parent or null if none
273 */
274 Parent getParent();
275
276 /**
277 * Return this parent's owning document or null if the branch containing
278 * this parent is currently not attached to a document.
279 *
280 * @return this child's owning document or null if none
281 */
282 Document getDocument();
283
284 /**
285 * Test whether this Parent instance can contain the specified content
286 * at the specified position.
287 * @param content The content to be checked
288 * @param index The location where the content would be put.
289 * @param replace true if the intention is to replace the content already at
290 * the index.
291 * @throws IllegalAddException if there is a problem with the content
292 */
293 void canContainContent(Content content, int index, boolean replace) throws IllegalAddException;
294
295 /**
296 * Appends the child to the end of the content list.
297 *
298 * @param child child to append to end of content list
299 * @return the Parent instance on which the method was called
300 * @throws IllegalAddException if the given child already has a parent.
301 */
302 public Parent addContent(Content child);
303
304 /**
305 * Appends all children in the given collection to the end of
306 * the content list. In event of an exception during add the
307 * original content will be unchanged and the objects in the supplied
308 * collection will be unaltered.
309 *
310 * @param c collection to append
311 * @return the document on which the method was called
312 * @throws IllegalAddException if any item in the collection
313 * already has a parent or is of an illegal type.
314 */
315 public Parent addContent(Collection<? extends Content> c);
316
317 /**
318 * Inserts the child into the content list at the given index.
319 *
320 * @param index location for adding the collection
321 * @param child child to insert
322 * @return the parent on which the method was called
323 * @throws IndexOutOfBoundsException if index is negative or beyond
324 * the current number of children
325 * @throws IllegalAddException if the given child already has a parent.
326 */
327 public Parent addContent(int index, Content child);
328
329 /**
330 * Inserts the content in a collection into the content list
331 * at the given index. In event of an exception the original content
332 * will be unchanged and the objects in the supplied collection will be
333 * unaltered.
334 *
335 * @param index location for adding the collection
336 * @param c collection to insert
337 * @return the parent on which the method was called
338 * @throws IndexOutOfBoundsException if index is negative or beyond
339 * the current number of children
340 * @throws IllegalAddException if any item in the collection
341 * already has a parent or is of an illegal type.
342 */
343 public Parent addContent(int index, Collection<? extends Content> c);
344
345 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import org.jdom.output.XMLOutputter2;
57
58 import java.util.*;
59
60 /**
61 * An XML processing instruction. Methods allow the user to obtain the target of
62 * the PI as well as its data. The data can always be accessed as a String or,
63 * if the data appears akin to an attribute list, can be retrieved as name/value
64 * pairs.
65 *
66 * @author Brett McLaughlin
67 * @author Jason Hunter
68 * @author Steven Gould
69 */
70
71 public class ProcessingInstruction extends Content {
72
73 /**
74 * JDOM2 Serialization. In this case, ProcessingInstruction is simple.
75 */
76 private static final long serialVersionUID = 200L;
77
78 /** The target of the PI */
79 protected String target;
80
81 /** The data for the PI as a String */
82 protected String rawData;
83
84 /** The data for the PI in name/value pairs */
85 protected transient Map<String,String> mapData = null;
86
87 /**
88 * Default, no-args constructor for implementations
89 * to use if needed.
90 */
91 protected ProcessingInstruction() {
92 super(CType.ProcessingInstruction);
93 }
94
95 /**
96 * This will create a new <code>ProcessingInstruction</code>
97 * with the specified target.
98 *
99 * @param target <code>String</code> target of PI.
100 * @throws IllegalTargetException if the given target is illegal
101 * as a processing instruction name.
102 */
103 public ProcessingInstruction(String target) {
104 this(target, "");
105 }
106
107 /**
108 * This will create a new <code>ProcessingInstruction</code>
109 * with the specified target and data.
110 *
111 * @param target <code>String</code> target of PI.
112 * @param data <code>Map</code> data for PI, in
113 * name/value pairs
114 * @throws IllegalTargetException if the given target is illegal
115 * as a processing instruction name.
116 */
117 public ProcessingInstruction(String target, Map<String,String> data) {
118 super(CType.ProcessingInstruction);
119 setTarget(target);
120 setData(data);
121 }
122
123 /**
124 * This will create a new <code>ProcessingInstruction</code>
125 * with the specified target and data.
126 *
127 * @param target <code>String</code> target of PI.
128 * @param data <code>String</code> data for PI.
129 * @throws IllegalTargetException if the given target is illegal
130 * as a processing instruction name.
131 */
132 public ProcessingInstruction(String target, String data) {
133 super(CType.ProcessingInstruction);
134 setTarget(target);
135 setData(data);
136 }
137
138 /**
139 * This will set the target for the PI.
140 *
141 * @param newTarget <code>String</code> new target of PI.
142 * @return <code>ProcessingInstruction</code> - this PI modified.
143 */
144 public ProcessingInstruction setTarget(String newTarget) {
145 String reason;
146 if ((reason = Verifier.checkProcessingInstructionTarget(newTarget))
147 != null) {
148 throw new IllegalTargetException(newTarget, reason);
149 }
150
151 target = newTarget;
152 return this;
153 }
154
155 /**
156 * Returns the XPath 1.0 string value of this element, which is the
157 * data of this PI.
158 *
159 * @return the data of this PI
160 */
161 @Override
162 public String getValue() {
163 return rawData;
164 }
165
166
167 /**
168 * This will retrieve the target of the PI.
169 *
170 * @return <code>String</code> - target of PI.
171 */
172 public String getTarget() {
173 return target;
174 }
175
176 /**
177 * This will return the raw data from all instructions.
178 *
179 * @return <code>String</code> - data of PI.
180 */
181 public String getData() {
182 return rawData;
183 }
184
185 /**
186 * This will return a <code>List</code> containing the names of the
187 * "attribute" style pieces of name/value pairs in this PI's data.
188 *
189 * @return <code>List</code> - the <code>List</code> containing the
190 * "attribute" names.
191 */
192 public List<String> getPseudoAttributeNames() {
193 return new ArrayList<String>(mapData.keySet());
194 }
195
196 /**
197 * This will set the raw data for the PI.
198 *
199 * @param data <code>String</code> data of PI.
200 * @return <code>ProcessingInstruction</code> - this PI modified.
201 */
202 public ProcessingInstruction setData(String data) {
203 String reason = Verifier.checkProcessingInstructionData(data);
204 if (reason != null) {
205 throw new IllegalDataException(data, reason);
206 }
207
208 this.rawData = data;
209 this.mapData = parseData(data);
210 return this;
211 }
212
213 /**
214 * This will set the name/value pairs within the passed
215 * <code>Map</code> as the pairs for the data of
216 * this PI. The keys should be the pair name
217 * and the values should be the pair values.
218 *
219 * @param data new map data to use
220 * @return <code>ProcessingInstruction</code> - modified PI.
221 */
222 public ProcessingInstruction setData(Map<String,String> data) {
223 String temp = toString(data);
224
225 String reason = Verifier.checkProcessingInstructionData(temp);
226 if (reason != null) {
227 throw new IllegalDataException(temp, reason);
228 }
229
230 this.rawData = temp;
231 this.mapData = new LinkedHashMap<String,String>(data);
232 return this;
233 }
234
235
236 /**
237 * This will return the value for a specific
238 * name/value pair on the PI. If no such pair is
239 * found for this PI, null is returned.
240 *
241 * @param name <code>String</code> name of name/value pair
242 * to lookup value for.
243 * @return <code>String</code> - value of name/value pair.
244 */
245 public String getPseudoAttributeValue(String name) {
246 return mapData.get(name);
247 }
248
249 /**
250 * This will set a pseudo attribute with the given name and value.
251 * If the PI data is not already in a pseudo-attribute format, this will
252 * replace the existing data.
253 *
254 * @param name <code>String</code> name of pair.
255 * @param value <code>String</code> value for pair.
256 * @return <code>ProcessingInstruction</code> this PI modified.
257 */
258 public ProcessingInstruction setPseudoAttribute(String name, String value) {
259 String reason = Verifier.checkProcessingInstructionData(name);
260 if (reason != null) {
261 throw new IllegalDataException(name, reason);
262 }
263
264 reason = Verifier.checkProcessingInstructionData(value);
265 if (reason != null) {
266 throw new IllegalDataException(value, reason);
267 }
268
269 this.mapData.put(name, value);
270 this.rawData = toString(mapData);
271 return this;
272 }
273
274
275 /**
276 * This will remove the pseudo attribute with the specified name.
277 *
278 * @param name name of pseudo attribute to remove
279 * @return <code>boolean</code> - whether the requested
280 * instruction was removed.
281 */
282 public boolean removePseudoAttribute(String name) {
283 if ((mapData.remove(name)) != null) {
284 rawData = toString(mapData);
285 return true;
286 }
287
288 return false;
289 }
290
291 /**
292 * This will convert the Map to a string representation.
293 *
294 * @param pmapData <code>Map</code> PI data to convert
295 * @return a string representation of the Map as appropriate for a PI
296 */
297 private static final String toString(Map<String,String> pmapData) {
298 StringBuilder stringData = new StringBuilder();
299
300 for (Map.Entry<String,String> me : pmapData.entrySet()) {
301 stringData.append(me.getKey())
302 .append("=\"")
303 .append(me.getValue())
304 .append("\" ");
305 }
306 // Remove last space, if we did any appending
307 if (stringData.length() > 0) {
308 stringData.setLength(stringData.length() - 1);
309 }
310
311 return stringData.toString();
312 }
313
314 /**
315 * This will parse and load the instructions for the PI.
316 * This is separated to allow it to occur once and then be reused.
317 */
318 private Map<String,String> parseData(String prawData) {
319 // The parsing here is done largely "by hand" which means the code
320 // gets a little tricky/messy. The following conditions should
321 // now be handled correctly:
322 // <?pi href="http://hi/a=b"?> Reads OK
323 // <?pi href = 'http://hi/a=b' ?> Reads OK
324 // <?pi href\t = \t'http://hi/a=b'?> Reads OK
325 // <?pi href = "http://hi/a=b"?> Reads OK
326 // <?pi?> Empty Map
327 // <?pi id=22?> Empty Map
328 // <?pi id='22?> Empty Map
329
330 Map<String,String> data = new LinkedHashMap<String,String>();
331
332 // System.out.println("rawData: " + rawData);
333
334 // The inputData variable holds the part of rawData left to parse
335 String inputData = prawData.trim();
336
337 // Iterate through the remaining inputData string
338 while (!inputData.trim().equals("")) {
339 //System.out.println("parseData() looking at: " + inputData);
340
341 // Search for "name =", "name=" or "name1 name2..."
342 String name = "";
343 String value = "";
344 int startName = 0;
345 char previousChar = inputData.charAt(startName);
346 int pos = 1;
347 for (; pos<inputData.length(); pos++) {
348 char currentChar = inputData.charAt(pos);
349 if (currentChar == '=') {
350 name = inputData.substring(startName, pos).trim();
351 // Get the boundaries on the quoted string
352 // We use boundaries so we know where to start next
353 int[] bounds = extractQuotedString(
354 inputData.substring(pos+1));
355 // A null value means a parse error and we return empty!
356 if (bounds == null) {
357 return Collections.emptyMap();
358 }
359 value = inputData.substring(bounds[0]+pos+1,
360 bounds[1]+pos+1);
361 pos += bounds[1] + 1; // skip past value
362 break;
363 }
364 else if (Character.isWhitespace(previousChar)
365 && !Character.isWhitespace(currentChar)) {
366 startName = pos;
367 }
368
369 previousChar = currentChar;
370 }
371
372 // Remove the first pos characters; they have been processed
373 inputData = inputData.substring(pos);
374
375 // System.out.println("Extracted (name, value) pair: ("
376 // + name + ", '" + value+"')");
377
378 // If both a name and a value have been found, then add
379 // them to the data Map - actually, we add an empty value if there
380 // is a valid name.
381 if (name.length() > 0) {
382 //if (data.containsKey(name)) {
383 // A repeat, that's a parse error, so return a null map
384 //return new HashMap();
385 //}
386 //else {
387 data.put(name, value);
388 //}
389 }
390 }
391
392 return data;
393 }
394
395 /**
396 * This is a helper routine, only used by parseData, to extract a
397 * quoted String from the input parameter, rawData. A quoted string
398 * can use either single or double quotes, but they must match up.
399 * A singly quoted string can contain an unbalanced amount of double
400 * quotes, or vice versa. For example, the String "JDOM's the best"
401 * is legal as is 'JDOM"s the best'.
402 *
403 * @param rawData the input string from which a quoted string is to
404 * be extracted.
405 * @return the first quoted string encountered in the input data. If
406 * no quoted string is found, then the empty string, "", is
407 * returned.
408 * @see #parseData
409 */
410 private static int[] extractQuotedString(String rawData) {
411 // Remembers whether we're actually in a quoted string yet
412 boolean inQuotes = false;
413
414 // Remembers which type of quoted string we're in
415 char quoteChar = '"';
416
417 // Stores the position of the first character inside
418 // the quoted string (i.e. the start of the return string)
419 int start = 0;
420
421 // Iterate through the input string looking for the start
422 // and end of the quoted string
423 for (int pos=0; pos < rawData.length(); pos++) {
424 char currentChar = rawData.charAt(pos);
425 if (currentChar=='"' || currentChar=='\'') {
426 if (!inQuotes) {
427 // We're entering a quoted string
428 quoteChar = currentChar;
429 inQuotes = true;
430 start = pos+1;
431 }
432 else if (quoteChar == currentChar) {
433 // We're leaving a quoted string
434 inQuotes = false;
435 return new int[] { start, pos };
436 }
437 // Otherwise we've encountered a quote
438 // inside a quote, so just continue
439 }
440 }
441
442 return null;
443 }
444
445 /**
446 * This returns a <code>String</code> representation of the
447 * <code>ProcessingInstruction</code>, suitable for debugging. If the XML
448 * representation of the <code>ProcessingInstruction</code> is desired,
449 * {@link XMLOutputter2#outputString(ProcessingInstruction)}
450 * should be used.
451 *
452 * @return <code>String</code> - information about the
453 * <code>ProcessingInstruction</code>
454 */
455 @Override
456 public String toString() {
457 return new StringBuilder()
458 .append("[ProcessingInstruction: ")
459 .append(new XMLOutputter2().outputString(this))
460 .append("]")
461 .toString();
462 }
463
464 @Override
465 public ProcessingInstruction clone() {
466 ProcessingInstruction pi = (ProcessingInstruction) super.clone();
467
468 // target and rawdata are immutable and references copied by
469 // Object.clone()
470
471 // Create a new Map object for the clone (since Map isn't Cloneable)
472 pi.mapData = parseData(rawData);
473 return pi;
474 }
475
476 @Override
477 public ProcessingInstruction detach() {
478 return (ProcessingInstruction)super.detach();
479 }
480
481 @Override
482 protected ProcessingInstruction setParent(Parent parent) {
483 return (ProcessingInstruction)super.setParent(parent);
484 }
485
486
487 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.Map;
57
58
59 /**
60 * This JDOMFactory instance reduces the amount of memory used by JDOM content.
61 * It does this by reusing String instances instead of using new (but equals())
62 * instances. It uses the {@link StringBin} class to provide a String cache.
63 *
64 * @see StringBin
65 * @author Rolf Lear
66 *
67 */
68 public class SlimJDOMFactory extends DefaultJDOMFactory {
69
70 private StringBin cache = new StringBin();
71 private final boolean cachetext;
72
73 /**
74 *
75 */
76 public SlimJDOMFactory() {
77 this(true);
78 }
79
80 /**
81 * Construct a SlimJDOMFactory which will optionally cache Text/CDATA/Comment/Attribute
82 * values. Caching these values is recommended because often XML documents have
83 * many instances of the same Text values (especially whitespace sequences...)
84 * @param cachetext should be true if you want the content of CDATA, Text,
85 * Comment and Attribute values cached as well.
86 */
87 public SlimJDOMFactory(final boolean cachetext) {
88 super();
89 this.cachetext = cachetext;
90 }
91
92
93 /**
94 * Reset any Cached String instance data from this SlimJDOMFaxctory cache.
95 */
96 public void clearCache() {
97 cache = new StringBin();
98 }
99
100 @Override
101 public Attribute attribute(final String name, final String value, final Namespace namespace) {
102 return super.attribute(cache.reuse(name),
103 (cachetext ? cache.reuse(value) : value),
104 namespace);
105 }
106
107 @Override
108 @Deprecated
109 public Attribute attribute(final String name, final String value, final int type,
110 final Namespace namespace) {
111 return super.attribute(cache.reuse(name),
112 (cachetext ? cache.reuse(value) : value),
113 type, namespace);
114 }
115
116 @Override
117 public Attribute attribute(final String name, final String value, final AttributeType type,
118 Namespace namespace) {
119 return super.attribute(cache.reuse(name),
120 (cachetext ? cache.reuse(value) : value),
121 type, namespace);
122 }
123
124 @Override
125 public Attribute attribute(final String name, final String value) {
126 return super.attribute(cache.reuse(name),
127 (cachetext ? cache.reuse(value) : value));
128 }
129
130 @Override
131 @Deprecated
132 public Attribute attribute(final String name, final String value, final int type) {
133 return super.attribute(cache.reuse(name),
134 (cachetext ? cache.reuse(value) : value),
135 type);
136 }
137
138 @Override
139 public Attribute attribute(final String name, final String value, final AttributeType type) {
140 return super.attribute(cache.reuse(name),
141 (cachetext ? cache.reuse(value) : value),
142 type);
143 }
144
145 @Override
146 public CDATA cdata(final int line, final int col, final String str) {
147 return super.cdata(line, col, (cachetext ? cache.reuse(str) : str));
148 }
149
150 @Override
151 public Text text(final int line, final int col, final String str) {
152 return super.text(line, col, (cachetext ? cache.reuse(str) : str));
153 }
154
155 @Override
156 public Comment comment(final int line, final int col, final String text) {
157 return super.comment(line, col, (cachetext ? cache.reuse(text) : text));
158 }
159
160 @Override
161 public DocType docType(final int line, final int col, final String elementName, final String publicID, final String systemID) {
162 return super.docType(line, col, cache.reuse(elementName), publicID, systemID);
163 }
164
165 @Override
166 public DocType docType(final int line, final int col, final String elementName, final String systemID) {
167 return super.docType(line, col, cache.reuse(elementName), systemID);
168 }
169
170 @Override
171 public DocType docType(final int line, final int col, final String elementName) {
172 return super.docType(line, col, cache.reuse(elementName));
173 }
174
175 @Override
176 public Element element(final int line, final int col, final String name, final Namespace namespace) {
177 return super.element(line, col, cache.reuse(name), namespace);
178 }
179
180 @Override
181 public Element element(final int line, final int col, final String name) {
182 return super.element(line, col, cache.reuse(name));
183 }
184
185 @Override
186 public Element element(final int line, final int col, final String name, final String uri) {
187 return super.element(line, col, cache.reuse(name), uri);
188 }
189
190 @Override
191 public Element element(final int line, final int col, final String name, final String prefix, final String uri) {
192 return super.element(line, col, cache.reuse(name), prefix, uri);
193 }
194
195 @Override
196 public ProcessingInstruction processingInstruction(final int line, final int col, final String target,
197 final Map<String, String> data) {
198 return super.processingInstruction(line, col, cache.reuse(target), data);
199 }
200
201 @Override
202 public ProcessingInstruction processingInstruction(final int line, final int col, final String target,
203 final String data) {
204 return super.processingInstruction(line, col, cache.reuse(target), data);
205 }
206
207 @Override
208 public ProcessingInstruction processingInstruction(final int line, final int col, final String target) {
209 return super.processingInstruction(line, col, cache.reuse(target));
210 }
211
212 @Override
213 public EntityRef entityRef(final int line, final int col, final String name) {
214 return super.entityRef(line, col, cache.reuse(name));
215 }
216
217 @Override
218 public EntityRef entityRef(final int line, final int col, final String name, final String publicID, final String systemID) {
219 return super.entityRef(line, col, cache.reuse(name), publicID, systemID);
220 }
221
222 @Override
223 public EntityRef entityRef(final int line, final int col, final String name, final String systemID) {
224 return super.entityRef(line, col, cache.reuse(name), systemID);
225 }
226
227 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import org.jdom.internal.ArrayCopy;
57
58
59 /**
60 * This is a mechanism for storing and reusing unique instances of Strings.
61 * The idea is that in XML the tag names, attribute names, and other String
62 * content is often repeated a lot. Each repeat is typically done as a new
63 * String instance. This class makes it possible to substantially reduce memory
64 * usage by reusing String instances instead of keeping the new ones.
65 * <p>
66 * This class is not the same as String.intern() because String.intern() uses
67 * the PermGen memory space (very limited in size), whereas this uses the heap.
68 * <p>
69 * The primary goal of this class is to be as memory efficient as possible. This
70 * has the interesting side effect of reducing the amount of time spent in
71 * garbage-collection cycles. While this does increase the amount of time to
72 * process a String, it means that subsequent String values can be 'recycled'
73 * fast, and, ideally, never need to leave the 'eden space' in the memory model
74 * which in turn means that the duplicate strings do not even hit the GC
75 * overhead. It is easy to measure that this process takes longer than simply
76 * keeping the duplicate String values, but it is much harder to measure the
77 * decreased cost of GC. It would be somewhat fair to say that the memory
78 * benefit is substantial, and the cost of allocation is offset by the savings
79 * in garbage collection. This trade-off is dependent on the amount of duplicate
80 * data you have. In XML where there are lots of repeating patterns of element
81 * and attribute names this can add up pretty fast.
82 * <p>
83 * This class is not thread-safe.
84 *
85 * @author Rolf Lear
86 *
87 */
88 final class StringBin {
89
90 // Here are some magic numbers:
91
92 /** Default bucket-size growth factor */
93 private static final int GROW = 4;
94 /**
95 * How many buckets to start with
96 * <p>
97 * Actually, this just sets the initial capacity which is used to calculate
98 * the number of buckets. This implementation will turn the default capacity
99 * of 1023 in to
100 */
101 private static final int DEFAULTCAP = 1023;
102 /** How big to let the largest bucket grow before a rehash */
103 private static final int MAXBUCKET = 64;
104
105 /**
106 * The actual buckets.
107 * There is a really good reason to use a two-dimensional array: a 1
108 * dimensional array would require us to do an inordinate amount of shifting
109 * of the data as we insert new values in to the middle.
110 * By having 'x' number of buckets, the average shift would be 1/x th of the
111 * amount, which is much faster.
112 */
113 private String[][] buckets;
114 private int lengths[];
115
116 /** The bit mask and bit shift */
117 private int mask = 0;
118
119 /**
120 * Create a default instance of the StringBin with the default capacity.
121 */
122 public StringBin() {
123 this(DEFAULTCAP);
124 }
125
126 /**
127 * Create a StringBin instance with a specified initial capacity.
128 * @param capacity the capacity to set.
129 */
130 public StringBin(int capacity) {
131 if (capacity < 0) {
132 throw new IllegalArgumentException("Can not have a negative capacity");
133 }
134 capacity--;
135 if (capacity < DEFAULTCAP) {
136 capacity = DEFAULTCAP;
137 }
138 // aim for 'GROW - 1' Strings per bucket...
139 capacity /= (GROW - 1);
140 int shift = 0;
141 while (capacity != 0) {
142 capacity >>>= 1;
143 shift++;
144 }
145 mask = (1 << shift) - 1;
146 buckets = new String[mask + 1][];
147 lengths = new int[buckets.length];
148 }
149
150 /**
151 * This code effectively does a binary search for a value.
152 * The order of the data in a bucket is increasing-by-hashcode, and then
153 * for values with the same hashcode, it is increasing by alphabetical.
154 * @param hash
155 * @param value
156 * @param bucket
157 * @param length
158 * @return
159 */
160 private final int locate(final int hash, final String value, final String[] bucket, final int length) {
161 int left = 0;
162 int right = length -1;
163 int mid = 0;
164 while (left <= right) {
165 mid = (left + right) >>> 1;
166 if (bucket[mid].hashCode() > hash) {
167 right = mid - 1;
168 } else if (bucket[mid].hashCode() < hash) {
169 left = mid + 1;
170 } else {
171 // have the same hashcode
172 // do a string-compare.
173 int cmp = value.compareTo(bucket[mid]);
174 if (cmp == 0) {
175 // equals.
176 return mid;
177 } else if (cmp < 0) {
178 // our input value comes before the bucket value, search
179 // backwards
180 while (--mid >= left && bucket[mid].hashCode() == hash) {
181 // we have gone back one, and we still have the same
182 // hash code... let's compare.
183 cmp = value.compareTo(bucket[mid]);
184 if (cmp == 0) {
185 // equals, found it.
186 return mid;
187 } else if (cmp > 0) {
188 // we were searching backwards because we started at
189 // the mid point which was after the input value.
190 // now that we have found a value that comes
191 // before the input value it means we have gone too
192 // far... which in turn means the insertion point
193 // is one place after where we are.
194 return - (mid + 1) - 1;
195 }
196 }
197 // this must mean that we ran out of data, or ran out of
198 // values with the same hashcode...
199 return - (mid + 1) - 1;
200 } else {
201 // we have a value that comes before the value with the
202 // same hash as us.
203 while (++mid <= right && bucket[mid].hashCode() == hash) {
204 //the next value exists and has the same hash code.
205 cmp = value.compareTo(bucket[mid]);
206 if (cmp == 0) {
207 // found our value.
208 return mid;
209 } else if (cmp < 0) {
210 // we were searching forwards because we started at
211 // the mid point which was before the input value.
212 // now that we have found a value that comes
213 // after the input value it means we have gone too
214 // far... which in turn means the insertion point
215 // is at the point where we are.
216 return - mid - 1;
217 }
218 }
219 // we have run out of values, or the value we are on has a
220 // different hashcode.
221 return - mid - 1;
222 }
223 }
224 }
225 // nothing had the same hashcode.
226 return -left - 1;
227 }
228
229 /**
230 * Get a String instance that is equal to the input value. This may or may
231 * not be the same instance as the input value. Null input values will
232 * reuse() as null.
233 * @param value The value to check.
234 * @return a String that is equals() to the input value, or null if the
235 * input was null
236 */
237 public String reuse(final String value) {
238 if (value == null) {
239 return null;
240 }
241 final int hash = value.hashCode();
242 /*
243 * we use a special masking routine here. This is important.
244 * we always do a 16-bit shift, XOR it with the unshifted value, and
245 * then apply the mask.
246 * The reason is relatively simple: it makes rehashing much faster
247 * because you never need to shift values in the rehash, they are always
248 * just appended.
249 * Further, there is no real need to get a true random distribution in
250 * the buckets... it's not important. The String.hashCode() is a good
251 * enough hash function so we do not lose much by doing it this way.
252 *
253 * In detail:
254 * Normally for a bucketing/hashing system we will try to use as many
255 * bits as possible to create the bucket hash for the value. In this
256 * case though, we XOR the high 16 bits with the low 16 bits (and keep
257 * the high 16 bits unchanged. Lets call this the 'interim result'.
258 * We then apply our bit mask to that interim result to get the bucket
259 * id. The important thing here is that the interim result is the same
260 * no matter how many buckets there are.
261 *
262 * If we need to rehash the buckets, the mask will include more bits,
263 * and that guarantees that the values in any one 'original' bucket
264 * will be divided in to different buckets, and never merged with
265 * values from a different original bucket.
266 *
267 * Thus, in a rehash, both because of the way we calculate the bucketid
268 * and also because the values in a bucket are stored in increasing
269 * hash value order, we never need to insert a value in to the middle
270 * of the rehashed bucket, we can always add to the end.
271 */
272 final int bucketid = ((hash >>> 16) ^ hash) & mask;
273
274 final int length = lengths[bucketid];
275 if (length == 0) {
276 // start a new bucket
277 final String v = compact(value);
278 buckets[bucketid] = new String[GROW];
279 buckets[bucketid][0] = v;
280 lengths[bucketid] = 1;
281 return v;
282 }
283
284 // get the existing bucket.
285 String[] bucket = buckets[bucketid];
286
287 // note the final value calculated as -val - 1
288 final int ip = - locate(hash, value, bucket, length) - 1;
289 if (ip < 0) {
290 // this means we have found the value.
291 return bucket[- ip - 1];
292 }
293 if (length >= MAXBUCKET) {
294 // need to rehash, so we do, and then add our value
295 rehash();
296 return reuse(value);
297 }
298 if (length == bucket.length) {
299 // there is no space for our value.
300 bucket = ArrayCopy.copyOf(bucket, length + GROW);
301 buckets[bucketid] = bucket;
302 }
303 System.arraycopy(bucket, ip, bucket, ip + 1, length - ip);
304 final String v = compact(value);
305 bucket[ip] = v;
306 lengths[bucketid]++;
307 return v;
308 }
309
310 /**
311 * Store the existing values in a new and larger set of buckets.
312 * This reduces the number of values in each bucket, which improves insert
313 * time.
314 * <p>
315 * The data is stored in hashCode() order, and then alphabetically for
316 * those instances where two String values have the same hashCode().
317 * <p>
318 * The bucketing hash key is calculated in a specific way that guarantees
319 * that when we rehash there values in a bucket will be divided between
320 * a new set of buckets, and no other source bucket will ever add values
321 * to a bucket that we are dividing our bucket to.
322 * <p>
323 * The combination of the bucket hash key, and the bucket ordering means
324 * that during a rehash we never have to insert values in to the middle of
325 * the bucket.
326 */
327 private void rehash() {
328 String[][] olddata = buckets;
329 // magic numbers ... we make 4-times as many buckets.
330 mask = ((mask + 1) << 2) - 1;
331 buckets = new String[mask + 1][];
332 lengths = new int[buckets.length];
333 int hash = 0, bucketid = 0, length = 0;
334 for (String[] ob : olddata) {
335 if (ob == null) {
336 // was an empty bucket.
337 continue;
338 }
339 for (String val : ob) {
340 if (val == null) {
341 // there are no more values to rehash in this bucket.
342 break;
343 }
344 hash = val.hashCode();
345 bucketid = ((hash >>> 16) ^ hash) & mask;
346 length = lengths[bucketid];
347 if (length == 0) {
348 buckets[bucketid] = new String[(ob.length + GROW) / GROW];
349 buckets[bucketid][0] = val;
350 } else {
351 if (buckets[bucketid].length == length) {
352 buckets[bucketid] = ArrayCopy.copyOf(
353 buckets[bucketid], lengths[bucketid] + GROW);
354 }
355 buckets[bucketid][length] = val;
356 }
357 lengths[bucketid]++;
358 }
359 }
360 }
361
362 /**
363 * Compact a Java String to its smallest char[] backing array.
364 * Java often reuses the char[] array that backs String classes. If you have
365 * one String value and substring it, or some other methods, then instead of
366 * creating a new char[] array it reuses the original one. This can lead to
367 * small String values being backed by very large arrays. We do not want to
368 * be caching these large arrays... just the smallest.
369 * @param input The String to compact
370 * @return a Compacted version of the String.
371 */
372 private static final String compact(final String input) {
373 return new String(input.toCharArray());
374 }
375
376 /**
377 * Number of registered Strings
378 * @return the number of registered String values.
379 */
380 public int size() {
381 int sum = 0;
382 for (int l : lengths) {
383 sum += l;
384 }
385 return sum;
386 }
387
388 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import org.jdom.output.Format;
57 import org.jdom.output.XMLOutputter2;
58
59 /**
60 * An XML character sequence. Provides a modular, parentable method of
61 * representing text. Text makes no guarantees about the underlying textual
62 * representation of character data, but does expose that data as a Java String.
63 *
64 * @author Brett McLaughlin
65 * @author Jason Hunter
66 * @author Bradley S. Huffman
67 */
68 public class Text extends Content {
69
70 /**
71 * JDOM2 Serialization. In this case, Text is simple.
72 */
73 private static final long serialVersionUID = 200L;
74
75 static final String EMPTY_STRING = "";
76
77 /** The actual character content */
78 // XXX See http://www.servlets.com/archive/servlet/ReadMsg?msgId=8612
79 // from elharo for a description of why Java characters may not suffice
80 // long term
81 protected String value;
82
83 /**
84 * CData type extends Text, and it needs to be able to change the Content
85 * type of this Content.
86 * @param ctype The CType to set for this Text-based Content.
87 */
88 protected Text(CType ctype) {
89 super(ctype);
90 }
91
92 /**
93 * This is the protected, no-args constructor standard in all JDOM
94 * classes. It allows subclassers to get a raw instance with no
95 * initialization.
96 */
97 protected Text() {
98 this(CType.Text);
99 }
100
101 /**
102 * This constructor creates a new <code>Text</code> node, with the
103 * supplied string value as it's character content.
104 *
105 * @param str the node's character content.
106 * @throws IllegalDataException if <code>str</code> contains an
107 * illegal character such as a vertical tab (as determined
108 * by {@link org.jdom.Verifier#checkCharacterData})
109 */
110 public Text(String str) {
111 this(CType.Text);
112 setText(str);
113 }
114
115 /**
116 * This returns the value of this <code>Text</code> node as a Java
117 * <code>String</code>.
118 *
119 * @return <code>String</code> - character content of this node.
120 */
121 public String getText() {
122 return value;
123 }
124
125 /**
126 * This returns the textual content with all surrounding whitespace
127 * removed. If only whitespace exists, the empty string is returned.
128 *
129 * @return trimmed text content or empty string
130 */
131 public String getTextTrim() {
132 return Format.trimBoth(getText());
133 }
134
135 /**
136 * This returns the textual content with all surrounding whitespace
137 * removed and internal whitespace normalized to a single space. If
138 * only whitespace exists, the empty string is returned.
139 *
140 * @return normalized text content or empty string
141 */
142 public String getTextNormalize() {
143 return normalizeString(getText());
144 }
145
146 /**
147 * This returns a new string with all surrounding whitespace
148 * removed and internal whitespace normalized to a single space. If
149 * only whitespace exists, the empty string is returned.
150 * <p>
151 * Per XML 1.0 Production 3 whitespace includes: #x20, #x9, #xD, #xA
152 * </p>
153 *
154 * @param str string to be normalized.
155 * @return normalized string or empty string
156 */
157 public static String normalizeString(String str) {
158 if (str == null)
159 return EMPTY_STRING;
160
161 return Format.compact(str);
162 }
163
164 /**
165 * This will set the value of this <code>Text</code> node.
166 *
167 * @param str value for node's content.
168 * @return the object on which the method was invoked
169 * @throws IllegalDataException if <code>str</code> contains an
170 * illegal character such as a vertical tab (as determined
171 * by {@link org.jdom.Verifier#checkCharacterData})
172 */
173 public Text setText(String str) {
174 String reason;
175
176 if (str == null) {
177 value = EMPTY_STRING;
178 return this;
179 }
180
181 if ((reason = Verifier.checkCharacterData(str)) != null) {
182 throw new IllegalDataException(str, "character content", reason);
183 }
184 value = str;
185 return this;
186 }
187
188 /**
189 * This will append character content to whatever content already
190 * exists within this <code>Text</code> node.
191 *
192 * @param str character content to append.
193 * @throws IllegalDataException if <code>str</code> contains an
194 * illegal character such as a vertical tab (as determined
195 * by {@link org.jdom.Verifier#checkCharacterData})
196 */
197 public void append(String str) {
198 String reason;
199
200 if (str == null) {
201 return;
202 }
203 if ((reason = Verifier.checkCharacterData(str)) != null) {
204 throw new IllegalDataException(str, "character content", reason);
205 }
206
207 if (str.length() > 0) {
208 value += str;
209 }
210 }
211
212 /**
213 * This will append the content of another <code>Text</code> node
214 * to this node.
215 *
216 * @param text Text node to append.
217 */
218 public void append(Text text) {
219 if (text == null) {
220 return;
221 }
222 value += text.getText();
223 }
224
225 /**
226 * Returns the XPath 1.0 string value of this element, which is the
227 * text itself.
228 *
229 * @return the text
230 */
231 @Override
232 public String getValue() {
233 return value;
234 }
235
236 /**
237 * This returns a <code>String</code> representation of the
238 * <code>Text</code> node, suitable for debugging. If the XML
239 * representation of the <code>Text</code> node is desired,
240 * either <code>{@link #getText}</code> or
241 * {@link XMLOutputter2#outputString(Text)}</code>
242 * should be used.
243 *
244 * @return <code>String</code> - information about this node.
245 */
246 @Override
247 public String toString() {
248 return new StringBuilder(64)
249 .append("[Text: ")
250 .append(getText())
251 .append("]")
252 .toString();
253 }
254
255 @Override
256 public Text clone() {
257 Text text = (Text)super.clone();
258 text.value = value;
259 return text;
260 }
261
262 @Override
263 public Text detach() {
264 return (Text)super.detach();
265 }
266
267 @Override
268 protected Text setParent(Parent parent) {
269 return (Text)super.setParent(parent);
270 }
271
272 @Override
273 public Element getParent() {
274 // because DocType can only be attached to a Document.
275 return (Element)super.getParent();
276 }
277
278 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.*;
57
58 /**
59 * Special factory for building documents without any content or structure
60 * checking. This should only be used when you are 100% positive that the
61 * input is absolutely correct. This factory can speed builds, but any
62 * problems in the input will be uncaught until later when they could cause
63 * infinite loops, malformed XML, or worse. Use with extreme caution.
64 *
65 * @author Various Authors - history is not complete
66 */
67 public class UncheckedJDOMFactory extends DefaultJDOMFactory {
68
69 // =====================================================================
70 // Element Factory
71 // =====================================================================
72
73 @Override
74 public Element element(final int line, final int col, final String name, Namespace namespace) {
75 Element e = new Element();
76 e.name = name;
77 if (namespace == null) {
78 namespace = Namespace.NO_NAMESPACE;
79 }
80 e.namespace = namespace;
81 return e;
82 }
83
84 @Override
85 public Element element(final int line, final int col, final String name) {
86 Element e = new Element();
87 e.name = name;
88 e.namespace = Namespace.NO_NAMESPACE;
89 return e;
90 }
91
92 @Override
93 public Element element(final int line, final int col, final String name, String uri) {
94 return element(name, Namespace.getNamespace("", uri));
95 }
96
97 @Override
98 public Element element(final int line, final int col, final String name, String prefix, String uri) {
99 return element(name, Namespace.getNamespace(prefix, uri));
100 }
101
102 // =====================================================================
103 // Attribute Factory
104 // =====================================================================
105
106 @Override
107 public Attribute attribute(String name, String value, Namespace namespace) {
108 Attribute a = new Attribute();
109 a.name = name;
110 a.value = value;
111 if (namespace == null) {
112 namespace = Namespace.NO_NAMESPACE;
113 }
114 a.namespace = namespace;
115 return a;
116 }
117
118 @Override
119 @Deprecated
120 public Attribute attribute(String name, String value, int type, Namespace namespace) {
121 return attribute(name, value, AttributeType.byIndex(type), namespace);
122 }
123
124 @Override
125 public Attribute attribute(String name, String value, AttributeType type, Namespace namespace) {
126 Attribute a = new Attribute();
127 a.name = name;
128 a.type = type;
129 a.value = value;
130 if (namespace == null) {
131 namespace = Namespace.NO_NAMESPACE;
132 }
133 a.namespace = namespace;
134 return a;
135 }
136
137 @Override
138 public Attribute attribute(String name, String value) {
139 Attribute a = new Attribute();
140 a.name = name;
141 a.value = value;
142 a.namespace = Namespace.NO_NAMESPACE;
143 return a;
144 }
145
146
147 @Override
148 @Deprecated
149 public Attribute attribute(String name, String value, int type) {
150 return attribute(name, value, AttributeType.byIndex(type));
151 }
152
153 @Override
154 public Attribute attribute(String name, String value, AttributeType type) {
155 Attribute a = new Attribute();
156 a.name = name;
157 a.type = type;
158 a.value = value;
159 a.namespace = Namespace.NO_NAMESPACE;
160 return a;
161 }
162
163 // =====================================================================
164 // Text Factory
165 // =====================================================================
166
167 @Override
168 public Text text(final int line, final int col, final String str) {
169 Text t = new Text();
170 t.value = str;
171 return t;
172 }
173
174 // =====================================================================
175 // CDATA Factory
176 // =====================================================================
177
178 @Override
179 public CDATA cdata(final int line, final int col, final String str) {
180 CDATA c = new CDATA();
181 c.value = str;
182 return c;
183 }
184
185 // =====================================================================
186 // Comment Factory
187 // =====================================================================
188
189 @Override
190 public Comment comment(final int line, final int col, final String str) {
191 Comment c = new Comment();
192 c.text = str;
193 return c;
194 }
195
196 // =====================================================================
197 // Processing Instruction Factory
198 // =====================================================================
199
200 @Override
201 public ProcessingInstruction processingInstruction(final int line, final int col, final String target, Map<String,String> data) {
202 ProcessingInstruction p = new ProcessingInstruction();
203 p.target = target;
204 p.setData(data);
205 return p;
206 }
207
208 @Override
209 public ProcessingInstruction processingInstruction(final int line, final int col, final String target, String data) {
210 ProcessingInstruction p = new ProcessingInstruction();
211 p.target = target;
212 p.setData(data);
213 return p;
214 }
215
216 @Override
217 public ProcessingInstruction processingInstruction(final int line, final int col, final String target) {
218 ProcessingInstruction p = new ProcessingInstruction();
219 p.target = target;
220 p.rawData = "";
221 return p;
222 }
223
224 // =====================================================================
225 // Entity Ref Factory
226 // =====================================================================
227
228 @Override
229 public EntityRef entityRef(final int line, final int col, final String name) {
230 EntityRef e = new org.jdom.EntityRef();
231 e.name = name;
232 return e;
233 }
234
235 @Override
236 public EntityRef entityRef(final int line, final int col, final String name, String systemID) {
237 EntityRef e = new EntityRef();
238 e.name = name;
239 e.systemID = systemID;
240 return e;
241 }
242
243 @Override
244 public EntityRef entityRef(final int line, final int col, final String name, String publicID, String systemID) {
245 EntityRef e = new EntityRef();
246 e.name = name;
247 e.publicID = publicID;
248 e.systemID = systemID;
249 return e;
250 }
251
252 // =====================================================================
253 // DocType Factory
254 // =====================================================================
255
256 @Override
257 public DocType docType(final int line, final int col, final String elementName, String publicID, String systemID) {
258 DocType d = new DocType();
259 d.elementName = elementName;
260 d.publicID = publicID;
261 d.systemID = systemID;
262 return d;
263 }
264
265 @Override
266 public DocType docType(final int line, final int col, final String elementName, String systemID) {
267 return docType(elementName, null, systemID);
268 }
269
270 @Override
271 public DocType docType(final int line, final int col, final String elementName) {
272 return docType(elementName, null, null);
273 }
274
275 // =====================================================================
276 // Document Factory
277 // =====================================================================
278
279 @Override
280 public Document document(Element rootElement, DocType docType, String baseURI) {
281 Document d = new Document();
282 if (docType != null) {
283 addContent(d, docType);
284 }
285 if (rootElement != null) {
286 addContent(d, rootElement);
287 }
288 if (baseURI != null) {
289 d.baseURI = baseURI;
290 }
291 return d;
292 }
293
294 @Override
295 public Document document(Element rootElement, DocType docType) {
296 return document(rootElement, docType, null);
297 }
298
299 @Override
300 public Document document(Element rootElement) {
301 return document(rootElement, null, null);
302 }
303
304 // =====================================================================
305 // List manipulation
306 // =====================================================================
307
308 @Override
309 public void addContent(Parent parent, Content child) {
310 if (parent instanceof Element) {
311 Element elt = (Element) parent;
312 elt.content.uncheckedAddContent(child);
313 }
314 else {
315 Document doc = (Document) parent;
316 doc.content.uncheckedAddContent(child);
317 }
318 }
319
320 @Override
321 public void setAttribute(Element parent, Attribute a) {
322 parent.getAttributeList().uncheckedAddAttribute(a);
323 }
324
325 @Override
326 public void addNamespaceDeclaration(Element parent, Namespace additional) {
327 if (parent.additionalNamespaces == null) {
328 parent.additionalNamespaces = new ArrayList<Namespace>(5); //Element.INITIAL_ARRAY_SIZE
329 }
330 parent.additionalNamespaces.add(additional);
331 }
332
333 @Override
334 public void setRoot(Document doc, Element root) {
335 doc.content.uncheckedAddContent(root);
336 }
337
338 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom;
55
56 import java.util.*;
57
58 /**
59 * A utility class to handle well-formedness checks on names, data, and other
60 * verification tasks for JDOM. The class is final and may not be subclassed.
61 *
62 * @author Brett McLaughlin
63 * @author Elliotte Rusty Harold
64 * @author Jason Hunter
65 * @author Bradley S. Huffman
66 * @author Rolf Lear
67 * @author Wilfried Middleton
68 */
69 final public class Verifier {
70
71 /*
72 * KEY TO UNDERSTANDING MASKS.
73 * ===========================
74 *
75 * This Verifier uses bitwise logic to perform fast validation on
76 * XML characters. The concept is as follows...
77 *
78 * There are 7 major tests for characters in JDOM and one special case.
79 * Can the character be a regular character, can it be part of an XML Name
80 * (element, attribute, entity-ref, etc.), does it represent a letter,
81 * digit, or combining character. Finally can a character be the first
82 * character in a name, or can the character be part of a URI. The special
83 * case is that Attributes and Element names in JDOM do not include the
84 * namespace prefix, thus, for Attribute and Elements, the name is the
85 * identical test to other XML names, but excludes the ':'. For performance
86 * reasons we only have the bitmask for the JDOM names, and then add the
87 * ':' for the general case tests.
88 *
89 * These 7 tests are often performed in very tight performance critical
90 * loops. It is essential for them to be fast.
91 *
92 * These 7 tests conveniently can be represented as 8 bits in a byte.
93 * We can thus have a single byte that represents the possible roles for
94 * each possible character. There are 64K characters... thus we need 64K
95 * bytes to represent each character's possible roles.
96 *
97 * We could use arrays of booleans to accomplish the same thing, but each
98 * boolean is a byte of memory, and using a bitmask allows us to put the
99 * 8 bitmask tests in the same memory space as just one boolean array.
100 *
101 * The end solution is to have an array of these bytes, one per character,
102 * and to then query each bit on the byte to see whether the corresponding
103 * character is able to perform in the respective role.
104 *
105 * The complicated part of this process is three-fold. The hardest part is
106 * knowing what role each character can play. The next hard part is
107 * converting this knowledge in to an array of bytes we can express in this
108 * Verifier class. The final part is querying that array for each test.
109 *
110 * Before this particular performance upgrade, the knowledge of what roles
111 * each character can play was embedded in each of the isXML*() methods.
112 * Those methods have been transferred in to the 'contrib' class
113 * org.jdom.contrib.verifier.VerifierBuilder. That VerifierBuilder class
114 * has a main method which takes that knowledge, and converts it in to a
115 * 'compressed' set of two arrays, the byte mask, and the number of
116 * consecutive characters that have that mask, which are then copy/pasted
117 * in to this file as the VALCONST and LENCONST arrays.
118 *
119 * These two arrays are then 'decompressed' in to the CHARFLAGS array.
120 *
121 * The CHARFLAGS array is then queried for each of the 8 critical tests
122 * to determine which roles a character performs.
123 *
124 * If you need to change the roles a character plays in XML (i.e. change
125 * the return-value of one of the isXML...() methods, then you need to:
126 *
127 * - update the logic in org.jdom.contrib.verifier.VerifierBuilder
128 * - run the VerifierBuilder
129 * - copy/paste the output to this file.
130 * - update the JUnit test harness TestVerifier
131 */
132
133 /**
134 * The seed array used with LENCONST to populate CHARFLAGS.
135 */
136 private static final byte[] VALCONST = new byte[] {
137 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x41, 0x01,
138 0x41, 0x49, 0x41, 0x59, 0x41, 0x01, 0x41, 0x01,
139 0x41, 0x4f, 0x01, 0x4d, 0x01, 0x4f, 0x01, 0x41,
140 0x01, 0x09, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
141 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
142 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
143 0x01, 0x0f, 0x01, 0x09, 0x01, 0x29, 0x01, 0x29,
144 0x01, 0x0f, 0x09, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
145 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
146 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
147 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x29,
148 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
149 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
150 0x01, 0x0f, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29,
151 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01, 0x0f,
152 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x09, 0x0f, 0x29,
153 0x01, 0x19, 0x01, 0x29, 0x0f, 0x01, 0x0f, 0x01,
154 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x29, 0x0f, 0x29,
155 0x01, 0x29, 0x01, 0x19, 0x01, 0x29, 0x01, 0x0f,
156 0x01, 0x29, 0x0f, 0x29, 0x01, 0x29, 0x01, 0x0f,
157 0x29, 0x01, 0x19, 0x01, 0x29, 0x01, 0x0f, 0x01,
158 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
159 0x0f, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01,
160 0x29, 0x01, 0x29, 0x01, 0x0f, 0x01, 0x0f, 0x29,
161 0x01, 0x19, 0x0f, 0x01, 0x29, 0x01, 0x0f, 0x01,
162 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
163 0x0f, 0x01, 0x0f, 0x01, 0x29, 0x01, 0x29, 0x01,
164 0x29, 0x01, 0x29, 0x01, 0x0f, 0x01, 0x0f, 0x01,
165 0x19, 0x29, 0x0f, 0x01, 0x29, 0x01, 0x0f, 0x01,
166 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
167 0x0f, 0x01, 0x0f, 0x01, 0x29, 0x0f, 0x29, 0x01,
168 0x29, 0x01, 0x29, 0x01, 0x0f, 0x01, 0x19, 0x01,
169 0x29, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
170 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x29, 0x0f,
171 0x29, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01,
172 0x0f, 0x01, 0x0f, 0x01, 0x19, 0x01, 0x29, 0x01,
173 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
174 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
175 0x0f, 0x01, 0x0f, 0x01, 0x29, 0x01, 0x29, 0x01,
176 0x29, 0x01, 0x29, 0x01, 0x19, 0x01, 0x29, 0x01,
177 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
178 0x0f, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01,
179 0x29, 0x01, 0x0f, 0x01, 0x19, 0x01, 0x29, 0x01,
180 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
181 0x0f, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01,
182 0x29, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x19, 0x01,
183 0x29, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
184 0x0f, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01,
185 0x29, 0x01, 0x0f, 0x01, 0x19, 0x01, 0x0f, 0x01,
186 0x0f, 0x29, 0x0f, 0x29, 0x01, 0x0f, 0x09, 0x29,
187 0x01, 0x19, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
188 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
189 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
190 0x01, 0x0f, 0x01, 0x0f, 0x29, 0x0f, 0x29, 0x01,
191 0x29, 0x0f, 0x01, 0x0f, 0x01, 0x09, 0x01, 0x29,
192 0x01, 0x19, 0x01, 0x29, 0x01, 0x19, 0x01, 0x29,
193 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x0f, 0x01,
194 0x0f, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01,
195 0x29, 0x01, 0x29, 0x01, 0x29, 0x01, 0x29, 0x01,
196 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
197 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
198 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
199 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
200 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
201 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
202 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
203 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
204 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
205 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
206 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
207 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
208 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
209 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x29, 0x01,
210 0x29, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x01,
211 0x0f, 0x01, 0x09, 0x01, 0x0f, 0x01, 0x0f, 0x29,
212 0x01, 0x09, 0x01, 0x0f, 0x01, 0x29, 0x01, 0x09,
213 0x01, 0x0f, 0x01, 0x09, 0x01, 0x0f, 0x01, 0x0f,
214 0x01, 0x0f, 0x01, 0x00, 0x01, 0x00};
215
216 /**
217 * The seed array used with VALCONST to populate CHARFLAGS.
218 */
219 private static final int [] LENCONST = new int [] {
220 9, 2, 2, 1, 18, 1, 1, 2,
221 9, 2, 1, 10, 1, 2, 1, 1,
222 2, 26, 4, 1, 1, 26, 3, 1,
223 56, 1, 8, 23, 1, 31, 1, 58,
224 2, 11, 2, 8, 1, 53, 1, 68,
225 9, 36, 3, 2, 4, 30, 56, 89,
226 18, 7, 14, 2, 46, 70, 26, 2,
227 36, 1, 1, 3, 1, 1, 1, 20,
228 1, 44, 1, 7, 3, 1, 1, 1,
229 1, 1, 1, 1, 1, 18, 13, 12,
230 1, 66, 1, 12, 1, 36, 1, 4,
231 9, 53, 2, 2, 2, 2, 3, 28,
232 2, 8, 2, 2, 55, 38, 2, 1,
233 7, 38, 10, 17, 1, 23, 1, 3,
234 1, 1, 1, 2, 1, 1, 11, 27,
235 5, 3, 46, 26, 5, 1, 10, 8,
236 13, 10, 6, 1, 71, 2, 5, 1,
237 15, 1, 4, 1, 1, 15, 2, 2,
238 1, 4, 2, 10, 519, 3, 1, 53,
239 2, 1, 1, 16, 3, 4, 3, 10,
240 2, 2, 10, 17, 3, 1, 8, 2,
241 2, 2, 22, 1, 7, 1, 1, 3,
242 4, 2, 1, 1, 7, 2, 2, 2,
243 3, 9, 1, 4, 2, 1, 3, 2,
244 2, 10, 2, 16, 1, 2, 6, 4,
245 2, 2, 22, 1, 7, 1, 2, 1,
246 2, 1, 2, 2, 1, 1, 5, 4,
247 2, 2, 3, 11, 4, 1, 1, 7,
248 10, 2, 3, 12, 3, 1, 7, 1,
249 1, 1, 3, 1, 22, 1, 7, 1,
250 2, 1, 5, 2, 1, 1, 8, 1,
251 3, 1, 3, 18, 1, 5, 10, 17,
252 3, 1, 8, 2, 2, 2, 22, 1,
253 7, 1, 2, 2, 4, 2, 1, 1,
254 6, 3, 2, 2, 3, 8, 2, 4,
255 2, 1, 3, 4, 10, 18, 2, 1,
256 6, 3, 3, 1, 4, 3, 2, 1,
257 1, 1, 2, 3, 2, 3, 3, 3,
258 8, 1, 3, 4, 5, 3, 3, 1,
259 4, 9, 1, 15, 9, 17, 3, 1,
260 8, 1, 3, 1, 23, 1, 10, 1,
261 5, 4, 7, 1, 3, 1, 4, 7,
262 2, 9, 2, 4, 10, 18, 2, 1,
263 8, 1, 3, 1, 23, 1, 10, 1,
264 5, 4, 7, 1, 3, 1, 4, 7,
265 2, 7, 1, 1, 2, 4, 10, 18,
266 2, 1, 8, 1, 3, 1, 23, 1,
267 16, 4, 6, 2, 3, 1, 4, 9,
268 1, 8, 2, 4, 10, 145, 46, 1,
269 1, 1, 2, 7, 5, 6, 1, 8,
270 1, 10, 39, 2, 1, 1, 2, 2,
271 1, 1, 2, 1, 6, 4, 1, 7,
272 1, 3, 1, 1, 1, 1, 2, 2,
273 1, 2, 1, 1, 1, 2, 6, 1,
274 2, 1, 2, 5, 1, 1, 1, 6,
275 2, 10, 62, 2, 6, 10, 11, 1,
276 1, 1, 1, 1, 4, 2, 8, 1,
277 33, 7, 20, 1, 6, 4, 6, 1,
278 1, 1, 21, 3, 7, 1, 1, 230,
279 38, 10, 39, 9, 1, 1, 2, 1,
280 3, 1, 1, 1, 2, 1, 5, 41,
281 1, 1, 1, 1, 1, 11, 1, 1,
282 1, 1, 1, 3, 2, 3, 1, 5,
283 3, 1, 1, 1, 1, 1, 1, 1,
284 1, 3, 2, 3, 2, 1, 1, 40,
285 1, 9, 1, 2, 1, 2, 2, 7,
286 2, 1, 1, 1, 7, 40, 1, 4,
287 1, 8, 1, 3078, 156, 4, 90, 6,
288 22, 2, 6, 2, 38, 2, 6, 2,
289 8, 1, 1, 1, 1, 1, 1, 1,
290 31, 2, 53, 1, 7, 1, 1, 3,
291 3, 1, 7, 3, 4, 2, 6, 4,
292 13, 5, 3, 1, 7, 211, 13, 4,
293 1, 68, 1, 3, 2, 2, 1, 81,
294 3, 3714, 1, 1, 1, 25, 9, 6,
295 1, 5, 11, 84, 4, 2, 2, 2,
296 2, 90, 1, 3, 6, 40, 7379, 20902,
297 3162, 11172, 92, 2048, 8190, 2};
298
299 /**
300 * The number of characters in Java.
301 */
302 private static final int CHARCNT = Character.MAX_VALUE + 1;
303
304 /**
305 * An array of byte where each byte represents the roles that the
306 * corresponding character can play. Use the bit mask values
307 * to access each character's role.
308 */
309 private static final byte[] CHARFLAGS = buildBitFlags();
310
311 /**
312 * Convert the two compressed arrays in to th CHARFLAGS array.
313 * @return the CHARFLAGS array.
314 */
315 private static final byte[] buildBitFlags() {
316 final byte[] ret = new byte[CHARCNT];
317 int index = 0;
318 for (int i = 0; i < VALCONST.length; i++) {
319 // v represents the roles a character can play.
320 final byte v = VALCONST[i];
321 // l is the number of consecutive chars that have the same
322 // roles 'v'
323 int l = LENCONST[i];
324 // we need to give the next 'l' chars the role bits 'v'
325 while (--l >= 0) {
326 ret[index++] = v;
327 }
328 }
329 return ret;
330 }
331
332 /** Mask used to test for {@link #isXMLCharacter(int)} */
333 private static final byte MASKXMLCHARACTER = 1 << 0;
334 /** Mask used to test for {@link #isXMLLetter(char)} */
335 private static final byte MASKXMLLETTER = 1 << 1;
336 /** Mask used to test for {@link #isXMLNameStartCharacter(char)} */
337 private static final byte MASKXMLSTARTCHAR = 1 << 2;
338 /** Mask used to test for {@link #isXMLNameCharacter(char)} */
339 private static final byte MASKXMLNAMECHAR = 1 << 3;
340 /** Mask used to test for {@link #isXMLDigit(char)} */
341 private static final byte MASKXMLDIGIT = 1 << 4;
342 /** Mask used to test for {@link #isXMLCombiningChar(char)} */
343 private static final byte MASKXMLCOMBINING = 1 << 5;
344 /** Mask used to test for {@link #isURICharacter(char)} */
345 private static final byte MASKURICHAR = 1 << 6;
346 /** Mask used to test for {@link #isXMLLetterOrDigit(char)} */
347 private static final byte MASKXMLLETTERORDIGIT = MASKXMLLETTER | MASKXMLDIGIT;
348
349 /**
350 * Ensure instantation cannot occur.
351 */
352 private Verifier() { }
353
354 private static final String checkJDOMName(final String name) {
355 // Check basic XML name rules first
356 // Cannot be empty or null
357 if (name == null) {
358 return "XML names cannot be null";
359 }
360
361 //final int len = name.length();
362 if (name.length() == 0) {
363 return "XML names cannot be empty";
364 }
365
366 // Cannot start with a number
367 if ((byte)0 == (CHARFLAGS[name.charAt(0)] & MASKXMLSTARTCHAR)) {
368 return "XML name '" + name + "' cannot begin with the character \"" +
369 name.charAt(0) + "\"";
370 }
371 // Ensure legal content for non-first chars
372 // also check char 0 to catch colon char ':'
373 for (int i = name.length() - 1; i >= 1; i--) {
374 if ((byte)0 == (byte)(CHARFLAGS[name.charAt(i)] & MASKXMLNAMECHAR)) {
375 return "XML name '" + name + "' cannot contain the character \""
376 + name.charAt(i) + "\"";
377 }
378 }
379
380 // If we got here, everything is OK
381 return null;
382 }
383
384 /**
385 * This will check the supplied name to see if it is legal for use as
386 * a JDOM <code>{@link Element}</code> name.
387 *
388 * @param name <code>String</code> name to check.
389 * @return <code>String</code> reason name is illegal, or
390 * <code>null</code> if name is OK.
391 */
392 public static String checkElementName(final String name) {
393 return checkJDOMName(name);
394 }
395
396 /**
397 * This will check the supplied name to see if it is legal for use as
398 * a JDOM <code>{@link Attribute}</code> name.
399 *
400 * @param name <code>String</code> name to check.
401 * @return <code>String</code> reason name is illegal, or
402 * <code>null</code> if name is OK.
403 */
404 public static String checkAttributeName(final String name) {
405 // Attribute names may not be xmlns since we do this internally too
406 if ("xmlns".equals(name)) {
407 return "An Attribute name may not be \"xmlns\"; " +
408 "use the Namespace class to manage namespaces";
409 }
410
411 return checkJDOMName(name);
412 }
413
414 /**
415 * This will check the supplied string to see if it only contains
416 * characters allowed by the XML 1.0 specification. The C0 controls
417 * (e.g. null, vertical tab, form-feed, etc.) are specifically excluded
418 * except for carriage return, line-feed, and the horizontal tab.
419 * Surrogates are also excluded.
420 * <p>
421 * This method is useful for checking element content and attribute
422 * values. Note that characters
423 * like " and &lt; are allowed in attribute values and element content.
424 * They will simply be escaped as &quot; or &lt;
425 * when the value is serialized.
426 * </p>
427 *
428 * @param text <code>String</code> value to check.
429 * @return <code>String</code> reason name is illegal, or
430 * <code>null</code> if name is OK.
431 */
432 public static String checkCharacterData(final String text) {
433 if (text == null) {
434 return "A null is not a legal XML value";
435 }
436
437 final int len = text.length();
438 for (int i = 0; i < len; i++) {
439 // we are expecting a normal char, but may be a surrogate.
440 // the isXMLCharacter method takes an int argument, but we have a char.
441 // we save a lot of time by doing the test directly here without
442 // doing the unnecessary cast-to-int and double-checking ranges
443 // for the char.
444 // Also, note that we only need to check for non-zero flags, instead
445 // of checking for an actual bit, because all the other
446 // character roles are a pure subset of CharacterData. Put another way,
447 // any character with any bit set, will always also have the
448 // CharacterData bit set.
449 while (CHARFLAGS[text.charAt(i)] != (byte)0) {
450 // fast-loop through the chars until we find something that's not.
451 if (++i == len) {
452 // we passed all the characters...
453 return null;
454 }
455 }
456 // the character is not a normal character.
457 // we need to sort out what it is. Neither high nor low
458 // surrogate pairs are valid characters, so they will get here.
459
460 if (isHighSurrogate(text.charAt(i))) {
461 // we have the valid high char of a pair.
462 // we will expect the low char on the next index,
463 i++;
464 if (i >= len) {
465 return String.format("Truncated Surrogate Pair 0x%04x????",
466 (int)text.charAt(i - 1));
467 }
468 if (isLowSurrogate(text.charAt(i))) {
469 // we now have the low char of a pair, decode and validate
470 if (!isXMLCharacter(decodeSurrogatePair(
471 text.charAt(i - 1), text.charAt(i)))) {
472 // Likely this character can't be easily displayed
473 // because it's a control so we use it'd hexadecimal
474 // representation in the reason.
475 return String.format("0x%06x is not a legal XML character",
476 decodeSurrogatePair(
477 text.charAt(i - 1), text.charAt(i)));
478 }
479 } else {
480 // we got a normal character, but we wanted a low surrogate
481 return String.format("Illegal Surrogate Pair 0x%04x%04x",
482 (int)text.charAt(i - 1), (int)text.charAt(i));
483 }
484 } else {
485 // Likely this character can't be easily displayed
486 // because it's a control so we use its hexadecimal
487 // representation in the reason.
488 return String.format("0x%04x is not a legal XML character",
489 (int)text.charAt(i));
490 }
491 }
492
493 // If we got here, everything is OK
494 return null;
495 }
496
497 /**
498 * This will check the supplied data to see if it is legal for use as
499 * JDOM <code>{@link CDATA}</code>.
500 *
501 * @param data <code>String</code> data to check.
502 * @return <code>String</code> reason data is illegal, or
503 * <code>null</code> is name is OK.
504 */
505 public static String checkCDATASection(final String data) {
506 String reason = null;
507 if ((reason = checkCharacterData(data)) != null) {
508 return reason;
509 }
510
511 if (data.indexOf("]]>") != -1) {
512 return "CDATA cannot internally contain a CDATA ending " +
513 "delimiter (]]>)";
514 }
515
516 // If we got here, everything is OK
517 return null;
518 }
519
520 /**
521 * This will check the supplied name to see if it is legal for use as
522 * a JDOM <code>{@link Namespace}</code> prefix.
523 *
524 * @param prefix <code>String</code> prefix to check.
525 * @return <code>String</code> reason name is illegal, or
526 * <code>null</code> if name is OK.
527 */
528 public static String checkNamespacePrefix(final String prefix) {
529 // Manually do rules, since URIs can be null or empty
530 if ((prefix == null) || (prefix.equals(""))) {
531 return null;
532 }
533
534 if (checkJDOMName(prefix) != null) {
535 // will double-check null and empty names, but that's OK
536 // since we have already checked them.
537 return checkJDOMName(prefix);
538 }
539
540 // Cannot start with "xml" in any character case
541 /* See Issue 126 - https://github.com/hunterhacker/jdom/issues/126
542 if (prefix.length() >= 3) {
543 if (prefix.charAt(0) == 'x' || prefix.charAt(0) == 'X') {
544 if (prefix.charAt(1) == 'm' || prefix.charAt(1) == 'M') {
545 if (prefix.charAt(2) == 'l' || prefix.charAt(2) == 'L') {
546 return "Namespace prefixes cannot begin with " +
547 "\"xml\" in any combination of case";
548 }
549 }
550 }
551 }
552 */
553
554 // If we got here, everything is OK
555 return null;
556 }
557
558 /**
559 * This will check the supplied name to see if it is legal for use as
560 * a JDOM <code>{@link Namespace}</code> URI.
561 * <p>
562 * This is a 'light' test of URI's designed to filter out only the worst
563 * illegal URIs. It tests only to ensure the first character is valid. A
564 * comprehensive URI validation process would be impractical.
565 *
566 * @param uri <code>String</code> URI to check.
567 * @return <code>String</code> reason name is illegal, or
568 * <code>null</code> if name is OK.
569 */
570 public static String checkNamespaceURI(final String uri) {
571 // Manually do rules, since URIs can be null or empty
572 if ((uri == null) || (uri.equals(""))) {
573 return null;
574 }
575
576 // Cannot start with a number
577 final char first = uri.charAt(0);
578 if (Character.isDigit(first)) {
579 return "Namespace URIs cannot begin with a number";
580 }
581 // Cannot start with a $
582 if (first == '$') {
583 return "Namespace URIs cannot begin with a dollar sign ($)";
584 }
585 // Cannot start with a -
586 if (first == '-') {
587 return "Namespace URIs cannot begin with a hyphen (-)";
588 }
589
590 // Cannot start with space...
591 if (isXMLWhitespace(first)) {
592 return "Namespace URIs cannot begin with white-space";
593 }
594
595 // If we got here, everything is OK
596 return null;
597 }
598
599 /**
600 * Check if two namespaces collide.
601 *
602 * @param namespace <code>Namespace</code> to check.
603 * @param other <code>Namespace</code> to check against.
604 * @return <code>String</code> reason for collision, or
605 * <code>null</code> if no collision.
606 */
607 public static String checkNamespaceCollision(final Namespace namespace,
608 final Namespace other) {
609 String p1,p2,u1,u2,reason;
610
611 reason = null;
612 p1 = namespace.getPrefix();
613 u1 = namespace.getURI();
614 p2 = other.getPrefix();
615 u2 = other.getURI();
616 if (p1.equals(p2) && !u1.equals(u2)) {
617 reason = "The namespace prefix \"" + p1 + "\" collides";
618 }
619 return reason;
620 }
621
622 /**
623 * Check if <code>{@link Attribute}</code>'s namespace collides with a
624 * <code>{@link Element}</code>'s namespace.
625 *
626 * @param attribute <code>Attribute</code> to check.
627 * @param element <code>Element</code> to check against.
628 * @return <code>String</code> reason for collision, or
629 * <code>null</code> if no collision.
630 */
631 public static String checkNamespaceCollision(final Attribute attribute,
632 final Element element) {
633 return checkNamespaceCollision(attribute, element, -1);
634 }
635
636 /**
637 * Check if <code>{@link Attribute}</code>'s namespace collides with a
638 * <code>{@link Element}</code>'s namespace.
639 *
640 * @param attribute <code>Attribute</code> to check.
641 * @param element <code>Element</code> to check against.
642 * @param ignoreatt Ignore a specific Attribute (if it exists) when
643 * calculating any collisions (used when replacing one attribute
644 * with another).
645 * @return <code>String</code> reason for collision, or
646 * <code>null</code> if no collision.
647 */
648 public static String checkNamespaceCollision(final Attribute attribute,
649 final Element element, final int ignoreatt) {
650 final Namespace namespace = attribute.getNamespace();
651 final String prefix = namespace.getPrefix();
652 if ("".equals(prefix)) {
653 return null;
654 }
655
656 return checkNamespaceCollision(namespace, element, ignoreatt);
657 }
658
659 /**
660 * Check if a <code>{@link Namespace}</code> collides with a
661 * <code>{@link Element}</code>'s namespace.
662 *
663 * @param namespace <code>Namespace</code> to check.
664 * @param element <code>Element</code> to check against.
665 * @return <code>String</code> reason for collision, or
666 * <code>null</code> if no collision.
667 */
668 public static String checkNamespaceCollision(final Namespace namespace,
669 final Element element) {
670 return checkNamespaceCollision(namespace, element, -1);
671 }
672
673 /**
674 * Check if a <code>{@link Namespace}</code> collides with a
675 * <code>{@link Element}</code>'s namespace.
676 *
677 * @param namespace <code>Namespace</code> to check.
678 * @param element <code>Element</code> to check against.
679 * @param ignoreatt Ignore a specific Attribute (if it exists) when
680 * calculating any collisions (used when replacing one attribute
681 * with another).
682 * @return <code>String</code> reason for collision, or
683 * <code>null</code> if no collision.
684 */
685 public static String checkNamespaceCollision(final Namespace namespace,
686 final Element element, final int ignoreatt) {
687 String reason = checkNamespaceCollision(namespace,
688 element.getNamespace());
689 if (reason != null) {
690 return reason + " with the element namespace prefix";
691 }
692
693 if (element.hasAdditionalNamespaces()) {
694 reason = checkNamespaceCollision(namespace,
695 element.getAdditionalNamespaces());
696 if (reason != null) {
697 return reason;
698 }
699 }
700
701 if (element.hasAttributes()) {
702 reason = checkNamespaceCollision(namespace, element.getAttributes(), ignoreatt);
703 if (reason != null) {
704 return reason;
705 }
706 }
707
708 return null;
709 }
710
711 /**
712 * Check if a <code>{@link Namespace}</code> collides with a
713 * <code>{@link Attribute}</code>'s namespace.
714 *
715 * @param namespace <code>Namespace</code> to check.
716 * @param attribute <code>Attribute</code> to check against.
717 * @return <code>String</code> reason for collision, or
718 * <code>null</code> if no collision.
719 */
720 public static String checkNamespaceCollision(final Namespace namespace,
721 final Attribute attribute) {
722 String reason = null;
723 if (!attribute.getNamespace().equals(Namespace.NO_NAMESPACE)) {
724 reason = checkNamespaceCollision(namespace,
725 attribute.getNamespace());
726 if (reason != null) {
727 reason += " with an attribute namespace prefix on the element";
728 }
729 }
730 return reason;
731 }
732
733 /**
734 * Check if a <code>{@link Namespace}</code> collides with any namespace
735 * from a list of objects.
736 *
737 * @param namespace <code>Namespace</code> to check.
738 * @param list <code>List</code> to check against.
739 * @return <code>String</code> reason for collision, or
740 * <code>null</code> if no collision.
741 */
742 public static String checkNamespaceCollision(final Namespace namespace,
743 final List<?> list) {
744 return checkNamespaceCollision(namespace, list, -1);
745 }
746
747 /**
748 * Check if a <code>{@link Namespace}</code> collides with any namespace
749 * from a list of objects.
750 *
751 * @param namespace <code>Namespace</code> to check.
752 * @param list <code>List</code> to check against.
753 * @param ignoreatt Ignore a specific Attribute (if it exists) when
754 * calculating any collisions (used when replacing one attribute
755 * with another).
756 * @return <code>String</code> reason for collision, or
757 * <code>null</code> if no collision.
758 */
759 public static String checkNamespaceCollision(final Namespace namespace,
760 final List<?> list, final int ignoreatt) {
761 if (list == null) {
762 return null;
763 }
764
765 String reason = null;
766 final Iterator<?> i = list.iterator();
767 int cnt = -1;
768 while ((reason == null) && i.hasNext()) {
769 final Object obj = i.next();
770 cnt++;
771 if (obj instanceof Attribute) {
772 if (cnt == ignoreatt) {
773 continue;
774 }
775 reason = checkNamespaceCollision(namespace, (Attribute) obj);
776 }
777 else if (obj instanceof Element) {
778 reason = checkNamespaceCollision(namespace, (Element) obj);
779 }
780 else if (obj instanceof Namespace) {
781 reason = checkNamespaceCollision(namespace, (Namespace) obj);
782 if (reason != null) {
783 reason += " with an additional namespace declared" +
784 " by the element";
785 }
786 }
787 }
788 return reason;
789 }
790
791 /**
792 * This will check the supplied data to see if it is legal for use as
793 * a JDOM <code>{@link ProcessingInstruction}</code> target.
794 *
795 * @param target <code>String</code> target to check.
796 * @return <code>String</code> reason target is illegal, or
797 * <code>null</code> if target is OK.
798 */
799 public static String checkProcessingInstructionTarget(final String target) {
800 // Check basic XML name rules first
801 String reason;
802 if ((reason = checkXMLName(target)) != null) {
803 return reason;
804 }
805
806 // No colons allowed, per Namespace Specification Section 6
807 if (target.indexOf(":") != -1) {
808 return "Processing instruction targets cannot contain colons";
809 }
810
811 // Cannot begin with 'xml' in any case
812 if (target.equalsIgnoreCase("xml")) {
813 return "Processing instructions cannot have a target of " +
814 "\"xml\" in any combination of case. (Note that the " +
815 "\"<?xml ... ?>\" declaration at the beginning of a " +
816 "document is not a processing instruction and should not " +
817 "be added as one; it is written automatically during " +
818 "output, e.g. by XMLOutputter.)";
819 }
820
821 // If we got here, everything is OK
822 return null;
823 }
824
825 /**
826 * This will check the supplied data to see if it is legal for use as
827 * <code>{@link ProcessingInstruction}</code> data. Besides checking that
828 * all the characters are allowed in XML, this also checks
829 * that the data does not contain the PI end-string "?&gt;".
830 *
831 * @param data <code>String</code> data to check.
832 * @return <code>String</code> reason data is illegal, or
833 * <code>null</code> if data is OK.
834 */
835 public static String checkProcessingInstructionData(final String data) {
836 // Check basic XML name rules first
837 final String reason = checkCharacterData(data);
838
839 if (reason == null) {
840 if (data.indexOf("?>") >= 0) {
841 return "Processing instructions cannot contain " +
842 "the string \"?>\"";
843 }
844 }
845
846 return reason;
847 }
848
849 /**
850 * This will check the supplied data to see if it is legal for use as
851 * JDOM <code>{@link Comment}</code> data.
852 *
853 * @param data <code>String</code> data to check.
854 * @return <code>String</code> reason data is illegal, or
855 * <code>null</code> if data is OK.
856 */
857 public static String checkCommentData(final String data) {
858 String reason = null;
859 if ((reason = checkCharacterData(data)) != null) {
860 return reason;
861 }
862
863 if (data.indexOf("--") != -1) {
864 return "Comments cannot contain double hyphens (--)";
865 }
866 if (data.endsWith("-")) {
867 return "Comment data cannot end with a hyphen.";
868 }
869
870 // If we got here, everything is OK
871 return null;
872 }
873 /**
874 * This is a utility function to decode a non-BMP
875 * UTF-16 surrogate pair.
876 * @param high high 16 bits
877 * @param low low 16 bits
878 * @return decoded character
879 */
880 public static int decodeSurrogatePair(final char high, final char low) {
881 return 0x10000 + (high - 0xD800) * 0x400 + (low - 0xDC00);
882 }
883
884 /**
885 * This will check the supplied data to see if it is legal for use as
886 * PublicID (in a {@link DocType} or {@link EntityRef}).
887 *
888 * @param c the character to validate
889 * @return <code>String</code> reason <i>c</i> is illegal, or
890 * <code>null</code> if <i>c</i> is OK.
891 */
892 public static boolean isXMLPublicIDCharacter(final char c) {
893 // [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] |
894 // [-'()+,./:=?;*#@$_%]
895
896 if (c >= 'a' && c <= 'z') return true;
897 if (c >= '?' && c <= 'Z') return true;
898 if (c >= '\'' && c <= ';') return true;
899
900 if (c == ' ') return true;
901 if (c == '!') return true;
902 if (c == '=') return true;
903 if (c == '#') return true;
904 if (c == '$') return true;
905 if (c == '_') return true;
906 if (c == '%') return true;
907 if (c == '\n') return true;
908 if (c == '\r') return true;
909 if (c == '\t') return true;
910
911 return false;
912 }
913
914 /**
915 * This will ensure that the data for a public identifier
916 * is legal.
917 *
918 * @param publicID <code>String</code> public ID to check.
919 * @return <code>String</code> reason public ID is illegal, or
920 * <code>null</code> if public ID is OK.
921 */
922 public static String checkPublicID(final String publicID) {
923 String reason = null;
924
925 if (publicID == null) return null;
926 // This indicates there is no public ID
927
928 for (int i = 0; i < publicID.length(); i++) {
929 final char c = publicID.charAt(i);
930 if (!isXMLPublicIDCharacter(c)) {
931 reason = c + " is not a legal character in public IDs";
932 break;
933 }
934 }
935
936 return reason;
937 }
938
939
940 /**
941 * This will ensure that the data for a system literal
942 * is legal.
943 *
944 * @param systemLiteral <code>String</code> system literal to check.
945 * @return <code>String</code> reason system literal is illegal, or
946 * <code>null</code> if system literal is OK.
947 */
948 public static String checkSystemLiteral(final String systemLiteral) {
949 String reason = null;
950
951 if (systemLiteral == null) return null;
952 // This indicates there is no system ID
953
954 if (systemLiteral.indexOf('\'') != -1
955 && systemLiteral.indexOf('"') != -1) {
956 reason =
957 "System literals cannot simultaneously contain both single and double quotes.";
958 }
959 else {
960 reason = checkCharacterData(systemLiteral);
961 }
962
963 return reason;
964 }
965
966 /**
967 * This is a utility function for sharing the base process of checking
968 * any XML name.
969 *
970 * @param name <code>String</code> to check for XML name compliance.
971 * @return <code>String</code> reason the name is illegal, or
972 * <code>null</code> if OK.
973 */
974 public static String checkXMLName(final String name) {
975 // Cannot be empty or null
976 if ((name == null)) {
977 return "XML names cannot be null";
978 }
979
980 final int len = name.length();
981 if (len == 0) {
982 return "XML names cannot be empty";
983 }
984
985
986 // Cannot start with a number
987 if (!isXMLNameStartCharacter(name.charAt(0))) {
988 return "XML names cannot begin with the character \"" +
989 name.charAt(0) + "\"";
990 }
991 // Ensure legal content for non-first chars
992 for (int i = 1; i < len; i++) {
993 if (!isXMLNameCharacter(name.charAt(i))) {
994 return "XML names cannot contain the character \"" + name.charAt(i) + "\"";
995 }
996 }
997
998 // We got here, so everything is OK
999 return null;
1000 }
1001
1002 /**
1003 * <p>
1004 * Checks a string to see if it is a legal RFC 2396 URI.
1005 * Both absolute and relative URIs are supported.
1006 * </p>
1007 *
1008 * @param uri <code>String</code> to check.
1009 * @return <code>String</code> reason the URI is illegal, or
1010 * <code>null</code> if OK.
1011 */
1012 public static String checkURI(final String uri) {
1013 // URIs can be null or empty
1014 if ((uri == null) || (uri.equals(""))) {
1015 return null;
1016 }
1017
1018 for (int i = 0; i < uri.length(); i++) {
1019 final char test = uri.charAt(i);
1020 if (!isURICharacter(test)) {
1021 String msgNumber = "0x" + Integer.toHexString(test);
1022 if (test <= 0x09) msgNumber = "0x0" + Integer.toHexString(test);
1023 return "URIs cannot contain " + msgNumber;
1024 } // end if
1025 if (test == '%') { // must be followed by two hexadecimal digits
1026 try {
1027 final char firstDigit = uri.charAt(i+1);
1028 final char secondDigit = uri.charAt(i+2);
1029 if (!isHexDigit(firstDigit) ||
1030 !isHexDigit(secondDigit)) {
1031 return "Percent signs in URIs must be followed by "
1032 + "exactly two hexadecimal digits.";
1033 }
1034
1035 }
1036 catch (final StringIndexOutOfBoundsException e) {
1037 return "Percent signs in URIs must be followed by "
1038 + "exactly two hexadecimal digits.";
1039 }
1040 }
1041 } // end for
1042
1043 // If we got here, everything is OK
1044 return null;
1045 }
1046
1047 /**
1048 * <p>
1049 * This is a utility function for determining whether a specified
1050 * Unicode character is a hexadecimal digit as defined in RFC 2396;
1051 * that is, one of the ASCII characters 0-9, a-f, or A-F.
1052 * </p>
1053 *
1054 * @param c to check for hex digit.
1055 * @return true if it's allowed, false otherwise.
1056 */
1057 public static boolean isHexDigit(final char c) {
1058
1059 // I suspect most characters passed to this method will be
1060 // correct hexadecimal digits, so I test for the true cases
1061 // first. If this proves to be a performance bottleneck
1062 // a switch statement or lookup table
1063 // might optimize this.
1064 if (c >= '0' && c <= '9') return true;
1065 if (c >= 'A' && c <= 'F') return true;
1066 if (c >= 'a' && c <= 'f') return true;
1067
1068 return false;
1069 }
1070
1071 /**
1072 * This is a function for determining whether the
1073 * specified character is the high 16 bits in a
1074 * UTF-16 surrogate pair.
1075 * @param ch character to check
1076 * @return true if the character is a high surrogate, false otherwise
1077 */
1078 public static boolean isHighSurrogate(final char ch) {
1079 // faster way to do it is with bit manipulation....
1080 // return (ch >= 0xD800 && ch <= 0xDBFF);
1081 // A high surrogate has the bit pattern:
1082 // 110110xx xxxxxxxx
1083 // ch & 0xFC00 does a bit-mask of the most significant 6 bits (110110)
1084 // return 0xD800 == (ch & 0xFC00);
1085 // as it happens, it is faster to do a bit-shift,
1086 return 0x36 == ch >>> 10;
1087 }
1088
1089 /**
1090 * This is a function for determining whether the
1091 * specified character is the low 16 bits in a
1092 * UTF-16 surrogate pair.
1093 * @param ch character to check
1094 * @return true if the character is a low surrogate, false otherwise.
1095 */
1096 public static boolean isLowSurrogate(final char ch) {
1097 // faster way to do it is with bit manipulation....
1098 // return (ch >= 0xDC00 && ch <= 0xDFFF);
1099 return 0x37 == ch >>> 10;
1100 }
1101
1102 /**
1103 * <p>
1104 * This is a utility function for determining whether
1105 * a specified Unicode character is legal in URI references
1106 * as determined by RFC 2396.
1107 * </p>
1108 *
1109 * @param c <code>char</code> to check for URI reference compliance.
1110 * @return true if it's allowed, false otherwise.
1111 */
1112 public static boolean isURICharacter(final char c) {
1113 return (byte)0 != (byte)(CHARFLAGS[c] & MASKURICHAR);
1114 }
1115
1116 /**
1117 * This is a utility function for determining whether a specified
1118 * character is a character according to production 2 of the
1119 * XML 1.0 specification.
1120 *
1121 * @param c <code>char</code> to check for XML compliance
1122 * @return <code>boolean</code> true if it's a character,
1123 * false otherwise
1124 */
1125 public static boolean isXMLCharacter(final int c) {
1126 if (c >= CHARCNT) {
1127 return c <= 0x10FFFF;
1128 }
1129 return (byte)0 != (byte)(CHARFLAGS[c] & MASKXMLCHARACTER);
1130 }
1131
1132
1133 /**
1134 * This is a utility function for determining whether a specified
1135 * character is a name character according to production 4 of the
1136 * XML 1.0 specification.
1137 *
1138 * @param c <code>char</code> to check for XML name compliance.
1139 * @return <code>boolean</code> true if it's a name character,
1140 * false otherwise.
1141 */
1142 public static boolean isXMLNameCharacter(final char c) {
1143 return (byte)0 != (byte)(CHARFLAGS[c] & MASKXMLNAMECHAR) || c == ':';
1144 }
1145
1146 /**
1147 * This is a utility function for determining whether a specified
1148 * character is a legal name start character according to production 5
1149 * of the XML 1.0 specification. This production does allow names
1150 * to begin with colons which the Namespaces in XML Recommendation
1151 * disallows.
1152 *
1153 * @param c <code>char</code> to check for XML name start compliance.
1154 * @return <code>boolean</code> true if it's a name start character,
1155 * false otherwise.
1156 */
1157 public static boolean isXMLNameStartCharacter(final char c) {
1158 return (byte)0 != (byte)(CHARFLAGS[c] & MASKXMLSTARTCHAR) || c == ':';
1159 }
1160
1161 /**
1162 * This is a utility function for determining whether a specified
1163 * character is a letter or digit according to productions 84 and 88
1164 * of the XML 1.0 specification.
1165 *
1166 * @param c <code>char</code> to check.
1167 * @return <code>boolean</code> true if it's letter or digit,
1168 * false otherwise.
1169 */
1170 public static boolean isXMLLetterOrDigit(final char c) {
1171 return (byte)0 != (byte)(CHARFLAGS[c] & MASKXMLLETTERORDIGIT);
1172 }
1173
1174 /**
1175 * This is a utility function for determining whether a specified character
1176 * is a letter according to production 84 of the XML 1.0 specification.
1177 *
1178 * @param c <code>char</code> to check for XML name compliance.
1179 * @return <code>String</code> true if it's a letter, false otherwise.
1180 */
1181 public static boolean isXMLLetter(final char c) {
1182 return (byte)0 != (byte)(CHARFLAGS[c] & MASKXMLLETTER);
1183 }
1184
1185 /**
1186 * This is a utility function for determining whether a specified character
1187 * is a combining character according to production 87
1188 * of the XML 1.0 specification.
1189 *
1190 * @param c <code>char</code> to check.
1191 * @return <code>boolean</code> true if it's a combining character,
1192 * false otherwise.
1193 */
1194 public static boolean isXMLCombiningChar(final char c) {
1195 return (byte)0 != (byte)(CHARFLAGS[c] & MASKXMLCOMBINING);
1196 }
1197
1198 /**
1199 * This is a utility function for determining whether a specified
1200 * character is an extender according to production 88 of the XML 1.0
1201 * specification.
1202 *
1203 * @param c <code>char</code> to check.
1204 * @return <code>String</code> true if it's an extender, false otherwise.
1205 */
1206 public static boolean isXMLExtender(final char c) {
1207 /*
1208 * This function is not accellerated by the bitmask system because
1209 * there are no longer any actual calls to it from the JDOM code.
1210 * It used to be called by the isXMLNameCharacter() method before
1211 * the bitmask optimization. Now the VerifierBuilder code actually
1212 * calls this method instead.
1213 */
1214
1215 if (c < 0x00B6) return false; // quick short circuit
1216
1217 // Extenders
1218 if (c == 0x00B7) return true;
1219 if (c == 0x02D0) return true;
1220 if (c == 0x02D1) return true;
1221 if (c == 0x0387) return true;
1222 if (c == 0x0640) return true;
1223 if (c == 0x0E46) return true;
1224 if (c == 0x0EC6) return true;
1225 if (c == 0x3005) return true;
1226
1227 if (c < 0x3031) return false; if (c <= 0x3035) return true;
1228 if (c < 0x309D) return false; if (c <= 0x309E) return true;
1229 if (c < 0x30FC) return false; if (c <= 0x30FE) return true;
1230
1231 return false;
1232
1233 }
1234
1235 /**
1236 * This is a utility function for determining whether a specified
1237 * Unicode character
1238 * is a digit according to production 88 of the XML 1.0 specification.
1239 *
1240 * @param c <code>char</code> to check for XML digit compliance
1241 * @return <code>boolean</code> true if it's a digit, false otherwise
1242 */
1243 public static boolean isXMLDigit(final char c) {
1244 return (byte)0 != (byte)(CHARFLAGS[c] & MASKXMLDIGIT);
1245 }
1246
1247 /**
1248 * This is a utility function for determining whether a specified
1249 * Unicode character is a whitespace character according to production 3
1250 * of the XML 1.0 specification.
1251 *
1252 * @param c <code>char</code> to check for XML whitespace compliance
1253 * @return <code>boolean</code> true if it's a whitespace, false otherwise
1254 */
1255 public static boolean isXMLWhitespace(final char c) {
1256 // the following if is faster than switch statements.
1257 // seems the implicit conversion to int is slower than
1258 // the fall-through or's
1259 if (c==' ' || c=='\n' || c=='\t' || c=='\r' ){
1260 return true;
1261 }
1262 return false;
1263 }
1264
1265 /**
1266 * This is a utility function for determining whether a specified
1267 * String is a whitespace character according to production 3
1268 * of the XML 1.0 specification.
1269 * <p>
1270 * This method delegates the individual calls for each character to
1271 * {@link #isXMLWhitespace(char)}.
1272 *
1273 * @param value
1274 * The value to inspect
1275 * @return true if all characters in the input value are all whitespace
1276 * (or the string is the empty-string).
1277 * @since JDOM2
1278 */
1279 public static final boolean isAllXMLWhitespace(final String value) {
1280 // Doing the count-down instead of a count-up saves a single int
1281 // variable declaration.
1282 int i = value.length();
1283 while (--i >= 0) {
1284 if (!isXMLWhitespace(value.charAt(i))) {
1285 return false;
1286 }
1287 }
1288 return true;
1289 }
1290
1291
1292 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.adapters;
55
56 import java.lang.reflect.InvocationTargetException;
57 import java.lang.reflect.Method;
58
59 import org.jdom.DocType;
60 import org.jdom.JDOMException;
61 import org.w3c.dom.DOMImplementation;
62 import org.w3c.dom.Document;
63 import org.w3c.dom.DocumentType;
64 import org.w3c.dom.Element;
65
66 /**
67 * A DOMAdapter utility abstract base class. Uses the concrete implementation
68 * to build a org.w3c.dom.Document instance, which in turn is used to apply
69 * the DocType.
70 * <p>
71 * Special attention should be paid to the setInternalSubset protected method,
72 * which may, or may not be supported by your actual DOM implementation.
73 *
74 * @author Brett McLaughlin
75 * @author Jason Hunter
76 */
77 public abstract class AbstractDOMAdapter implements DOMAdapter {
78
79 /**
80 * This creates an empty <code>Document</code> object based
81 * on a specific parser implementation with the given DOCTYPE.
82 * If the doctype parameter is null, the behavior is the same as
83 * calling <code>createDocument()</code>.
84 *
85 * @param doctype Initial <code>DocType</code> of the document.
86 * @return <code>Document</code> - created DOM Document.
87 * @throws JDOMException when errors occur.
88 */
89 @Override
90 public Document createDocument(DocType doctype) throws JDOMException {
91 if (doctype == null) {
92 return createDocument();
93 }
94
95 DOMImplementation domImpl = createDocument().getImplementation();
96 DocumentType domDocType = domImpl.createDocumentType(
97 doctype.getElementName(),
98 doctype.getPublicID(),
99 doctype.getSystemID());
100
101 // Set the internal subset if possible
102 setInternalSubset(domDocType, doctype.getInternalSubset());
103
104 Document ret = domImpl.createDocument("http://temporary",
105 doctype.getElementName(),
106 domDocType);
107
108 Element root = ret.getDocumentElement();
109 if (root != null) {
110 ret.removeChild(root);
111 }
112
113 return ret;
114 }
115
116 /**
117 * This attempts to change the DocumentType to have the given internal DTD
118 * subset value. This is not a standard ability in DOM, so it's only
119 * available with some parsers. Subclasses can alter the mechanism by
120 * which the attempt is made to set the value.
121 *
122 * @param dt DocumentType to be altered
123 * @param s String to use as the internal DTD subset
124 */
125 protected void setInternalSubset(DocumentType dt, String s) {
126 if (dt == null || s == null) return;
127
128 // Default behavior is to attempt a setInternalSubset() call using
129 // reflection. This method is not part of the DOM spec, but it's
130 // available on Xerces 1.4.4+. It's not currently in Crimson.
131 try {
132 Class<? extends DocumentType> dtclass = dt.getClass();
133 Method setInternalSubset = dtclass.getMethod(
134 "setInternalSubset", String.class);
135 setInternalSubset.invoke(dt, s);
136 } catch (InvocationTargetException e) {
137 // ignore
138 } catch (IllegalAccessException e) {
139 // ignore
140 } catch (SecurityException e) {
141 // ignore
142 } catch (NoSuchMethodException e) {
143 // ignore
144 }
145 }
146 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.adapters;
55
56 import org.jdom.DocType;
57 import org.jdom.JDOMException;
58 import org.jdom.output.DOMOutputter;
59
60 import org.w3c.dom.Document;
61
62 /**
63 * Defines a standard set of adapter methods for interfacing with a DOM parser
64 * and obtaining a DOM {@link org.w3c.dom.Document org.w3c.dom.Document} object.
65 * Instances of this interface are used by the {@link DOMOutputter} class to
66 * create a DOM output result using the org.w3c.dom.Document implementation
67 * returned by these methods.
68 * <p>
69 * You should never need to implement this interface unless you have a specific
70 * need to use something other than the default JAXP-based mechanism.
71 * <p>
72 * JDOM only provides one 'concrete' implementation of the DOMAdapter: the
73 * {@link JAXPDOMAdapter} class. That implementation is a thread-safe and
74 * efficient implementation. It can be used as a template for building your own
75 * custom DOMAdapter implementation, if you need it.
76 * <p>
77 * The {@link AbstractDOMAdapter} class could help you by implementing the
78 * DocType-based method which leverages the base createDocument() method.
79 * <p>
80 * <strong>Special note for implementation of DOMAdapter</strong>: For backward
81 * compatibility with JDOM 1.x (which allows a class-name to be used to specify
82 * a DOMAdapter in the DOMOoutputter class), it is required that your
83 * implementations of DOMAdapter have a no-argument default constructor. If you
84 * require a constructor argument then you have to ensure that you use the
85 * correct (non-deprecated) mechanisms on DOMOutputter to specify your custom
86 * DOMAdapter.
87 *
88 *
89 * @author Brett McLaughlin
90 * @author Jason Hunter
91 */
92 public interface DOMAdapter {
93
94 /**
95 * This creates an empty <code>Document</code> object based
96 * on a specific parser implementation.
97 *
98 * @return <code>Document</code> - created DOM Document.
99 * @throws JDOMException if an error occurs.
100 */
101 public Document createDocument() throws JDOMException;
102
103 /**
104 * This creates an empty <code>Document</code> object based
105 * on a specific parser implementation with the given DOCTYPE.
106 *
107 * @param doctype Initial <code>DocType</code> of the document.
108 * @return <code>Document</code> - created DOM Document.
109 * @throws JDOMException if an error occurs.
110 */
111 public Document createDocument(DocType doctype) throws JDOMException;
112 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.adapters;
55
56 import javax.xml.parsers.DocumentBuilder;
57 import javax.xml.parsers.DocumentBuilderFactory;
58 import javax.xml.parsers.ParserConfigurationException;
59
60 import org.w3c.dom.Document;
61
62 import org.jdom.JDOMException;
63
64 /**
65 * A DOMAdapter that uses JAXP to obtain a org.w3c.dom.Document instance.
66 * <p>
67 * This class is fully thread-safe.
68 *
69 * @author Jason Hunter
70 * @author Rolf Lear
71 */
72 public class JAXPDOMAdapter extends AbstractDOMAdapter {
73
74 /**
75 * Use a Thread-local for keeping a single instance of a
76 * DocumentBuilder in memory. Thread-safe this way.
77 */
78 private static final ThreadLocal<DocumentBuilder> localbuilder =
79 new ThreadLocal<DocumentBuilder>();
80
81 /**
82 * This creates an empty <code>Document</code> object based
83 * on the current JAXP parser implementation.
84 *
85 * @return <code>Document</code> - created DOM Document.
86 * @throws JDOMException when errors occur in parsing.
87 */
88 @Override
89 public Document createDocument()
90 throws JDOMException {
91
92 DocumentBuilder db = localbuilder.get();
93 if (db == null) {
94 try {
95 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
96 db = dbf.newDocumentBuilder();
97 localbuilder.set(db);
98 } catch (ParserConfigurationException e) {
99 throw new JDOMException("Unable to obtain a DOM parser. See cause:", e);
100 }
101 }
102 return db.newDocument();
103
104 }
105
106 }
0 /*--
1
2 $Id: XML4JDOMAdapter.java,v 1.18 2007/11/10 05:28:59 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 package org.jdom.adapters;
57
58 import org.jdom.JDOMException;
59 import org.jdom.input.sax.BuilderErrorHandler;
60 import org.w3c.dom.Document;
61 import org.xml.sax.ErrorHandler;
62 import org.xml.sax.InputSource;
63 import org.xml.sax.SAXParseException;
64
65 import java.io.File;
66 import java.io.FileInputStream;
67 import java.io.IOException;
68 import java.io.InputStream;
69 import java.lang.reflect.InvocationTargetException;
70 import java.lang.reflect.Method;
71
72 /**
73 * An adapter for the IBM XML4J DOM parser.
74 *
75 * @version $Revision: 1.18 $, $Date: 2007/11/10 05:28:59 $
76 * @author Brett McLaughlin
77 * @author Jason Hunter
78 */
79 public class XML4JDOMAdapter extends AbstractDOMAdapter {
80
81 private static final String CVS_ID =
82 "@(#) $RCSfile: XML4JDOMAdapter.java,v $ $Revision: 1.18 $ $Date: 2007/11/10 05:28:59 $ $Name: $";
83
84 /**
85 * This creates a new <code>{@link Document}</code> from an
86 * existing <code>InputStream</code> by letting a DOM
87 * parser handle parsing using the supplied stream.
88 *
89 * @param filename file to parse.
90 * @param validate <code>boolean</code> to indicate if validation should occur.
91 * @return <code>Document</code> - instance ready for use.
92 * @throws IOException when I/O error occurs.
93 * @throws JDOMException when errors occur in parsing.
94 */
95 public Document getDocument(File filename, boolean validate)
96 throws IOException, JDOMException {
97
98 return getDocument(new FileInputStream(filename), validate);
99 }
100
101 /**
102 * This creates a new <code>{@link Document}</code> from an
103 * existing <code>InputStream</code> by letting a DOM
104 * parser handle parsing using the supplied stream.
105 *
106 * @param in <code>InputStream</code> to parse.
107 * @param validate <code>boolean</code> to indicate if validation should occur.
108 * @return <code>Document</code> - instance ready for use.
109 * @throws IOException when I/O error occurs.
110 * @throws JDOMException when errors occur in parsing.
111 */
112 public Document getDocument(InputStream in, boolean validate)
113 throws IOException, JDOMException {
114
115 try {
116 /*
117 * IBM XML4J actually uses the Xerces parser, so this is
118 * all Xerces specific code.
119 */
120
121 // Load the parser class
122 Class parserClass = Class.forName("org.apache.xerces.parsers.DOMParser");
123 Object parser = parserClass.newInstance();
124
125 // Set validation
126 Method setFeature =
127 parserClass.getMethod("setFeature",
128 new Class[] {java.lang.String.class,
129 boolean.class});
130 setFeature.invoke(parser, new Object[] {"http://xml.org/sax/features/validation",
131 new Boolean(validate)});
132
133 // Set namespaces
134 setFeature.invoke(parser, new Object[] {"http://xml.org/sax/features/namespaces",
135 new Boolean(false)});
136
137 // Set the error handler
138 if (validate) {
139 Method setErrorHandler =
140 parserClass.getMethod("setErrorHandler",
141 new Class[] {ErrorHandler.class});
142 setErrorHandler.invoke(parser, new Object[] {new BuilderErrorHandler()});
143 }
144
145 // Parse the document
146 Method parse =
147 parserClass.getMethod("parse",
148 new Class[] {org.xml.sax.InputSource.class});
149 parse.invoke(parser, new Object[]{new InputSource(in)});
150
151 // Get the Document object
152 Method getDocument = parserClass.getMethod("getDocument", null);
153 Document doc = (Document)getDocument.invoke(parser, null);
154
155 return doc;
156 } catch (InvocationTargetException e) {
157 Throwable targetException = e.getTargetException();
158 if (targetException instanceof org.xml.sax.SAXParseException) {
159 SAXParseException parseException = (SAXParseException)targetException;
160 throw new JDOMException("Error on line " + parseException.getLineNumber() +
161 " of XML document: " + parseException.getMessage(), parseException);
162 } else if (targetException instanceof IOException) {
163 IOException ioException = (IOException) targetException;
164 throw ioException;
165 } else {
166 throw new JDOMException(targetException.getMessage(), targetException);
167 }
168 } catch (Exception e) {
169 throw new JDOMException(e.getClass().getName() + ": " +
170 e.getMessage(), e);
171 }
172 }
173
174 /**
175 * This creates an empty <code>Document</code> object based
176 * on a specific parser implementation.
177 *
178 * @return <code>Document</code> - created DOM Document.
179 * @throws JDOMException when errors occur.
180 */
181 public Document createDocument() throws JDOMException {
182 try {
183 return
184 (Document)Class.forName(
185 "org.apache.xerces.dom.DocumentImpl")
186 .newInstance();
187
188 } catch (Exception e) {
189 throw new JDOMException(e.getClass().getName() + ": " +
190 e.getMessage() + " while creating document", e);
191 }
192 }
193 }
0 <body>
1
2 Classes to create specific DOM Document instances. The DOMOutputter is the
3 only user of this code in JDOM, and customizing these classes is not generally
4 needed except in truly advanced situations.
5
6 </body>
0 /*--
1
2 $Id: AbstractFilter.java,v 1.6 2007/11/10 05:29:00 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 package org.jdom.filter;
57
58 import org.jdom.Content;
59
60 /**
61 * Partial implementation of {@link Filter}.
62 *
63 * @author Bradley S. Huffman
64 * @version $Revision: 1.6 $, $Date: 2007/11/10 05:29:00 $
65 */
66 public abstract class AbstractFilter<T extends Content> implements Filter<T> {
67
68 private static final String CVS_ID =
69 "@(#) $RCSfile: AbstractFilter.java,v $ $Revision: 1.6 $ $Date: 2007/11/10 05:29:00 $";
70
71 public Filter negate() {
72 return new NegateFilter(this);
73 }
74
75 public Filter or(Filter filter) {
76 return new OrFilter(this, filter);
77 }
78
79 public Filter and(Filter filter) {
80 return new AndFilter(this, filter);
81 }
82
83 public static <T extends Content> org.jdom.filter2.Filter<T> toFilter2(final Filter<T> filter) {
84 return new org.jdom.filter2.AbstractFilter<T>() {
85 @Override
86 public T filter(Object content) {
87 //noinspection unchecked
88 return filter.matches(content) ? (T) content : null;
89 }
90 };
91 }
92 }
0 /*--
1
2 $Id: AndFilter.java,v 1.4 2007/11/10 05:29:00 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 package org.jdom.filter;
57
58 import org.jdom.Content;
59
60 /**
61 * Allow two filters to be chained together with a logical
62 * <b>and</b> operation.
63 *
64 * @author Bradley S. Huffman
65 * @version $Revision: 1.4 $, $Date: 2007/11/10 05:29:00 $
66 */
67 final class AndFilter<E extends Content> extends AbstractFilter<E> {
68
69 private static final String CVS_ID =
70 "@(#) $RCSfile: AndFilter.java,v $ $Revision: 1.4 $ $Date: 2007/11/10 05:29:00 $";
71
72 // Filter for left side of logical <b>and</b>.
73 private Filter left;
74
75 // Filter for right side of logical <b>and</b>.
76 private Filter right;
77
78 /**
79 * Match if only both supplied filters match.
80 *
81 * @param left left side of logical <b>and</b>
82 * @param right right side of logical <b>and</b>
83 * @throws IllegalArgumentException if either supplied filter is null
84 */
85 public AndFilter(Filter left, Filter right) {
86 if ((left == null) || (right == null)) {
87 throw new IllegalArgumentException("null filter not allowed");
88 }
89 this.left = left;
90 this.right = right;
91 }
92
93 public boolean matches(Object obj) {
94 return left.matches(obj) && right.matches(obj);
95 }
96
97 public boolean equals(Object obj) {
98 if (this == obj) {
99 return true;
100 }
101
102 if (obj instanceof AndFilter) {
103 AndFilter filter = (AndFilter) obj;
104 if ((left.equals(filter.left) && right.equals(filter.right)) ||
105 (left.equals(filter.right) && right.equals(filter.left))) {
106 return true;
107 }
108 }
109 return false;
110 }
111
112 public int hashCode() {
113 return (31 * left.hashCode()) + right.hashCode();
114 }
115
116 public String toString() {
117 return new StringBuffer(64)
118 .append("[AndFilter: ")
119 .append(left.toString())
120 .append(",\n")
121 .append(" ")
122 .append(right.toString())
123 .append("]")
124 .toString();
125 }
126 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter;
55
56 import org.jdom.Content;
57
58 /**
59 * Filter input according to the input class.
60 *
61 * @author Rolf Lear
62 *
63 * @param <T> The generic type of the filtered data.
64 */
65 final class ClassFilter<T extends Content> extends AbstractFilter<T> {
66
67 /**
68 * JDOM2 Serialization: Default mechanism
69 */
70 private static final long serialVersionUID = 200L;
71
72 private final Class<? extends T> fclass;
73
74 /**
75 * Construct the new ClassFilter.
76 * @param tclass the class instance for the generic type.
77 */
78 public ClassFilter(Class<? extends T> tclass) {
79 fclass = tclass;
80 }
81
82 @Override
83 public boolean matches(Object obj) {
84 return fclass.isInstance(obj);
85 }
86
87 @Override
88 public String toString() {
89 return "[ClassFilter: Class " + fclass.getName() + "]";
90 }
91
92 @Override
93 public boolean equals(Object obj) {
94 if (obj == this) {
95 return true;
96 }
97 if (obj instanceof ClassFilter<?>) {
98 return fclass.equals(((ClassFilter<?>)obj).fclass);
99 }
100 return false;
101 }
102
103 @Override
104 public int hashCode() {
105 return fclass.hashCode();
106 }
107
108 }
0 /*--
1
2 $Id: ContentFilter.java,v 1.15 2007/11/10 05:29:00 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 package org.jdom.filter;
57
58 import org.jdom.*;
59
60 /**
61 * A general purpose Filter able to represent all legal JDOM objects or a
62 * specific subset. Filtering is accomplished by way of a filtering mask in
63 * which each bit represents whether a JDOM object is visible or not.
64 * For example to view all Text and CDATA nodes in the content of element x.
65 * <pre><code>
66 * Filter filter = new ContentFilter(ContentFilter.TEXT |
67 * ContentFilter.CDATA);
68 * List content = x.getContent(filter);
69 * </code></pre>
70 * <p>
71 * For those who don't like bit-masking, set methods are provided as an
72 * alternative. For example to allow everything except Comment nodes.
73 * <pre><code>
74 * Filter filter = new ContentFilter();
75 * filter.setCommentVisible(false);
76 * List content = x.getContent(filter);
77 * </code></pre>
78 * <p>
79 * The default is to allow all valid JDOM objects.
80 *
81 * @version $Revision: 1.15 $, $Date: 2007/11/10 05:29:00 $
82 * @author Bradley S. Huffman
83 */
84 public class ContentFilter<E extends Content> extends AbstractFilter<E> {
85
86 private static final String CVS_ID =
87 "@(#) $RCSfile: ContentFilter.java,v $ $Revision: 1.15 $ $Date: 2007/11/10 05:29:00 $ $Name: $";
88
89 /** Mask for JDOM {@link Element} objects */
90 public static final int ELEMENT = 1;
91
92 /** Mask for JDOM {@link CDATA} objects */
93 public static final int CDATA = 2;
94
95 /** Mask for JDOM {@link Text} objects */
96 public static final int TEXT = 4;
97
98 /** Mask for JDOM {@link Comment} objects */
99 public static final int COMMENT = 8;
100
101 /** Mask for JDOM {@link ProcessingInstruction} objects */
102 public static final int PI = 16;
103
104 /** Mask for JDOM {@link EntityRef} objects */
105 public static final int ENTITYREF = 32;
106
107 /** Mask for JDOM {@link Document} object */
108 public static final int DOCUMENT = 64;
109
110 /** Mask for JDOM {@link DocType} object */
111 public static final int DOCTYPE = 128;
112
113 /** The JDOM object mask */
114 private int filterMask;
115
116 /**
117 * Default constructor that allows any legal JDOM objects.
118 */
119 public ContentFilter() {
120 setDefaultMask();
121 }
122
123 /**
124 * Set whether all JDOM objects are visible or not.
125 *
126 * @param allVisible <code>true</code> all JDOM objects are visible,
127 * <code>false</code> all JDOM objects are hidden.
128 */
129 public ContentFilter(boolean allVisible) {
130 if (allVisible) {
131 setDefaultMask();
132 }
133 else {
134 filterMask &= ~filterMask;
135 }
136 }
137
138 /**
139 * Filter out JDOM objects according to a filtering mask.
140 *
141 * @param mask Mask of JDOM objects to allow.
142 */
143 public ContentFilter(int mask) {
144 setFilterMask(mask);
145 }
146
147 /**
148 * Return current filtering mask.
149 *
150 * @return the current filtering mask
151 */
152 public int getFilterMask() {
153 return filterMask;
154 }
155
156 /**
157 * Set filtering mask.
158 *
159 * @param mask the new filtering mask
160 */
161 public void setFilterMask(int mask) {
162 setDefaultMask();
163 filterMask &= mask;
164 }
165
166 /**
167 * Set this filter to allow all legal JDOM objects.
168 */
169 public void setDefaultMask() {
170 filterMask = ELEMENT | CDATA | TEXT | COMMENT |
171 PI | ENTITYREF | DOCUMENT | DOCTYPE;
172 }
173
174 /**
175 * Set filter to match only JDOM objects that are legal
176 * document content.
177 */
178 public void setDocumentContent() {
179 filterMask = ELEMENT | COMMENT | PI | DOCTYPE;
180 }
181
182 /**
183 * Set filter to match only JDOM objects that are legal
184 * element content.
185 */
186 public void setElementContent() {
187 filterMask = ELEMENT | CDATA | TEXT |
188 COMMENT | PI | ENTITYREF;
189 }
190
191 /**
192 * Set visiblity of <code>Element</code> objects.
193 *
194 * @param visible whether Elements are visible, <code>true</code>
195 * if yes, <code>false</code> if not
196 */
197 public void setElementVisible(boolean visible) {
198 if (visible) {
199 filterMask |= ELEMENT;
200 }
201 else {
202 filterMask &= ~ELEMENT;
203 }
204 }
205
206 /**
207 * Set visiblity of <code>CDATA</code> objects.
208 *
209 * @param visible whether CDATA nodes are visible, <code>true</code>
210 * if yes, <code>false</code> if not
211 */
212 public void setCDATAVisible(boolean visible) {
213 if (visible) {
214 filterMask |= CDATA;
215 }
216 else {
217 filterMask &= ~CDATA;
218 }
219 }
220
221 /**
222 * Set visiblity of <code>Text</code> objects.
223 *
224 * @param visible whether Text nodes are visible, <code>true</code>
225 * if yes, <code>false</code> if not
226 */
227 public void setTextVisible(boolean visible) {
228 if (visible) {
229 filterMask |= TEXT;
230 }
231 else {
232 filterMask &= ~TEXT;
233 }
234 }
235
236 /**
237 * Set visiblity of <code>Comment</code> objects.
238 *
239 * @param visible whether Comments are visible, <code>true</code>
240 * if yes, <code>false</code> if not
241 */
242 public void setCommentVisible(boolean visible) {
243 if (visible) {
244 filterMask |= COMMENT;
245 }
246 else {
247 filterMask &= ~COMMENT;
248 }
249 }
250
251 /**
252 * Set visiblity of <code>ProcessingInstruction</code> objects.
253 *
254 * @param visible whether ProcessingInstructions are visible,
255 * <code>true</code> if yes, <code>false</code> if not
256 */
257 public void setPIVisible(boolean visible) {
258 if (visible) {
259 filterMask |= PI;
260 }
261 else {
262 filterMask &= ~PI;
263 }
264 }
265
266 /**
267 * Set visiblity of <code>EntityRef</code> objects.
268 *
269 * @param visible whether EntityRefs are visible, <code>true</code>
270 * if yes, <code>false</code> if not
271 */
272 public void setEntityRefVisible(boolean visible) {
273 if (visible) {
274 filterMask |= ENTITYREF;
275 }
276 else {
277 filterMask &= ~ENTITYREF;
278 }
279 }
280
281 /**
282 * Set visiblity of <code>DocType</code> objects.
283 *
284 * @param visible whether the DocType is visible, <code>true</code>
285 * if yes, <code>false</code> if not
286 */
287 public void setDocTypeVisible(boolean visible) {
288 if (visible) {
289 filterMask |= DOCTYPE;
290 }
291 else {
292 filterMask &= ~DOCTYPE;
293 }
294 }
295
296 /**
297 * Check to see if the object matches according to the filter mask.
298 *
299 * @param obj The object to verify.
300 * @return <code>true</code> if the objected matched a predfined
301 * set of rules.
302 */
303 public boolean matches(Object obj) {
304 if (obj instanceof Element) {
305 return (filterMask & ELEMENT) != 0;
306 }
307 else if (obj instanceof CDATA) { // must come before Text check
308 return (filterMask & CDATA) != 0;
309 }
310 else if (obj instanceof Text) {
311 return (filterMask & TEXT) != 0;
312 }
313 else if (obj instanceof Comment) {
314 return (filterMask & COMMENT) != 0;
315 }
316 else if (obj instanceof ProcessingInstruction) {
317 return (filterMask & PI) != 0;
318 }
319 else if (obj instanceof EntityRef) {
320 return (filterMask & ENTITYREF) != 0;
321 }
322 else if (obj instanceof Document) {
323 return (filterMask & DOCUMENT) != 0;
324 }
325 else if (obj instanceof DocType) {
326 return (filterMask & DOCTYPE) != 0;
327 }
328
329 return false;
330 }
331
332 /**
333 * Returns whether the two filters are equivalent (i&#46;e&#46; the
334 * matching mask values are identical).
335 *
336 * @param obj the object to compare against
337 * @return whether the two filters are equal
338 */
339 public boolean equals(Object obj) {
340 // Generated by IntelliJ
341 if (this == obj) return true;
342 if (!(obj instanceof ContentFilter)) return false;
343
344 final ContentFilter filter = (ContentFilter) obj;
345
346 if (filterMask != filter.filterMask) return false;
347
348 return true;
349 }
350
351 public int hashCode() {
352 // Generated by IntelliJ
353 return filterMask;
354 }
355 }
0 /*--
1
2 $Id: ElementFilter.java,v 1.20 2007/11/10 05:29:00 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 package org.jdom.filter;
57
58 import java.io.*;
59 import org.jdom.*;
60
61 /**
62 * A Filter that only matches {@link org.jdom.Element} objects.
63 *
64 * @version $Revision: 1.20 $, $Date: 2007/11/10 05:29:00 $
65 * @author Jools Enticknap
66 * @author Bradley S. Huffman
67 */
68 public class ElementFilter extends AbstractFilter<Element> {
69
70 private static final String CVS_ID =
71 "@(#) $RCSfile: ElementFilter.java,v $ $Revision: 1.20 $ $Date: 2007/11/10 05:29:00 $ $Name: $";
72
73 /** The element name */
74 private String name;
75
76 /** The element namespace */
77 private transient Namespace namespace;
78
79 /**
80 * Select only the Elements.
81 */
82 public ElementFilter() {}
83
84 /**
85 * Select only the Elements with the supplied name in any Namespace.
86 *
87 * @param name The name of the Element.
88 */
89 public ElementFilter(String name) {
90 this.name = name;
91 }
92
93 /**
94 * Select only the Elements with the supplied Namespace.
95 *
96 * @param namespace The namespace the Element lives in.
97 */
98 public ElementFilter(Namespace namespace) {
99 this.namespace = namespace;
100 }
101
102 /**
103 * Select only the Elements with the supplied name and Namespace.
104 *
105 * @param name The name of the Element.
106 * @param namespace The namespace the Element lives in.
107 */
108 public ElementFilter(String name, Namespace namespace) {
109 this.name = name;
110 this.namespace = namespace;
111 }
112
113 /**
114 * Check to see if the object matches a predefined set of rules.
115 *
116 * @param obj The object to verify.
117 * @return <code>true</code> if the objected matched a predfined
118 * set of rules.
119 */
120 public boolean matches(Object obj) {
121 if (obj instanceof Element) {
122 Element el = (Element) obj;
123 return
124 (this.name == null || this.name.equals(el.getName())) &&
125 (this.namespace == null || this.namespace.equals(el.getNamespace()));
126 }
127 return false;
128 }
129
130 /**
131 * Returns whether the two filters are equivalent (i&#46;e&#46; the
132 * matching names and namespace are equivalent).
133 *
134 * @param obj the object to compare against
135 * @return whether the two filters are equal
136 */
137 public boolean equals(Object obj) {
138 // Generated by IntelliJ
139 if (this == obj) return true;
140 if (!(obj instanceof ElementFilter)) return false;
141
142 final ElementFilter filter = (ElementFilter) obj;
143
144 if (name != null ? !name.equals(filter.name) : filter.name != null) return false;
145 if (namespace != null ? !namespace.equals(filter.namespace) : filter.namespace != null) return false;
146
147 return true;
148 }
149
150 public int hashCode() {
151 // Generated by IntelliJ
152 int result;
153 result = (name != null ? name.hashCode() : 0);
154 result = 29 * result + (namespace != null ? namespace.hashCode() : 0);
155 return result;
156 }
157
158 // Support a custom Namespace serialization so no two namespace
159 // object instances may exist for the same prefix/uri pair
160 private void writeObject(ObjectOutputStream out) throws IOException {
161
162 out.defaultWriteObject();
163
164 // We use writeObject() and not writeUTF() to minimize space
165 // This allows for writing pointers to already written strings
166 if (namespace != null) {
167 out.writeObject(namespace.getPrefix());
168 out.writeObject(namespace.getURI());
169 }
170 else {
171 out.writeObject(null);
172 out.writeObject(null);
173 }
174 }
175
176 private void readObject(ObjectInputStream in)
177 throws IOException, ClassNotFoundException {
178
179 in.defaultReadObject();
180
181 Object prefix = in.readObject();
182 Object uri = in.readObject();
183
184 if (prefix != null) { // else leave namespace null here
185 namespace = Namespace.getNamespace((String) prefix, (String) uri);
186 }
187 }
188 }
0 /*--
1
2 $Id: Filter.java,v 1.10 2007/11/10 05:29:00 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 package org.jdom.filter;
57
58
59 import org.jdom.Content;
60
61 /**
62 * A generalized filter to restrict visibility or mutability on a list.
63 *
64 * @version $Revision: 1.10 $, $Date: 2007/11/10 05:29:00 $
65 * @author Jools Enticknap
66 * @author Bradley S. Huffman
67 */
68 public interface Filter<E extends Content> extends java.io.Serializable {
69 /**
70 * Check to see if the object matches a predefined set of rules.
71 *
72 * @param obj The object to verify.
73 * @return <code>true</code> if the object matches a predfined
74 * set of rules.
75 */
76 public boolean matches(Object obj);
77 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter;
55
56 import org.jdom.*;
57
58 /**
59 * Factory class of convenience methods to create Filter instances of common
60 * types. Methods that return Filters that act on core JDOM classes (Element,
61 * Text, etc.) are simply named after the content they return.
62 * <p>
63 * Filters that
64 * match non-core classes (Boolean, Object, etc.) are all prefixed with the
65 * letter 'f' (for <strong>f</strong>ilter).
66 * <p>
67 * The Filter returned by {@link #fpassthrough()} is not really a filter in the
68 * sense that it will never filter anything out - everything matches. This can
69 * be useful to accomplish some tasks, for example the JDOM XPath API uses it
70 * extensively.
71 *
72 * @author Rolf Lear
73 *
74 */
75 public final class Filters {
76
77 private static final Filter<Content> fcontent =
78 new ClassFilter<Content>(Content.class);
79
80 private static final Filter<Comment> fcomment =
81 new ClassFilter<Comment>(Comment.class);
82
83 private static final Filter<CDATA> fcdata =
84 new ClassFilter<CDATA>(CDATA.class);
85
86 private static final Filter<DocType> fdoctype =
87 new ClassFilter<DocType>(DocType.class);
88
89 private static final Filter<EntityRef> fentityref =
90 new ClassFilter<EntityRef>(EntityRef.class);
91
92 private static final Filter<ProcessingInstruction> fpi =
93 new ClassFilter<ProcessingInstruction>(ProcessingInstruction.class);
94
95 private static final Filter<Text> ftext =
96 new ClassFilter<Text>(Text.class);
97
98 private static final Filter<Text> ftextonly = new TextOnlyFilter();
99
100 private static final Filter<Element> felement =
101 new ClassFilter<Element>(Element.class);
102
103
104 private Filters() {
105 // do nothing... make instances impossible.
106 }
107
108 /**
109 * Return a Filter that matches any {@link Content} data.
110 *
111 * @return a Filter that matches any {@link Content} data.
112 */
113 public static final Filter<Content> content() {
114 return fcontent;
115 }
116
117 /**
118 * Return a Filter that matches any {@link Comment} data.
119 *
120 * @return a Filter that matches any {@link Comment} data.
121 */
122 public static final Filter<Comment> comment() {
123 return fcomment;
124 }
125
126 /**
127 * Return a Filter that matches any {@link CDATA} data.
128 *
129 * @return a Filter that matches any {@link CDATA} data.
130 */
131 public static final Filter<CDATA> cdata() {
132 return fcdata;
133 }
134
135 /**
136 * Return a Filter that matches any {@link DocType} data.
137 *
138 * @return a Filter that matches any {@link DocType} data.
139 */
140 public static final Filter<DocType> doctype() {
141 return fdoctype;
142 }
143
144 /**
145 * Return a Filter that matches any {@link EntityRef} data.
146 *
147 * @return a Filter that matches any {@link EntityRef} data.
148 */
149 public static final Filter<EntityRef> entityref() {
150 return fentityref;
151 }
152
153 /**
154 * Return a Filter that matches any {@link Element} data.
155 *
156 * @return a Filter that matches any {@link Element} data.
157 */
158 public static final Filter<Element> element() {
159 return felement;
160 }
161
162 /**
163 * Return a Filter that matches any {@link Element} data with the specified
164 * name.
165 *
166 * @param name The name of Elements to match.
167 * @return a Filter that matches any {@link Element} data with the specified
168 * name.
169 */
170 public static final Filter<Element> element(String name) {
171 return new ElementFilter(name, Namespace.NO_NAMESPACE);
172 }
173
174 /**
175 * Return a Filter that matches any {@link Element} data with the specified
176 * name and Namespace.
177 *
178 * @param name The name of Elements to match.
179 * @param ns The Namespace to match
180 * @return a Filter that matches any {@link Element} data with the specified
181 * name and Namespace.
182 */
183 public static final Filter<Element> element(String name, Namespace ns) {
184 return new ElementFilter(name, ns);
185 }
186
187 /**
188 * Return a Filter that matches any {@link Element} data with the specified
189 * Namespace.
190 *
191 * @param ns The Namespace to match
192 * @return a Filter that matches any {@link Element} data with the specified
193 * Namespace.
194 */
195 public static final Filter<Element> element(Namespace ns) {
196 return new ElementFilter(null, ns);
197 }
198
199 /**
200 * Return a Filter that matches any {@link ProcessingInstruction} data.
201 *
202 * @return a Filter that matches any {@link ProcessingInstruction} data.
203 */
204 public static final Filter<ProcessingInstruction> processinginstruction() {
205 return fpi;
206 }
207
208 /**
209 * Return a Filter that matches any {@link Text} data (which includes
210 * {@link CDATA} since that is a subclass of Text).
211 *
212 * @return a Filter that matches any {@link Text} data (which includes
213 * {@link CDATA} since that is a subclass of Text).
214 */
215 public static final Filter<Text> text() {
216 return ftext;
217 }
218
219 /**
220 * Return a Filter that matches any {@link Text} data (excludes
221 * {@link CDATA} instances).
222 *
223 * @return a Filter that matches any {@link Text} data (which excludes
224 * {@link CDATA} instances).
225 */
226 public static final Filter<Text> textOnly() {
227 return ftextonly;
228 }
229 }
0 /*--
1
2 $Id: NegateFilter.java,v 1.4 2007/11/10 05:29:00 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 package org.jdom.filter;
57
58 import org.jdom.Content;
59
60 /**
61 * Filter that is the logical <b>negation</b> operation of another filter.
62 *
63 *
64 * @author Bradley S. Huffman
65 * @version $Revision: 1.4 $, $Date: 2007/11/10 05:29:00 $
66 */
67 final class NegateFilter<E extends Content> extends AbstractFilter<E> {
68
69 private static final String CVS_ID =
70 "@(#) $RCSfile: NegateFilter.java,v $ $Revision: 1.4 $ $Date: 2007/11/10 05:29:00 $";
71
72 // Underlying filter.
73 private Filter filter;
74
75 /**
76 * Match if the supplied filter <b>does not</b> match.
77 *
78 * @param filter filter to use.
79 */
80 public NegateFilter(Filter filter) {
81 this.filter = filter;
82 }
83
84 public boolean matches(Object obj) {
85 return !filter.matches(obj);
86 }
87
88 public Filter negate() {
89 return filter;
90 }
91
92 public boolean equals(Object obj) {
93 if (this == obj) {
94 return true;
95 }
96
97 if (obj instanceof NegateFilter) {
98 return filter.equals(((NegateFilter) obj).filter);
99 }
100 return false;
101 }
102
103 public int hashCode() {
104 return ~filter.hashCode();
105 }
106
107 public String toString() {
108 return new StringBuffer(64)
109 .append("[NegateFilter: ")
110 .append(filter.toString())
111 .append("]")
112 .toString();
113 }
114 }
0 /*--
1
2 $Id: OrFilter.java,v 1.5 2007/11/10 05:29:00 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 package org.jdom.filter;
57
58 import org.jdom.Content;
59
60 /**
61 * Allow two filters to be chained together with a logical
62 * <b>or</b> operation.
63 *
64 * @author Bradley S. Huffman
65 * @version $Revision: 1.5 $, $Date: 2007/11/10 05:29:00 $
66 */
67 final class OrFilter<E extends Content> extends AbstractFilter<E> {
68
69 private static final String CVS_ID =
70 "@(#) $RCSfile: OrFilter.java,v $ $Revision: 1.5 $ $Date: 2007/11/10 05:29:00 $";
71
72 /** Filter for left side of logical <b>or</b> */
73 private Filter left;
74
75 /** Filter for right side of logical <b>or</b> */
76 private Filter right;
77
78 /**
79 * Match if either of the supplied filters.
80 *
81 * @param left left side of logical <b>or</b>
82 * @param right right side of logical <b>or</b>
83 * @throws IllegalArgumentException if either supplied filter is null
84 */
85 public OrFilter(Filter left, Filter right) {
86 if ((left == null) || (right == null)) {
87 throw new IllegalArgumentException("null filter not allowed");
88 }
89 this.left = left;
90 this.right = right;
91 }
92
93 public boolean matches(Object obj) {
94 return left.matches(obj) || right.matches(obj);
95 }
96
97 public boolean equals(Object obj) {
98 if (this == obj) {
99 return true;
100 }
101
102 if (obj instanceof OrFilter) {
103 OrFilter filter = (OrFilter) obj;
104 if ((left.equals(filter.left) && right.equals(filter.right)) ||
105 (left.equals(filter.right) && right.equals(filter.left))) {
106 return true;
107 }
108 }
109 return false;
110 }
111
112 public int hashCode() {
113 return (31 * left.hashCode()) + right.hashCode();
114 }
115
116 public String toString() {
117 return new StringBuffer(64)
118 .append("[OrFilter: ")
119 .append(left.toString())
120 .append(",\n")
121 .append(" ")
122 .append(right.toString())
123 .append("]")
124 .toString();
125 }
126 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter;
55
56 import org.jdom.Text;
57 import org.jdom.Content.CType;
58
59 /**
60 * A filter that matches Text, but not CDATA content.
61 * This filter is made accessible through {@link Filters#textOnly()}
62 *
63 * @author Rolf Lear
64 *
65 */
66 final class TextOnlyFilter extends AbstractFilter<Text> {
67
68 /**
69 * JDOM2 Serialization: Default mechanism
70 */
71 private static final long serialVersionUID = 200L;
72
73 @Override
74 public boolean matches(Object content) {
75 if (content instanceof Text) {
76 final Text txt = (Text)content;
77 if (txt.getCType() == CType.Text) {
78 return true;
79 }
80 }
81 return false;
82 }
83
84 @Override
85 public int hashCode() {
86 return this.getClass().hashCode();
87 }
88
89 @Override
90 public boolean equals(Object obj) {
91 return obj instanceof TextOnlyFilter;
92 }
93
94 }
0 <body>
1
2 Classes to programmatically filter nodes of a document based on type, name,
3 value, or other aspects and to boolean and/or/negate these rules. Filters can
4 be used in methods like getContent(Filter) and getDescendants(Filter). A
5 sampling of generally useful filters are provided here. Alternate filters can
6 be user defined.
7
8 </body>
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.RandomAccess;
61
62 import org.jdom.Content;
63
64 /**
65 * Partial implementation of {@link Filter}.
66 *
67 * @author Bradley S. Huffman
68 * @author Rolf Lear
69 * @param <T> The Generic type of content returned by this Filter
70 */
71 public abstract class AbstractFilter<T> implements Filter<T> {
72
73 /**
74 * JDOM2 Serialization: Default mechanism
75 */
76 private static final long serialVersionUID = 200L;
77
78 @Override
79 public final boolean matches(Object content) {
80 return filter(content) != null;
81 }
82
83 @Override
84 public List<T> filter(List<?> content) {
85 if (content == null) {
86 return Collections.emptyList();
87 }
88 if (content instanceof RandomAccess) {
89 final int sz = content.size();
90 final ArrayList<T> ret = new ArrayList<T>(sz);
91 for (int i = 0; i < sz; i++) {
92 final T c = filter(content.get(i));
93 if (c != null) {
94 ret.add(c);
95 }
96 }
97 if (ret.isEmpty()) {
98 return Collections.emptyList();
99 }
100 return Collections.unmodifiableList(ret);
101 }
102 final ArrayList<T> ret = new ArrayList<T>(10);
103 for (Iterator<?> it = content.iterator(); it.hasNext(); ) {
104 final T c = filter(it.next());
105 if (c != null) {
106 ret.add(c);
107 }
108 }
109 if (ret.isEmpty()) {
110 return Collections.emptyList();
111 }
112 return Collections.unmodifiableList(ret);
113 }
114
115 @Override
116 public final Filter<?> negate() {
117 if (this instanceof NegateFilter) {
118 return ((NegateFilter)this).getBaseFilter();
119 }
120 return new NegateFilter(this);
121 }
122
123 @Override
124 public final Filter<? extends Content> or(Filter<?> filter) {
125 return new OrFilter(this, filter);
126 }
127
128 @Override
129 public final Filter<T> and(Filter<?> filter) {
130 return new AndFilter<T>(filter, this);
131 }
132
133 @Override
134 public <R> Filter<R> refine(Filter<R> filter) {
135 return new AndFilter<R>(this, filter);
136 }
137
138 public static <E extends Content> org.jdom.filter.Filter<E> toFilter(final Filter<E> filter) {
139 return new org.jdom.filter.Filter<E>() {
140 @Override
141 public boolean matches(Object obj) {
142 return filter.matches(obj);
143 }
144 };
145 }
146 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56
57 /**
58 * Allow two filters to be chained together with a logical
59 * <b>and</b> operation.
60 *
61 * @author Bradley S. Huffman
62 * @author Rolf Lear
63 * @param <T> The Generic type of content returned by this Filter
64 */
65 final class AndFilter<T> extends AbstractFilter<T> {
66
67 /**
68 * JDOM2 Serialization: Default mechanism
69 */
70 private static final long serialVersionUID = 200L;
71
72 private final Filter<?> base;
73 private final Filter<T> refiner;
74
75 public AndFilter(Filter<?> base, Filter<T> refiner) {
76 if (base == null || refiner == null) {
77 throw new NullPointerException("Cannot have a null base or refiner filter");
78 }
79 this.base = base;
80 this.refiner = refiner;
81 }
82
83 @Override
84 public T filter(Object content) {
85 Object o = base.filter(content);
86 if (o != null) {
87 return refiner.filter(content);
88 }
89 return null;
90 }
91
92 @Override
93 public int hashCode() {
94 return base.hashCode() ^ refiner.hashCode();
95 }
96
97 @Override
98 public boolean equals(Object obj) {
99 if (obj == this) {
100 return true;
101 }
102 if (obj instanceof AndFilter<?>) {
103 AndFilter<?> them = (AndFilter<?>)obj;
104 return (base.equals(them.base) && refiner.equals(them.refiner)) ||
105 (refiner.equals(them.base) && base.equals(them.refiner));
106 }
107
108 return false;
109 }
110
111 @Override
112 public String toString() {
113 return new StringBuilder(64)
114 .append("[AndFilter: ")
115 .append(base.toString())
116 .append(",\n")
117 .append(" ")
118 .append(refiner.toString())
119 .append("]")
120 .toString();
121 }
122 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 import org.jdom.Attribute;
57 import org.jdom.Namespace;
58
59 /**
60 * A Filter that only matches {@link org.jdom.Attribute} objects.
61 *
62 * @author Rolf Lear
63 */
64 public class AttributeFilter extends AbstractFilter<Attribute> {
65
66 /**
67 * JDOM2 Serialization: Default mechanism
68 */
69 private static final long serialVersionUID = 200L;
70
71 /** The element name */
72 private final String name;
73
74 /** The element namespace */
75 private final Namespace namespace;
76
77 /**
78 * Select only the Elements.
79 */
80 public AttributeFilter() {
81 this(null,null);
82 }
83
84 /**
85 * Select only the Elements with the supplied name in any Namespace.
86 *
87 * @param name The name of the Element.
88 */
89 public AttributeFilter(String name) {
90 this(name, null);
91 }
92
93 /**
94 * Select only the Attributes with the supplied Namespace.
95 *
96 * @param namespace The namespace the Attribute lives in.
97 */
98 public AttributeFilter(Namespace namespace) {
99 this(null, namespace);
100 }
101
102 /**
103 * Select only the Attributes with the supplied name and Namespace.
104 *
105 * @param name The name of the Attribute.
106 * @param namespace The namespace the Attribute lives in.
107 */
108 public AttributeFilter(String name, Namespace namespace) {
109 this.name = name;
110 this.namespace = namespace;
111 }
112
113 /**
114 * Check to see if the Content matches a predefined set of rules.
115 *
116 * @param content The Content to verify.
117 * @return <code>true</code> if the objected matched a predfined
118 * set of rules.
119 */
120 @Override
121 public Attribute filter(Object content) {
122 if (content instanceof Attribute) {
123 Attribute att = (Attribute) content;
124 if (name == null) {
125 if (namespace == null) {
126 return att;
127 }
128 return namespace.equals(att.getNamespace()) ? att : null;
129 }
130 if (!name.equals(att.getName())) {
131 return null;
132 }
133 if (namespace == null) {
134 return att;
135 }
136 return namespace.equals(att.getNamespace()) ? att : null;
137 }
138 return null;
139 }
140
141 /**
142 * Returns whether the two filters are equivalent (i&#46;e&#46; the
143 * matching names and namespace are equivalent).
144 *
145 * @param obj the object to compare against
146 * @return whether the two filters are equal
147 */
148 @Override
149 public boolean equals(Object obj) {
150 // Generated by IntelliJ
151 if (this == obj) return true;
152 if (!(obj instanceof AttributeFilter)) return false;
153
154 final AttributeFilter filter = (AttributeFilter) obj;
155
156 if (name != null ? !name.equals(filter.name) : filter.name != null) return false;
157 if (namespace != null ? !namespace.equals(filter.namespace) : filter.namespace != null) return false;
158
159 return true;
160 }
161
162 @Override
163 public int hashCode() {
164 int result;
165 result = (name != null ? name.hashCode() : 0);
166 result = 29 * result + (namespace != null ? namespace.hashCode() : 0);
167 return result;
168 }
169
170 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 /**
57 * Filter input according to the input class.
58 *
59 * @author Rolf Lear
60 *
61 * @param <T> The generic type of the filtered data.
62 */
63 final class ClassFilter<T> extends AbstractFilter<T> {
64
65 /**
66 * JDOM2 Serialization: Default mechanism
67 */
68 private static final long serialVersionUID = 200L;
69
70 private final Class<? extends T> fclass;
71
72 /**
73 * Construct the new ClassFilter.
74 * @param tclass the class instance for the generic type.
75 */
76 public ClassFilter(Class<? extends T> tclass) {
77 fclass = tclass;
78 }
79
80 @Override
81 public T filter(Object content) {
82 return fclass.isInstance(content) ? fclass.cast(content) : null;
83 }
84
85 @Override
86 public String toString() {
87 return "[ClassFilter: Class " + fclass.getName() + "]";
88 }
89
90 @Override
91 public boolean equals(Object obj) {
92 if (obj == this) {
93 return true;
94 }
95 if (obj instanceof ClassFilter<?>) {
96 return fclass.equals(((ClassFilter<?>)obj).fclass);
97 }
98 return false;
99 }
100
101 @Override
102 public int hashCode() {
103 return fclass.hashCode();
104 }
105
106 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 import org.jdom.*;
57
58 /**
59 * A general purpose Filter able to represent all legal JDOM objects or a
60 * specific subset. Filtering is accomplished by way of a filtering mask in
61 * which each bit represents whether a JDOM object is visible or not.
62 * For example to view all Text and CDATA nodes in the content of element x.
63 * <pre><code>
64 * Filter filter = new ContentFilter(ContentFilter.TEXT |
65 * ContentFilter.CDATA);
66 * List content = x.getContent(filter);
67 * </code></pre>
68 * <p>
69 * For those who don't like bit-masking, set methods are provided as an
70 * alternative. For example to allow everything except Comment nodes.
71 * <pre><code>
72 * Filter filter = new ContentFilter();
73 * filter.setCommentVisible(false);
74 * List content = x.getContent(filter);
75 * </code></pre>
76 * <p>
77 * The default is to allow all valid JDOM objects.
78 *
79 * @author Bradley S. Huffman
80 */
81 public class ContentFilter extends AbstractFilter<Content> {
82
83 /**
84 * JDOM2 Serialization: Default mechanism
85 */
86 private static final long serialVersionUID = 200L;
87
88 /** Mask for JDOM {@link Element} objects */
89 public static final int ELEMENT = 1;
90
91 /** Mask for JDOM {@link CDATA} objects */
92 public static final int CDATA = 2;
93
94 /** Mask for JDOM {@link Text} objects */
95 public static final int TEXT = 4;
96
97 /** Mask for JDOM {@link Comment} objects */
98 public static final int COMMENT = 8;
99
100 /** Mask for JDOM {@link ProcessingInstruction} objects */
101 public static final int PI = 16;
102
103 /** Mask for JDOM {@link EntityRef} objects */
104 public static final int ENTITYREF = 32;
105
106 /** Mask for JDOM {@link Document} object */
107 public static final int DOCUMENT = 64;
108
109 /** Mask for JDOM {@link DocType} object */
110 public static final int DOCTYPE = 128;
111
112 /** The JDOM object mask */
113 private int filterMask;
114
115 /**
116 * Default constructor that allows any legal JDOM objects.
117 */
118 public ContentFilter() {
119 setDefaultMask();
120 }
121
122 /**
123 * Set whether all JDOM objects are visible or not.
124 *
125 * @param allVisible <code>true</code> all JDOM objects are visible,
126 * <code>false</code> all JDOM objects are hidden.
127 */
128 public ContentFilter(boolean allVisible) {
129 if (allVisible) {
130 setDefaultMask();
131 }
132 else {
133 filterMask &= ~filterMask;
134 }
135 }
136
137 /**
138 * Filter out JDOM objects according to a filtering mask.
139 *
140 * @param mask Mask of JDOM objects to allow.
141 */
142 public ContentFilter(int mask) {
143 setFilterMask(mask);
144 }
145
146 /**
147 * Return current filtering mask.
148 *
149 * @return the current filtering mask
150 */
151 public int getFilterMask() {
152 return filterMask;
153 }
154
155 /**
156 * Set filtering mask.
157 *
158 * @param mask the new filtering mask
159 */
160 public void setFilterMask(int mask) {
161 setDefaultMask();
162 filterMask &= mask;
163 }
164
165 /**
166 * Set this filter to allow all legal JDOM objects.
167 */
168 public void setDefaultMask() {
169 filterMask = ELEMENT | CDATA | TEXT | COMMENT |
170 PI | ENTITYREF | DOCUMENT | DOCTYPE;
171 }
172
173 /**
174 * Set filter to match only JDOM objects that are legal
175 * document content.
176 */
177 public void setDocumentContent() {
178 filterMask = ELEMENT | COMMENT | PI | DOCTYPE;
179 }
180
181 /**
182 * Set filter to match only JDOM objects that are legal
183 * element content.
184 */
185 public void setElementContent() {
186 filterMask = ELEMENT | CDATA | TEXT |
187 COMMENT | PI | ENTITYREF;
188 }
189
190 /**
191 * Set visiblity of <code>Element</code> objects.
192 *
193 * @param visible whether Elements are visible, <code>true</code>
194 * if yes, <code>false</code> if not
195 */
196 public void setElementVisible(boolean visible) {
197 if (visible) {
198 filterMask |= ELEMENT;
199 }
200 else {
201 filterMask &= ~ELEMENT;
202 }
203 }
204
205 /**
206 * Set visiblity of <code>CDATA</code> objects.
207 *
208 * @param visible whether CDATA nodes are visible, <code>true</code>
209 * if yes, <code>false</code> if not
210 */
211 public void setCDATAVisible(boolean visible) {
212 if (visible) {
213 filterMask |= CDATA;
214 }
215 else {
216 filterMask &= ~CDATA;
217 }
218 }
219
220 /**
221 * Set visiblity of <code>Text</code> objects.
222 *
223 * @param visible whether Text nodes are visible, <code>true</code>
224 * if yes, <code>false</code> if not
225 */
226 public void setTextVisible(boolean visible) {
227 if (visible) {
228 filterMask |= TEXT;
229 }
230 else {
231 filterMask &= ~TEXT;
232 }
233 }
234
235 /**
236 * Set visiblity of <code>Comment</code> objects.
237 *
238 * @param visible whether Comments are visible, <code>true</code>
239 * if yes, <code>false</code> if not
240 */
241 public void setCommentVisible(boolean visible) {
242 if (visible) {
243 filterMask |= COMMENT;
244 }
245 else {
246 filterMask &= ~COMMENT;
247 }
248 }
249
250 /**
251 * Set visiblity of <code>ProcessingInstruction</code> objects.
252 *
253 * @param visible whether ProcessingInstructions are visible,
254 * <code>true</code> if yes, <code>false</code> if not
255 */
256 public void setPIVisible(boolean visible) {
257 if (visible) {
258 filterMask |= PI;
259 }
260 else {
261 filterMask &= ~PI;
262 }
263 }
264
265 /**
266 * Set visiblity of <code>EntityRef</code> objects.
267 *
268 * @param visible whether EntityRefs are visible, <code>true</code>
269 * if yes, <code>false</code> if not
270 */
271 public void setEntityRefVisible(boolean visible) {
272 if (visible) {
273 filterMask |= ENTITYREF;
274 }
275 else {
276 filterMask &= ~ENTITYREF;
277 }
278 }
279
280 /**
281 * Set visiblity of <code>DocType</code> objects.
282 *
283 * @param visible whether the DocType is visible, <code>true</code>
284 * if yes, <code>false</code> if not
285 */
286 public void setDocTypeVisible(boolean visible) {
287 if (visible) {
288 filterMask |= DOCTYPE;
289 }
290 else {
291 filterMask &= ~DOCTYPE;
292 }
293 }
294
295 /**
296 * Check to see if the object matches according to the filter mask.
297 *
298 * @param obj The object to verify.
299 * @return <code>true</code> if the objected matched a predfined
300 * set of rules.
301 */
302 @Override
303 public Content filter(Object obj) {
304 if (obj == null || !Content.class.isInstance(obj)) {
305 return null;
306 }
307
308 Content content = (Content)obj;
309
310 if (content instanceof Element) {
311 return (filterMask & ELEMENT) != 0 ? content : null;
312 }
313 else if (content instanceof CDATA) { // must come before Text check
314 return (filterMask & CDATA) != 0 ? content : null;
315 }
316 else if (content instanceof Text) {
317 return (filterMask & TEXT) != 0 ? content : null;
318 }
319 else if (content instanceof Comment) {
320 return (filterMask & COMMENT) != 0 ? content : null;
321 }
322 else if (content instanceof ProcessingInstruction) {
323 return (filterMask & PI) != 0 ? content : null;
324 }
325 else if (content instanceof EntityRef) {
326 return (filterMask & ENTITYREF) != 0 ? content : null;
327 }
328 // else if (obj instanceof Document) {
329 // return (filterMask & DOCUMENT) != 0 ? obj : null;
330 // }
331 else if (content instanceof DocType) {
332 return (filterMask & DOCTYPE) != 0 ? content : null;
333 }
334
335 return null;
336 }
337
338 /**
339 * Returns whether the two filters are equivalent (i&#46;e&#46; the
340 * matching mask values are identical).
341 *
342 * @param obj the object to compare against
343 * @return whether the two filters are equal
344 */
345 @Override
346 public boolean equals(Object obj) {
347 // Generated by IntelliJ
348 if (this == obj) return true;
349 if (!(obj instanceof ContentFilter)) return false;
350
351 final ContentFilter filter = (ContentFilter) obj;
352
353 if (filterMask != filter.filterMask) return false;
354
355 return true;
356 }
357
358 @Override
359 public int hashCode() {
360 // Generated by IntelliJ
361 return filterMask;
362 }
363 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 import org.jdom.Element;
57 import org.jdom.Namespace;
58
59 /**
60 * A Filter that only matches {@link org.jdom.Element} objects.
61 *
62 * @author Jools Enticknap
63 * @author Bradley S. Huffman
64 */
65 public class ElementFilter extends AbstractFilter<Element> {
66
67 /**
68 * JDOM2 Serialization: Default mechanism
69 */
70 private static final long serialVersionUID = 200L;
71
72 /** The element name */
73 private String name;
74
75 /** The element namespace */
76 private Namespace namespace;
77
78 /**
79 * Select only the Elements.
80 */
81 public ElementFilter() {}
82
83 /**
84 * Select only the Elements with the supplied name in any Namespace.
85 *
86 * @param name The name of the Element.
87 */
88 public ElementFilter(String name) {
89 this.name = name;
90 }
91
92 /**
93 * Select only the Elements with the supplied Namespace.
94 *
95 * @param namespace The namespace the Element lives in.
96 */
97 public ElementFilter(Namespace namespace) {
98 this.namespace = namespace;
99 }
100
101 /**
102 * Select only the Elements with the supplied name and Namespace.
103 *
104 * @param name The name of the Element.
105 * @param namespace The namespace the Element lives in.
106 */
107 public ElementFilter(String name, Namespace namespace) {
108 this.name = name;
109 this.namespace = namespace;
110 }
111
112 /**
113 * Check to see if the object matches a predefined set of rules.
114 *
115 * @param content The object to verify.
116 * @return <code>true</code> if the objected matched a predfined
117 * set of rules.
118 */
119 @Override
120 public Element filter(Object content) {
121 if (content instanceof Element) {
122 Element el = (Element) content;
123 if (name == null) {
124 if (namespace == null) {
125 return el;
126 }
127 return namespace.equals(el.getNamespace()) ? el : null;
128 }
129 if (!name.equals(el.getName())) {
130 return null;
131 }
132 if (namespace == null) {
133 return el;
134 }
135 return namespace.equals(el.getNamespace()) ? el : null;
136 }
137 return null;
138 }
139
140 /**
141 * Returns whether the two filters are equivalent (i&#46;e&#46; the
142 * matching names and namespace are equivalent).
143 *
144 * @param obj the object to compare against
145 * @return whether the two filters are equal
146 */
147 @Override
148 public boolean equals(Object obj) {
149 // Generated by IntelliJ
150 if (this == obj) return true;
151 if (!(obj instanceof ElementFilter)) return false;
152
153 final ElementFilter filter = (ElementFilter) obj;
154
155 if (name != null ? !name.equals(filter.name) : filter.name != null) return false;
156 if (namespace != null ? !namespace.equals(filter.namespace) : filter.namespace != null) return false;
157
158 return true;
159 }
160
161 @Override
162 public int hashCode() {
163 // Generated by IntelliJ
164 int result;
165 result = (name != null ? name.hashCode() : 0);
166 result = 29 * result + (namespace != null ? namespace.hashCode() : 0);
167 return result;
168 }
169
170 @Override
171 public String toString() {
172 return "[ElementFilter: Name " + (name == null ? "*any*" : name) +
173 " with Namespace " + namespace + "]";
174 }
175
176
177 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 import java.util.List;
57
58
59 /**
60 * A generalized filter to restrict visibility or mutability on a list.
61 *
62 * @author Jools Enticknap
63 * @author Bradley S. Huffman
64 * @author Rolf Lear
65 * @param <T> The Generic type of content returned by this Filter
66 */
67 public interface Filter <T> extends java.io.Serializable {
68
69
70 /**
71 * Filter the input list keeping only the items that match the Filter.
72 *
73 * @param content The content to filter.
74 * @return a new read-only RandomAccess list of the filtered input content.
75 */
76 public List<T> filter(List<?> content);
77
78 /**
79 * Check to see if the content matches this Filter.
80 * If it does, return the content cast as this filter's return type,
81 * otherwise return null.
82 * @param content The content to test.
83 * @return The content if it matches the filter, cast as this Filter's type.
84 */
85 public T filter(Object content);
86
87 /**
88 * Check to see if the object matches a predefined set of rules.
89 *
90 * @param content The object to verify.
91 * @return <code>true</code> if the object matches a predfined
92 * set of rules.
93 */
94 public boolean matches(Object content);
95
96
97 /**
98 * Creates an 'inverse' filter
99 * @return a Filter that returns all content except what this Filter
100 * instance would.
101 */
102 public Filter<? extends Object> negate();
103
104 /**
105 * Creates an ORing filter
106 * @param filter a second Filter to OR with.
107 * @return a new Filter instance that returns the 'union' of this filter and
108 * the specified filter.
109 */
110 public Filter<? extends Object> or(Filter<?> filter);
111
112 /**
113 * Creates an ANDing filter. The generic type of the result is the same as
114 * this Filter.
115 *
116 * @param filter a second Filter to AND with.
117 * @return a new Filter instance that returns the 'intersection' of this
118 * filter and the specified filter.
119 */
120 public Filter<T> and(Filter<?> filter);
121
122 /**
123 * This is similar to the and(Filter) method except the generic type is
124 * different.
125 * @param <R> The Generic type of the returned data is taken from the input
126 * instance.
127 * @param filter The filter to refine our results with.
128 * @return A Filter that requires content to both match our instance and the
129 * refining instance, but the generic type of the retuned data is based
130 * on the refining instance, not this instance.
131 */
132 public <R> Filter<R> refine(Filter<R> filter);
133 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 import org.jdom.Attribute;
57 import org.jdom.CDATA;
58 import org.jdom.Comment;
59 import org.jdom.Content;
60 import org.jdom.DocType;
61 import org.jdom.Document;
62 import org.jdom.Element;
63 import org.jdom.EntityRef;
64 import org.jdom.Namespace;
65 import org.jdom.ProcessingInstruction;
66 import org.jdom.Text;
67
68 /**
69 * Factory class of convenience methods to create Filter instances of common
70 * types. Methods that return Filters that act on core JDOM classes (Element,
71 * Text, etc.) are simply named after the content they return.
72 * <p>
73 * Filters that
74 * match non-core classes (Boolean, Object, etc.) are all prefixed with the
75 * letter 'f' (for <strong>f</strong>ilter).
76 * <p>
77 * The Filter returned by {@link #fpassthrough()} is not really a filter in the
78 * sense that it will never filter anything out - everything matches. This can
79 * be useful to accomplish some tasks, for example the JDOM XPath API uses it
80 * extensively.
81 *
82 * @author Rolf Lear
83 *
84 */
85 public final class Filters {
86
87 private static final Filter<Content> fcontent =
88 new ClassFilter<Content>(Content.class);
89
90 private static final Filter<Attribute> fattribute =
91 new AttributeFilter();
92
93 private static final Filter<Comment> fcomment =
94 new ClassFilter<Comment>(Comment.class);
95
96 private static final Filter<CDATA> fcdata =
97 new ClassFilter<CDATA>(CDATA.class);
98
99 private static final Filter<DocType> fdoctype =
100 new ClassFilter<DocType>(DocType.class);
101
102 private static final Filter<EntityRef> fentityref =
103 new ClassFilter<EntityRef>(EntityRef.class);
104
105 private static final Filter<ProcessingInstruction> fpi =
106 new ClassFilter<ProcessingInstruction>(ProcessingInstruction.class);
107
108 private static final Filter<Text> ftext =
109 new ClassFilter<Text>(Text.class);
110
111 private static final Filter<Text> ftextonly = new TextOnlyFilter();
112
113 private static final Filter<Element> felement =
114 new ClassFilter<Element>(Element.class);
115
116 private static final Filter<Document> fdocument =
117 new ClassFilter<Document>(Document.class);
118
119 private static final Filter<Double> fdouble =
120 new ClassFilter<Double>(Double.class);
121
122 private static final Filter<Boolean> fboolean =
123 new ClassFilter<Boolean>(Boolean.class);
124
125 private static final Filter<String> fstring =
126 new ClassFilter<String>(String.class);
127
128 private static final Filter<Object> fpassthrough =
129 new PassThroughFilter();
130
131
132 private Filters() {
133 // do nothing... make instances impossible.
134 }
135
136 /**
137 * Return a Filter that matches any {@link Content} data.
138 *
139 * @return a Filter that matches any {@link Content} data.
140 */
141 public static final Filter<Content> content() {
142 return fcontent;
143 }
144
145 /**
146 * Return a Filter that matches any {@link Attribute} data.
147 *
148 * @return a Filter that matches any {@link Attribute} data.
149 */
150 public static final Filter<Attribute> attribute() {
151 return fattribute;
152 }
153
154 /**
155 * Return a Filter that matches any {@link Attribute} data with the
156 * specified name.
157 *
158 * @param name The name for all the Attributes to have (these can be in any
159 * Namespace).
160 * @return a Filter that matches any {@link Attribute} data with the
161 * specified name.
162 */
163 public static final Filter<Attribute> attribute(String name) {
164 return new AttributeFilter(name);
165 }
166
167 /**
168 * Return a Filter that matches any {@link Attribute} data with the
169 * specified name and namespace.
170 *
171 * @param name The name for all the Attributes to have.
172 * @param ns The Namespace for all the Attributes to have.
173 * @return a Filter that matches any {@link Attribute} data with the
174 * specified name and namespace.
175 */
176 public static final Filter<Attribute> attribute(String name, Namespace ns) {
177 return new AttributeFilter(name, ns);
178 }
179
180 /**
181 * Return a Filter that matches any {@link Attribute} data with the
182 * specified namespace.
183 *
184 * @param ns The Namespace for all the Attributes to have.
185 * @return a Filter that matches any {@link Attribute} data with the
186 * specified namespace.
187 */
188 public static final Filter<Attribute> attribute(Namespace ns) {
189 return new AttributeFilter(ns);
190 }
191
192 /**
193 * Return a Filter that matches any {@link Comment} data.
194 *
195 * @return a Filter that matches any {@link Comment} data.
196 */
197 public static final Filter<Comment> comment() {
198 return fcomment;
199 }
200
201 /**
202 * Return a Filter that matches any {@link CDATA} data.
203 *
204 * @return a Filter that matches any {@link CDATA} data.
205 */
206 public static final Filter<CDATA> cdata() {
207 return fcdata;
208 }
209
210 /**
211 * Return a Filter that matches any {@link DocType} data.
212 *
213 * @return a Filter that matches any {@link DocType} data.
214 */
215 public static final Filter<DocType> doctype() {
216 return fdoctype;
217 }
218
219 /**
220 * Return a Filter that matches any {@link EntityRef} data.
221 *
222 * @return a Filter that matches any {@link EntityRef} data.
223 */
224 public static final Filter<EntityRef> entityref() {
225 return fentityref;
226 }
227
228 /**
229 * Return a Filter that matches any {@link Element} data.
230 *
231 * @return a Filter that matches any {@link Element} data.
232 */
233 public static final Filter<Element> element() {
234 return felement;
235 }
236
237 /**
238 * Return a Filter that matches any {@link Document} data.
239 *
240 * @return a Filter that matches any {@link Document} data.
241 */
242 public static final Filter<Document> document() {
243 return fdocument;
244 }
245
246 /**
247 * Return a Filter that matches any {@link Element} data with the specified
248 * name.
249 *
250 * @param name The name of Elements to match.
251 * @return a Filter that matches any {@link Element} data with the specified
252 * name.
253 */
254 public static final Filter<Element> element(String name) {
255 return new ElementFilter(name, Namespace.NO_NAMESPACE);
256 }
257
258 /**
259 * Return a Filter that matches any {@link Element} data with the specified
260 * name and Namespace.
261 *
262 * @param name The name of Elements to match.
263 * @param ns The Namespace to match
264 * @return a Filter that matches any {@link Element} data with the specified
265 * name and Namespace.
266 */
267 public static final Filter<Element> element(String name, Namespace ns) {
268 return new ElementFilter(name, ns);
269 }
270
271 /**
272 * Return a Filter that matches any {@link Element} data with the specified
273 * Namespace.
274 *
275 * @param ns The Namespace to match
276 * @return a Filter that matches any {@link Element} data with the specified
277 * Namespace.
278 */
279 public static final Filter<Element> element(Namespace ns) {
280 return new ElementFilter(null, ns);
281 }
282
283 /**
284 * Return a Filter that matches any {@link ProcessingInstruction} data.
285 *
286 * @return a Filter that matches any {@link ProcessingInstruction} data.
287 */
288 public static final Filter<ProcessingInstruction> processinginstruction() {
289 return fpi;
290 }
291
292 /**
293 * Return a Filter that matches any {@link Text} data (which includes
294 * {@link CDATA} since that is a subclass of Text).
295 *
296 * @return a Filter that matches any {@link Text} data (which includes
297 * {@link CDATA} since that is a subclass of Text).
298 */
299 public static final Filter<Text> text() {
300 return ftext;
301 }
302
303 /**
304 * Return a Filter that matches any {@link Text} data (excludes
305 * {@link CDATA} instances).
306 *
307 * @return a Filter that matches any {@link Text} data (which excludes
308 * {@link CDATA} instances).
309 */
310 public static final Filter<Text> textOnly() {
311 return ftextonly;
312 }
313
314 /**
315 * Return a Filter that matches any Boolean data.
316 *
317 * @return a Filter that matches any Boolean data.
318 */
319 public static final Filter<Boolean> fboolean() {
320 return fboolean;
321 }
322
323 /**
324 * Return a Filter that matches any String data.
325 *
326 * @return a Filter that matches any String data.
327 */
328 public static final Filter<String> fstring() {
329 return fstring;
330 }
331
332 /**
333 * Return a Filter that matches any Double data.
334 *
335 * @return a Filter that matches any Double data.
336 */
337 public static final Filter<Double> fdouble() {
338 return fdouble;
339 }
340
341 /**
342 * Return a Filter that matches any data of the specified Class.
343 *
344 * @param <F> The generic type of the content returned by this Filter
345 * @param clazz the Class type to match in the filter
346 * @return a Filter that matches any data of the specified Class.
347 */
348 public static final <F> Filter<F> fclass(Class<F> clazz) {
349 return new ClassFilter<F>(clazz);
350 }
351
352 /**
353 * Return a filter that does no filtering at all - everything matches.
354 * @return A Pass-Through Filter.
355 */
356 public static final Filter<Object> fpassthrough() {
357 return fpassthrough;
358 }
359
360 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56
57 /**
58 * Filter that is the logical <b>negation</b> operation of another filter.
59 *
60 *
61 * @author Bradley S. Huffman
62 */
63 final class NegateFilter extends AbstractFilter<Object> {
64
65 /**
66 * JDOM2 Serialization: Default mechanism
67 */
68 private static final long serialVersionUID = 200L;
69
70 // Underlying filter.
71 private final Filter<?> filter;
72
73 /**
74 * Match if the supplied filter <b>does not</b> match.
75 *
76 * @param filter filter to use.
77 */
78 public NegateFilter(Filter<?> filter) {
79 this.filter = filter;
80 }
81
82 @Override
83 public Object filter(Object content) {
84 if (filter.matches(content)) {
85 return null;
86 }
87 return content;
88 }
89
90 Filter<?> getBaseFilter() {
91 return filter;
92 }
93
94 @Override
95 public boolean equals(Object obj) {
96 if (this == obj) {
97 return true;
98 }
99
100 if (obj instanceof NegateFilter) {
101 return filter.equals(((NegateFilter) obj).filter);
102 }
103 return false;
104 }
105
106 @Override
107 public int hashCode() {
108 return ~filter.hashCode();
109 }
110
111 @Override
112 public String toString() {
113 return new StringBuilder(64)
114 .append("[NegateFilter: ")
115 .append(filter.toString())
116 .append("]")
117 .toString();
118 }
119 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 import org.jdom.Content;
57
58 /**
59 * Allow two filters to be chained together with a logical
60 * <b>or</b> operation.
61 *
62 * @author Bradley S. Huffman
63 */
64 final class OrFilter extends AbstractFilter<Content> {
65
66 /**
67 * JDOM2 Serialization: Default mechanism
68 */
69 private static final long serialVersionUID = 200L;
70
71 /** Filter for left side of logical <b>or</b> */
72 private final Filter<?> left;
73
74 /** Filter for right side of logical <b>or</b> */
75 private final Filter<?> right;
76
77 /**
78 * Match if either of the supplied filters.
79 *
80 * @param left left side of logical <b>or</b>
81 * @param right right side of logical <b>or</b>
82 * @throws IllegalArgumentException if either supplied filter is null
83 */
84 public OrFilter(Filter<?> left, Filter<?> right) {
85 if ((left == null) || (right == null)) {
86 throw new IllegalArgumentException("null filter not allowed");
87 }
88 this.left = left;
89 this.right = right;
90 }
91
92 @Override
93 public Content filter(Object obj) {
94 if (left.matches(obj) || right.matches(obj)) {
95 return (Content)obj;
96 }
97 return null;
98 }
99
100 @Override
101 public boolean equals(Object obj) {
102 if (this == obj) {
103 return true;
104 }
105
106 if (obj instanceof OrFilter) {
107 OrFilter filter = (OrFilter) obj;
108 if ((left.equals(filter.left) && right.equals(filter.right)) ||
109 (left.equals(filter.right) && right.equals(filter.left))) {
110 return true;
111 }
112 }
113 return false;
114 }
115
116 @Override
117 public int hashCode() {
118 return ~(left.hashCode()) ^ right.hashCode();
119 }
120
121 @Override
122 public String toString() {
123 return new StringBuilder(64)
124 .append("[OrFilter: ")
125 .append(left.toString())
126 .append(",\n")
127 .append(" ")
128 .append(right.toString())
129 .append("]")
130 .toString();
131 }
132 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.RandomAccess;
61
62 /**
63 * A filter that does not actual filtering.
64 * This is made available through {@link Filters#fpassthrough()}.
65 *
66 * @author Rolf Lear
67 *
68 */
69 final class PassThroughFilter extends AbstractFilter<Object> {
70 /**
71 * JDOM2 Serialization: Default mechanism
72 */
73 private static final long serialVersionUID = 200L;
74
75
76 @Override
77 public Object filter(Object content) {
78 return content;
79 }
80
81 @Override
82 public List<Object> filter(List<?> content) {
83 if (content == null || content.isEmpty()) {
84 return Collections.emptyList();
85 }
86 if (content instanceof RandomAccess) {
87 return Collections.unmodifiableList(content);
88 }
89 ArrayList<Object> ret = new ArrayList<Object>();
90 for (Iterator<?> it = content.iterator(); it.hasNext(); ) {
91 ret.add(it.next());
92 }
93 return Collections.unmodifiableList(ret);
94 }
95
96 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.filter2;
55
56 import org.jdom.Text;
57 import org.jdom.Content.CType;
58
59 /**
60 * A filter that matches Text, but not CDATA content.
61 * This filter is made accessible through {@link Filters#textOnly()}
62 *
63 * @author Rolf Lear
64 *
65 */
66 final class TextOnlyFilter extends AbstractFilter<Text> {
67
68 /**
69 * JDOM2 Serialization: Default mechanism
70 */
71 private static final long serialVersionUID = 200L;
72
73 @Override
74 public Text filter(Object content) {
75 if (content instanceof Text) {
76 final Text txt = (Text)content;
77 if (txt.getCType() == CType.Text) {
78 return txt;
79 }
80 }
81 return null;
82 }
83
84 @Override
85 public int hashCode() {
86 return this.getClass().hashCode();
87 }
88
89 @Override
90 public boolean equals(Object obj) {
91 return obj instanceof TextOnlyFilter;
92 }
93
94 }
0 <body>
1 Classes to both filter and generically type-cast nodes of a document
2 based on type, name, value, or other aspects, and to boolean
3 AND/OR/NEGATE these rules. Filters can be used in methods like
4 getContent(Filter) and getDescendants(Filter). Filters are also used
5 extensively in the XPath API. The <code>Filters</code> class provides access
6 to a large number of useful filters, and also a sampling of generally useful
7 filters is provided here. Additional filters can be user defined, and that
8 is made easier by extending thr AbstractFilter class.
9
10 </body>
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input;
55
56 /*
57 * To keep things simple, all DOM-based items are fully qualified in this code.
58 * As such, there are no import org.w3c.dom.* statements...
59 * This way there isless confusion about what a Document or Element is....
60 */
61
62 import static org.jdom.JDOMConstants.*;
63
64 import java.util.HashMap;
65
66 import org.jdom.Attribute;
67 import org.jdom.DefaultJDOMFactory;
68 import org.jdom.DocType;
69 import org.jdom.Document;
70 import org.jdom.Element;
71 import org.jdom.JDOMFactory;
72 import org.jdom.Namespace;
73
74
75 /**
76 * Builds a JDOM Document from a pre-existing DOM {@link org.w3c.dom.Document
77 * org.w3c.dom.Document}.
78 * <p>
79 * If you are building a document that has Namespace declarations, you should
80 * ensure that the Namespaces are correctly recorded in the DOM document before
81 * building the JDOM document from the DOM. By default, the native Java
82 * DOMBuilderFactory is configured to ignore Namespaces, and thus they are
83 * 'lost' in the DOM tree. JDOM expects Namespace-aware documents, so you
84 * should ensure that you change the default settings on the
85 * DOMBuilderFactory before parsing the DOM document. For example:
86 * <p>
87 * <pre>
88 * DocumentBuilderFactory domfactory = DocumentBuilderFactory.newInstance();
89 * domfactory.setNamespaceAware(true);
90 * DocumentBuilder dombuilder = domfac.newDocumentBuilder();
91 * org.w3c.dom.Document doc = dombuilder.parse(....);
92 * </pre>
93 *
94 * @author Brett McLaughlin
95 * @author Jason Hunter
96 * @author Philip Nelson
97 * @author Kevin Regan
98 * @author Yusuf Goolamabbas
99 * @author Dan Schaffer
100 * @author Bradley S. Huffman
101 */
102 public class DOMBuilder {
103
104 /** The factory for creating new JDOM objects */
105 private JDOMFactory factory = new DefaultJDOMFactory();
106
107 /**
108 * This creates a new DOMBuilder instance using the DefaultJDOMFactory
109 * to build the JDOM content.
110 */
111 public DOMBuilder() {
112 }
113
114 /**
115 * This sets a custom JDOMFactory for the builder. Use this to build
116 * the tree with your own subclasses of the JDOM classes.
117 *
118 * @param factory <code>JDOMFactory</code> to use
119 */
120 public void setFactory(JDOMFactory factory) {
121 this.factory = factory;
122 }
123
124 /**
125 * Returns the current {@link org.jdom.JDOMFactory} in use.
126 * @return the factory in use
127 */
128 public JDOMFactory getFactory() {
129 return factory;
130 }
131
132 /**
133 * This will build a JDOM tree from an existing DOM tree.
134 *
135 * @param domDocument <code>org.w3c.dom.Document</code> object
136 * @return <code>Document</code> - JDOM document object.
137 */
138 public Document build(org.w3c.dom.Document domDocument) {
139 Document doc = factory.document(null);
140 buildTree(domDocument, doc, null, true);
141 return doc;
142 }
143
144 /**
145 * This will build a JDOM Element from an existing DOM Element
146 *
147 * @param domElement <code> org.w3c.dom.Element</code> object
148 * @return <code>Element</code> - JDOM Element object
149 */
150 public org.jdom.Element build(org.w3c.dom.Element domElement) {
151 Document doc = factory.document(null);
152 buildTree(domElement, doc, null, true);
153 return doc.getRootElement();
154 }
155
156 /**
157 * This will build a JDOM CDATA from an existing DOM CDATASection
158 *
159 * @param cdata <code> org.w3c.dom.CDATASection</code> object
160 * @return <code>CDATA</code> - JDOM CDATA object
161 * @since JDOM2
162 */
163 public org.jdom.CDATA build(org.w3c.dom.CDATASection cdata) {
164 return factory.cdata(cdata.getNodeValue());
165 }
166
167 /**
168 * This will build a JDOM Text from an existing DOM Text
169 *
170 * @param text <code> org.w3c.dom.Text</code> object
171 * @return <code>Text</code> - JDOM Text object
172 * @since JDOM2
173 */
174 public org.jdom.Text build(org.w3c.dom.Text text) {
175 return factory.text(text.getNodeValue());
176 }
177
178 /**
179 * This will build a JDOM Comment from an existing DOM Comment
180 *
181 * @param comment <code> org.w3c.dom.Comment</code> object
182 * @return <code>Comment</code> - JDOM Comment object
183 * @since JDOM2
184 */
185 public org.jdom.Comment build(org.w3c.dom.Comment comment) {
186 return factory.comment(comment.getNodeValue());
187 }
188
189 /**
190 * This will build a JDOM ProcessingInstruction from an existing DOM ProcessingInstruction
191 *
192 * @param pi <code> org.w3c.dom.ProcessingInstruction</code> object
193 * @return <code>ProcessingInstruction</code> - JDOM ProcessingInstruction object
194 * @since JDOM2
195 */
196 public org.jdom.ProcessingInstruction build(org.w3c.dom.ProcessingInstruction pi) {
197 return factory.processingInstruction(pi.getTarget(), pi.getData());
198 }
199
200 /**
201 * This will build a JDOM EntityRef from an existing DOM EntityReference
202 *
203 * @param er <code> org.w3c.dom.EntityReference</code> object
204 * @return <code>EnityRef</code> - JDOM EntityRef object
205 * @since JDOM2
206 */
207 public org.jdom.EntityRef build(org.w3c.dom.EntityReference er) {
208 return factory.entityRef(er.getNodeName());
209 }
210
211 /**
212 * This will build a JDOM Element from an existing DOM Element
213 *
214 * @param doctype <code> org.w3c.dom.Element</code> object
215 * @return <code>Element</code> - JDOM Element object
216 * @since JDOM2
217 */
218 public org.jdom.DocType build(org.w3c.dom.DocumentType doctype) {
219 String publicID = doctype.getPublicId();
220 String systemID = doctype.getSystemId();
221 String internalDTD = doctype.getInternalSubset();
222
223 DocType docType = factory.docType(doctype.getName());
224 docType.setPublicID(publicID);
225 docType.setSystemID(systemID);
226 docType.setInternalSubset(internalDTD);
227 return docType;
228 }
229
230
231
232 /**
233 * This takes a DOM <code>Node</code> and builds up
234 * a JDOM tree, recursing until the DOM tree is exhausted
235 * and the JDOM tree results.
236 *
237 * @param node <code>Code</node> to examine.
238 * @param doc JDOM <code>Document</code> being built.
239 * @param current <code>Element</code> that is current parent.
240 * @param atRoot <code>boolean</code> indicating whether at root level.
241 */
242 private void buildTree(org.w3c.dom.Node node,
243 Document doc,
244 Element current,
245 boolean atRoot) {
246 // Recurse through the tree
247 switch (node.getNodeType()) {
248 case org.w3c.dom.Node.DOCUMENT_NODE:
249 org.w3c.dom.NodeList nodes = node.getChildNodes();
250 for (int i=0, size=nodes.getLength(); i<size; i++) {
251 buildTree(nodes.item(i), doc, current, true);
252 }
253 break;
254
255 case org.w3c.dom.Node.ELEMENT_NODE:
256 String nodeName = node.getNodeName();
257 String prefix = NS_PREFIX_DEFAULT;
258 String localName = nodeName;
259 int colon = nodeName.indexOf(':');
260 if (colon >= 0) {
261 prefix = nodeName.substring(0, colon);
262 localName = nodeName.substring(colon + 1);
263 }
264
265 // Get element's namespace
266 Namespace ns = null;
267 String uri = node.getNamespaceURI();
268 if (uri == null) {
269 ns = (current == null) ? Namespace.NO_NAMESPACE
270 : current.getNamespace(prefix);
271 }
272 else {
273 ns = Namespace.getNamespace(prefix, uri);
274 }
275
276 Element element = factory.element(localName, ns);
277
278 if (atRoot) {
279 // If at root, set as document root
280 factory.setRoot(doc, element);
281 } else {
282 // else add to parent element
283 factory.addContent(current, element);
284 }
285
286 // Add namespaces
287 org.w3c.dom.NamedNodeMap attributeList = node.getAttributes();
288 int attsize = attributeList.getLength();
289
290 for (int i = 0; i < attsize; i++) {
291 org.w3c.dom.Attr att = (org.w3c.dom.Attr) attributeList.item(i);
292
293 String attname = att.getName();
294 if (attname.startsWith(NS_PREFIX_XMLNS)) {
295 String attPrefix = NS_PREFIX_DEFAULT;
296 colon = attname.indexOf(':');
297 if (colon >= 0) {
298 attPrefix = attname.substring(colon + 1);
299 }
300
301 String attvalue = att.getValue();
302
303 Namespace declaredNS =
304 Namespace.getNamespace(attPrefix, attvalue);
305
306 // Add as additional namespaces if it's different
307 // to this element's namespace (perhaps we should
308 // also have logic not to mark them as additional if
309 // it's been done already, but it probably doesn't
310 // matter)
311 if (prefix.equals(attPrefix)) {
312 // RL: note, it should also be true that uri.equals(attvalue)
313 // if not, then the parser is boken.
314 // further, declaredNS should be exactly the same as ns
315 // so the following should in fact do nothing.
316 element.setNamespace(declaredNS);
317 }
318 else {
319 factory.addNamespaceDeclaration(element, declaredNS);
320 }
321 }
322 }
323
324 // Add attributes
325 for (int i = 0; i < attsize; i++) {
326 org.w3c.dom.Attr att = (org.w3c.dom.Attr) attributeList.item(i);
327
328 String attname = att.getName();
329
330 if ( !attname.startsWith(NS_PREFIX_XMLNS)) {
331 String attPrefix = NS_PREFIX_DEFAULT;
332 String attLocalName = attname;
333 colon = attname.indexOf(':');
334 if (colon >= 0) {
335 attPrefix = attname.substring(0, colon);
336 attLocalName = attname.substring(colon + 1);
337 }
338
339 String attvalue = att.getValue();
340
341 // Get attribute's namespace
342 Namespace attNS = null;
343 String attURI = att.getNamespaceURI();
344 if (attPrefix.isEmpty() && (attURI == null || NS_URI_DEFAULT.equals(attURI))) {
345 attNS = Namespace.NO_NAMESPACE;
346 } else {
347 // various conditions can lead here.
348 // the logical one is that we have a prefix for the
349 // attribute, and also a namespace URI.
350 // The alternative to that is in some conditions,
351 // the parser could have a 'default' or 'fixed'
352 // attribute that comes from an XSD used for
353 // validation. In that case there may not be a prefix
354 // There's also the possibility the DOM contains
355 // garbage.
356 if (attPrefix.length() > 0) {
357 // If the att has a prefix, we can assume that
358 // the DOM is valid, and we can just use the prefix.
359 // if this prefix conflicts with some other namespace
360 // then we re-declare it. If redeclaring it screws up
361 // other attributes in this Element, then the DOM
362 // was broken to start with.
363 if (attURI == null) {
364 // this can happen when the DOM is created
365 // without being namespace aware. we have a
366 // prefix, but the URI is not embedded in
367 // the Attribute itself. It must be declared
368 // on the element somewhere....
369 // https://github.com/hunterhacker/jdom/issues/138
370 attNS = element.getNamespace(attPrefix);
371 } else {
372 attNS = Namespace.getNamespace(attPrefix, attURI);
373 }
374 } else {
375 // OK, no prefix.
376 // must be a defaulted value from an XSD.
377 // perhaps we can find the namespace in our
378 // element's ancestry, and use the prefix from that.
379 HashMap<String, Namespace> tmpmap = new HashMap<String, Namespace>();
380 for(Namespace nss : element.getNamespacesInScope()) {
381 if (nss.getPrefix().length() > 0 && nss.getURI().equals(attURI)) {
382 attNS = nss;
383 break;
384 }
385 tmpmap.put(nss.getPrefix(), nss);
386 }
387 if (attNS == null) {
388 // we cannot find a 'prevailing' namespace that has a prefix
389 // that is for this namespace.
390 // This basically means that there's an XMLSchema, for the
391 // DEFAULT namespace, and there's a defaulted/fixed
392 // attribute definition in the XMLSchema that's targeted
393 // for this namespace,... but, the user has either not
394 // declared a prefixed version of the namespace, or has
395 // re-declared the same prefix at a lower level with a
396 // different namespace.
397 // All of these things are possible.
398 // Create some sort of default prefix.
399 int cnt = 0;
400 String base = "attns";
401 String pfx = base + cnt;
402 while (tmpmap.containsKey(pfx)) {
403 cnt++;
404 pfx = base + cnt;
405 }
406 attNS = Namespace.getNamespace(pfx, attURI);
407 }
408 }
409 }
410
411 Attribute attribute =
412 factory.attribute(attLocalName, attvalue, attNS);
413 factory.setAttribute(element, attribute);
414 }
415 }
416
417 // Recurse on child nodes
418 // The list should never be null nor should it ever contain
419 // null nodes, but some DOM impls are broken
420 org.w3c.dom.NodeList children = node.getChildNodes();
421 if (children != null) {
422 int size = children.getLength();
423 for (int i = 0; i < size; i++) {
424 org.w3c.dom.Node item = children.item(i);
425 if (item != null) {
426 buildTree(item, doc, element, false);
427 }
428 }
429 }
430 break;
431
432 case org.w3c.dom.Node.TEXT_NODE:
433 factory.addContent(current, build((org.w3c.dom.Text)node));
434 break;
435
436 case org.w3c.dom.Node.CDATA_SECTION_NODE:
437 factory.addContent(current, build((org.w3c.dom.CDATASection)node));
438 break;
439
440
441 case org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE:
442 if (atRoot) {
443 factory.addContent(doc, build((org.w3c.dom.ProcessingInstruction)node));
444 } else {
445 factory.addContent(current, build((org.w3c.dom.ProcessingInstruction)node));
446 }
447 break;
448
449 case org.w3c.dom.Node.COMMENT_NODE:
450 if (atRoot) {
451 factory.addContent(doc, build((org.w3c.dom.Comment)node));
452 } else {
453 factory.addContent(current, build((org.w3c.dom.Comment)node));
454 }
455 break;
456
457 case org.w3c.dom.Node.ENTITY_REFERENCE_NODE:
458 factory.addContent(current, build((org.w3c.dom.EntityReference)node));
459 break;
460
461 case org.w3c.dom.Node.ENTITY_NODE:
462 // ??
463 break;
464
465 case org.w3c.dom.Node.DOCUMENT_TYPE_NODE:
466
467 factory.addContent(doc, build((org.w3c.dom.DocumentType)node));
468 break;
469 }
470 }
471 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input;
55
56 import org.jdom.*;
57 import org.xml.sax.*;
58
59 /**
60 * Thrown during parse errors, with information about where the parse error
61 * occurred as well as access to the partially built document.
62 *
63 * @author Laurent Bihanic
64 */
65 public class JDOMParseException extends JDOMException {
66
67 /**
68 * Standard JDOM2 Exception Serialization. Default.
69 */
70 private static final long serialVersionUID = 200L;
71
72 /**
73 * The portion of the document that was successfully built before
74 * the parse error occurred.
75 */
76 private final Document partialDocument;
77
78 /**
79 * This will create a parse <code>Exception</code> with the given
80 * message and wrap the <code>Exception</code> that cause a document
81 * parse to fail.
82 *
83 * @param message <code>String</code> message indicating
84 * the problem that occurred.
85 * @param cause <code>Throwable</code> that caused this
86 * to be thrown.
87 */
88 public JDOMParseException(String message, Throwable cause) {
89 this(message, cause, null);
90 }
91
92 /**
93 * This will create a parse <code>Exception</code> with the given
94 * message and the partial document and wrap the
95 * <code>Exception</code> that cause a document parse to fail.
96 *
97 * @param message <code>String</code> message indicating
98 * the problem that occurred.
99 * @param cause <code>Throwable</code> that caused this
100 * to be thrown.
101 * @param partialDocument <code>Document</code> the portion of
102 * the input XML document that was
103 * successfully built.
104 */
105 public JDOMParseException(String message, Throwable cause,
106 Document partialDocument) {
107 super(message, cause);
108 this.partialDocument = partialDocument;
109 }
110
111 /**
112 * Returns the partial document that was successfully built before
113 * the error occurred.
114 *
115 * @return the partial document or null if none.
116 */
117 public Document getPartialDocument() {
118 return partialDocument;
119 }
120
121 /**
122 * Returns the public identifier of the entity where the
123 * parse error occurred.
124 *
125 * @return a string containing the public identifier, or
126 * <code>null</code> if the information is not available.
127 */
128 public String getPublicId() {
129 return (getCause() instanceof SAXParseException)?
130 ((SAXParseException)getCause()).getPublicId(): null;
131 }
132
133 /**
134 * Returns the system identifier of the entity where the
135 * parse error occurred.
136 *
137 * @return a string containing the system identifier, or
138 * <code>null</code> if the information is not available.
139 */
140 public String getSystemId() {
141 return (getCause() instanceof SAXParseException)?
142 ((SAXParseException)getCause()).getSystemId(): null;
143 }
144
145 /**
146 * Returns the line number of the end of the text where the
147 * parse error occurred.
148 * <p>
149 * The first line in the document is line 1.</p>
150 *
151 * @return an integer representing the line number, or -1
152 * if the information is not available.
153 */
154 public int getLineNumber() {
155 return (getCause() instanceof SAXParseException)?
156 ((SAXParseException)getCause()).getLineNumber(): -1;
157 }
158
159 /**
160 * Returns the column number of the end of the text where the
161 * parse error occurred.
162 * <p>
163 * The first column in a line is position 1.</p>
164 *
165 * @return an integer representing the column number, or -1
166 * if the information is not available.
167 */
168 public int getColumnNumber() {
169 return (getCause() instanceof SAXParseException)?
170 ((SAXParseException)getCause()).getColumnNumber(): -1;
171 }
172 }
173
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input;
55
56 import static org.jdom.JDOMConstants.SAX_FEATURE_EXTERNAL_ENT;
57 import static org.jdom.JDOMConstants.SAX_PROPERTY_DECLARATION_HANDLER;
58 import static org.jdom.JDOMConstants.SAX_PROPERTY_LEXICAL_HANDLER;
59 import static org.jdom.JDOMConstants.SAX_PROPERTY_LEXICAL_HANDLER_ALT;
60
61 import java.io.File;
62 import java.io.IOException;
63 import java.io.InputStream;
64 import java.io.Reader;
65 import java.net.MalformedURLException;
66 import java.net.URL;
67 import java.util.HashMap;
68 import java.util.Map;
69
70 import org.xml.sax.DTDHandler;
71 import org.xml.sax.EntityResolver;
72 import org.xml.sax.ErrorHandler;
73 import org.xml.sax.InputSource;
74 import org.xml.sax.SAXException;
75 import org.xml.sax.SAXNotRecognizedException;
76 import org.xml.sax.SAXNotSupportedException;
77 import org.xml.sax.XMLFilter;
78 import org.xml.sax.XMLReader;
79
80 import org.jdom.DefaultJDOMFactory;
81 import org.jdom.DocType;
82 import org.jdom.Document;
83 import org.jdom.EntityRef;
84 import org.jdom.JDOMException;
85 import org.jdom.JDOMFactory;
86 import org.jdom.Verifier;
87 import org.jdom.input.sax.BuilderErrorHandler;
88 import org.jdom.input.sax.DefaultSAXHandlerFactory;
89 import org.jdom.input.sax.SAXBuilderEngine;
90 import org.jdom.input.sax.SAXEngine;
91 import org.jdom.input.sax.SAXHandler;
92 import org.jdom.input.sax.SAXHandlerFactory;
93 import org.jdom.input.sax.XMLReaderJDOMFactory;
94 import org.jdom.input.sax.XMLReaderSAX2Factory;
95 import org.jdom.input.sax.XMLReaders;
96
97 /**
98 * Builds a JDOM Document using a SAX parser.
99 * <p>
100 * SAXbuilder uses a third-party SAX parser (chosen by JAXP by default, or you
101 * can configure it manually) to handle the parsing duties and uses an instance
102 * of a SAXHandler to listen to the SAX events in order to construct a document
103 * with JDOM content using a JDOMFactory. Information about SAX can be found at
104 * <a href="http://www.saxproject.org">http://www.saxproject.org</a>.
105 * <p>
106 * For a complete description of how SAXBuilder is used, and how to customise
107 * the process you should look at the {@link org.jdom.input.sax} package
108 * documentation.
109 * <p>
110 * JDOM users needing to customise the SAX parsing process have traditionally
111 * sub-classed this SAXBuilder class. In JDOM2 this should never be necessary.
112 * Please read the full documentation of this class, {@link SAXHandler},
113 * {@link SAXHandlerFactory}, {@link JDOMFactory}, and the package documentation
114 * for {@link org.jdom.input.sax} before overriding this class. Future versions
115 * of JDOM2 may make this class 'final'. I you feel you have a good reason to
116 * subclass SAXBuilder please mention it on <a
117 * href="http://www.jdom.org/involved/lists.html">jdom-interest</a> mailing list
118 * so that SAXBuilder can be extended or adapted to handle your use-case.
119 * <p>
120 * Neither SAXBuilder nor anything derived from SAXBuilder is thread-safe. You
121 * must ensure that SAXBuilder is used in a single thread, or that sufficient
122 * locking is in place to ensure that SAXBuilder is not concurrently accessed.
123 * See the special note on {@link #buildEngine()}.
124 * <p>
125 * Known issues:
126 * <ul>
127 * <li>Relative paths for a {@link DocType} or {@link EntityRef} may be
128 * converted by the SAX parser into absolute paths.
129 * <li>SAX does not recognise whitespace character content outside the root
130 * element (nor does JDOM) so any formatting outside the root Element will be
131 * lost.
132 * </ul>
133 *
134 * @see org.jdom.input.sax
135 * @author Jason Hunter
136 * @author Brett McLaughlin
137 * @author Dan Schaffer
138 * @author Philip Nelson
139 * @author Alex Rosen
140 * @author Rolf Lear
141 */
142 public class SAXBuilder implements SAXEngine {
143
144 /** Default source of SAXHandlers */
145 private static final SAXHandlerFactory DEFAULTSAXHANDLERFAC =
146 new DefaultSAXHandlerFactory();
147
148 /** Default source of JDOM Content */
149 private static final JDOMFactory DEFAULTJDOMFAC = new DefaultJDOMFactory();
150
151 /*
152 * ====================================================================
153 */
154
155 /**
156 * The XMLReader pillar of SAXBuilder
157 */
158 private XMLReaderJDOMFactory readerfac = null;
159
160 /**
161 * The SAXHandler pillar of SAXBuilder
162 */
163 private SAXHandlerFactory handlerfac = null;
164
165 /**
166 * The JDOMFactory pillar for creating new JDOM objects
167 */
168 private JDOMFactory jdomfac = null;
169
170 /*
171 * ========================================================================
172 * Configuration settings for SAX parsing.
173 * ========================================================================
174 */
175
176 /** User-specified features to be set on the SAX parser */
177 private final HashMap<String, Boolean> features = new HashMap<String, Boolean>(5);
178
179 /** User-specified properties to be set on the SAX parser */
180 private final HashMap<String, Object> properties = new HashMap<String, Object>(5);
181
182 /** ErrorHandler class to use */
183 private ErrorHandler saxErrorHandler = null;
184
185 /** EntityResolver class to use */
186 private EntityResolver saxEntityResolver = null;
187
188 /** DTDHandler class to use */
189 private DTDHandler saxDTDHandler = null;
190
191 /** XMLFilter instance to use */
192 private XMLFilter saxXMLFilter = null;
193
194 /** Whether expansion of entities should occur */
195 private boolean expand = true;
196
197 /** Whether to ignore ignorable whitespace */
198 private boolean ignoringWhite = false;
199
200 /** Whether to ignore all whitespace content */
201 private boolean ignoringBoundaryWhite = false;
202
203 /** Whether parser reuse is allowed. */
204 private boolean reuseParser = true;
205
206 /** The current SAX parser, if parser reuse has been activated. */
207 private SAXEngine engine = null;
208
209 /**
210 * Creates a new JAXP-based SAXBuilder. The underlying parser will not
211 * validate.
212 *
213 * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
214 * JDOMFactory)
215 * @see XMLReaders#NONVALIDATING
216 * @see DefaultSAXHandlerFactory
217 * @see DefaultJDOMFactory
218 */
219 public SAXBuilder() {
220 this(null, null, null);
221 }
222
223 /**
224 * Creates a new JAXP-based SAXBuilder. The underlying parser will validate
225 * (using DTD) or not according to the given parameter. If you want Schema
226 * validation then use SAXBuilder(XMLReaders.XSDVALIDATOR)
227 *
228 * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
229 * JDOMFactory)
230 * @see XMLReaders#NONVALIDATING
231 * @see XMLReaders#DTDVALIDATING
232 * @see DefaultSAXHandlerFactory
233 * @see DefaultJDOMFactory
234 * @see org.jdom.input.sax for important details on SAXBuilder
235 * @param validate
236 * <code>boolean</code> indicating if DTD validation should occur.
237 * @deprecated use {@link SAXBuilder#SAXBuilder(XMLReaderJDOMFactory)} with
238 * either {@link XMLReaders#DTDVALIDATING}
239 * or {@link XMLReaders#NONVALIDATING}
240 */
241 @Deprecated
242 public SAXBuilder(final boolean validate) {
243 this(validate
244 ? XMLReaders.DTDVALIDATING
245 : XMLReaders.NONVALIDATING,
246 null, null);
247 }
248
249 /**
250 * Creates a new SAXBuilder using the specified SAX parser. The underlying
251 * parser will not validate.
252 *
253 * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
254 * JDOMFactory)
255 * @see XMLReaderSAX2Factory
256 * @see DefaultSAXHandlerFactory
257 * @see DefaultJDOMFactory
258 * @see org.jdom.input.sax for important details on SAXBuilder
259 * @param saxDriverClass
260 * <code>String</code> name of SAX Driver to use for parsing.
261 * @deprecated use {@link SAXBuilder#SAXBuilder(XMLReaderJDOMFactory)} with
262 * {@link XMLReaderSAX2Factory#XMLReaderSAX2Factory(boolean, String)}
263 */
264 @Deprecated
265 public SAXBuilder(final String saxDriverClass) {
266 this(saxDriverClass, false);
267 }
268
269 /**
270 * Creates a new SAXBuilder using the specified SAX2.0 parser source. The
271 * underlying parser will validate or not according to the given parameter.
272 *
273 * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
274 * JDOMFactory)
275 * @see XMLReaderSAX2Factory
276 * @see DefaultSAXHandlerFactory
277 * @see DefaultJDOMFactory
278 * @see org.jdom.input.sax for important details on SAXBuilder
279 * @param saxDriverClass
280 * <code>String</code> name of SAX Driver to use for parsing.
281 * @param validate
282 * <code>boolean</code> indicating if validation should occur.
283 * @deprecated use {@link SAXBuilder#SAXBuilder(XMLReaderJDOMFactory)} with
284 * {@link XMLReaderSAX2Factory#XMLReaderSAX2Factory(boolean, String)}
285 */
286 @Deprecated
287 public SAXBuilder(final String saxDriverClass, final boolean validate) {
288 this(new XMLReaderSAX2Factory(validate, saxDriverClass), null, null);
289 }
290
291 /**
292 * Creates a new SAXBuilder with the specified XMLReaderJDOMFactory.
293 * <p>
294 *
295 * @see SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory,
296 * JDOMFactory)
297 * @see XMLReaderJDOMFactory
298 * @see XMLReaders#NONVALIDATING
299 * @see DefaultSAXHandlerFactory
300 * @see DefaultJDOMFactory
301 * @see org.jdom.input.sax for important details on SAXBuilder
302 * @param readersouce
303 * the {@link XMLReaderJDOMFactory} that supplies XMLReaders. If the
304 * value is null then a Non-Validating JAXP-based SAX2.0 parser will
305 * be used.
306 */
307 public SAXBuilder(final XMLReaderJDOMFactory readersouce) {
308 this(readersouce, null, null);
309 }
310
311 /**
312 * Creates a new SAXBuilder. This is the base constructor for all other
313 * SAXBuilder constructors: they all find a way to create a
314 * JDOMXMLReaderFactory and then call this constructor with that factory,
315 * and the {@link DefaultSAXHandlerFactory} and {@link DefaultJDOMFactory}.
316 * <p>
317 *
318 * @see XMLReaderJDOMFactory
319 * @see XMLReaders#NONVALIDATING
320 * @see SAXHandlerFactory
321 * @see DefaultSAXHandlerFactory
322 * @see JDOMFactory
323 * @see DefaultJDOMFactory
324 * @see org.jdom.input.sax for important details on SAXBuilder
325 * @param xmlreaderfactory
326 * a {@link XMLReaderJDOMFactory} that creates XMLReaders. Specify
327 * null for the default.
328 * @param handlerfactory
329 * a {@link SAXHandlerFactory} that creates SAXHandlers Specify null
330 * for the default.
331 * @param jdomfactory
332 * a {@link JDOMFactory} that creates JDOM Content. Specify null for
333 * the default.
334 */
335 public SAXBuilder(final XMLReaderJDOMFactory xmlreaderfactory, final SAXHandlerFactory handlerfactory,
336 final JDOMFactory jdomfactory) {
337 this.readerfac = xmlreaderfactory == null
338 ? XMLReaders.NONVALIDATING
339 : xmlreaderfactory;
340 this.handlerfac = handlerfactory == null
341 ? DEFAULTSAXHANDLERFAC
342 : handlerfactory;
343 this.jdomfac = jdomfactory == null
344 ? DEFAULTJDOMFAC
345 : jdomfactory;
346 }
347
348 /**
349 * Returns the driver class assigned in the constructor, or null if none.
350 * The driver class is only available if a SAX2 source was specified. This
351 * method is available for backward-compatibility with JDOM 1.x
352 *
353 * @return the driver class assigned in the constructor
354 * @deprecated as the driver class is only available in limited situations
355 * and anyway it had to be supplied in a constructor as either a
356 * direct value or as an {@link XMLReaderSAX2Factory} instance.
357 */
358 @Deprecated
359 public String getDriverClass() {
360 if (readerfac instanceof XMLReaderSAX2Factory) {
361 return ((XMLReaderSAX2Factory) readerfac).getDriverClassName();
362 }
363 return null;
364 }
365
366 /**
367 * Returns the current {@link org.jdom.JDOMFactory} in use.
368 *
369 * @return the factory in use
370 * @deprecated as it is replaced by {@link #getJDOMFactory()}
371 */
372 @Deprecated
373 public JDOMFactory getFactory() {
374 return getJDOMFactory();
375 }
376
377 /**
378 * Returns the current {@link org.jdom.JDOMFactory} in use.
379 *
380 * @return the factory in use
381 */
382 @Override
383 public JDOMFactory getJDOMFactory() {
384 return jdomfac;
385 }
386
387 /**
388 * This sets a custom JDOMFactory for the builder. Use this to build the
389 * tree with your own subclasses of the JDOM classes.
390 *
391 * @param factory
392 * <code>JDOMFactory</code> to use
393 * @deprecated as it is replaced by {@link #setJDOMFactory(JDOMFactory)}
394 */
395 @Deprecated
396 public void setFactory(final JDOMFactory factory) {
397 setJDOMFactory(factory);
398 }
399
400 /**
401 * This sets a custom JDOMFactory for the builder. Use this to build the
402 * tree with your own subclasses of the JDOM classes.
403 *
404 * @param factory
405 * <code>JDOMFactory</code> to use
406 */
407 public void setJDOMFactory(final JDOMFactory factory) {
408 this.jdomfac = factory;
409 engine = null;
410 }
411
412 /**
413 * Get the current XMLReader factory.
414 *
415 * @return the current JDOMXMLReaderFactory
416 */
417 public XMLReaderJDOMFactory getXMLReaderFactory() {
418 return readerfac;
419 }
420
421 /**
422 * Set the current XMLReader factory.
423 *
424 * @param rfac
425 * the JDOMXMLReaderFactory to set. A null rfac will indicate the
426 * default {@link XMLReaders#NONVALIDATING}
427 */
428 public void setXMLReaderFactory(final XMLReaderJDOMFactory rfac) {
429 readerfac = rfac == null
430 ? XMLReaders.NONVALIDATING
431 : rfac;
432 engine = null;
433 }
434
435 /**
436 * Get the SAXHandlerFactory used to supply SAXHandlers to this SAXBuilder.
437 *
438 * @return the current SAXHandlerFactory (never null).
439 */
440 public SAXHandlerFactory getSAXHandlerFactory() {
441 return handlerfac;
442 }
443
444 /**
445 * Set the SAXHandlerFactory to be used by this SAXBuilder.
446 *
447 * @param factory
448 * the required SAXHandlerFactory. A null input factory will request
449 * the {@link DefaultSAXHandlerFactory}.
450 */
451 public void setSAXHandlerFactory(final SAXHandlerFactory factory) {
452 this.handlerfac = factory == null ? DEFAULTSAXHANDLERFAC : factory;
453 engine = null;
454 }
455
456 /**
457 * Returns whether validation is to be performed during the build.
458 *
459 * @return whether validation is to be performed during the build
460 * @deprecated in lieu of {@link #isValidating()}
461 */
462 @Deprecated
463 public boolean getValidation() {
464 return isValidating();
465 }
466
467 /**
468 * Returns whether validation is to be performed during the build.
469 *
470 * @return whether validation is to be performed during the build
471 */
472 @Override
473 public boolean isValidating() {
474 return readerfac.isValidating();
475 }
476
477 /**
478 * This sets validation for the builder.
479 * <p>
480 * <b>Do Not Use</b>
481 * <p>
482 * JDOM2 introduces the concept of XMLReader factories. The XMLReader is
483 * what determines the type of validation. A simple boolean is not enough to
484 * indicate what sort of validation is required. The
485 * {@link #setXMLReaderFactory(XMLReaderJDOMFactory)} method provides a
486 * means to be more specific about validation.
487 * <p>
488 * For backward compatibility this method has been retained, but its use is
489 * discouraged. It does make some logical choices though. The code is
490 * equivalent to:
491 * <p>
492 *
493 * <pre>
494 * setXMLReaderFactory(XMLReaders.DTDVALIDATING)
495 * </pre>
496 *
497 * for true, and
498 *
499 * <pre>
500 * setXMLReaderFactory(XMLReaders.NONVALIDATING)
501 * </pre>
502 *
503 * for false.
504 *
505 * @see #setXMLReaderFactory(XMLReaderJDOMFactory)
506 * @see XMLReaders#NONVALIDATING
507 * @see XMLReaders#DTDVALIDATING
508 * @param validate
509 * <code>boolean</code> indicating whether validation should occur.
510 * @deprecated use {@link #setXMLReaderFactory(XMLReaderJDOMFactory)}
511 */
512 @Deprecated
513 public void setValidation(final boolean validate) {
514 setXMLReaderFactory(validate
515 ? XMLReaders.DTDVALIDATING
516 : XMLReaders.NONVALIDATING);
517 }
518
519 /**
520 * Returns the {@link ErrorHandler} assigned, or null if none. When the
521 * SAXBuilder parses a document it will always have an ErrorHandler but it
522 * will be an instance of {@link BuilderErrorHandler} unless you specify a
523 * different ErrorHandler in {@link #setErrorHandler(ErrorHandler)}. In
524 * other words, a null return value from here indicates a default will be
525 * used.
526 *
527 * @return the ErrorHandler assigned, or null if SAXBuilder will create a
528 * default ErrorHandler when needed.
529 */
530 @Override
531 public ErrorHandler getErrorHandler() {
532 return saxErrorHandler;
533 }
534
535 /**
536 * This sets custom ErrorHandler for the Builder. Setting a null value will
537 * indicate SAXBuilder should create a default ErrorHandler when needed.
538 *
539 * @param errorHandler
540 * <code>ErrorHandler</code>
541 */
542 public void setErrorHandler(final ErrorHandler errorHandler) {
543 saxErrorHandler = errorHandler;
544 engine = null;
545 }
546
547 /**
548 * Returns the {@link EntityResolver} assigned, or null if none.
549 *
550 * @return the EntityResolver assigned
551 */
552 @Override
553 public EntityResolver getEntityResolver() {
554 return saxEntityResolver;
555 }
556
557 /**
558 * This sets custom EntityResolver for the <code>Builder</code>.
559 *
560 * @param entityResolver
561 * <code>EntityResolver</code>
562 */
563 public void setEntityResolver(final EntityResolver entityResolver) {
564 saxEntityResolver = entityResolver;
565 engine = null;
566 }
567
568 /**
569 * Returns the {@link DTDHandler} assigned, or null if the assigned
570 * {@link SAXHandler} will be used for DTD SAX events.
571 *
572 * @return the DTDHandler assigned
573 */
574 @Override
575 public DTDHandler getDTDHandler() {
576 return saxDTDHandler;
577 }
578
579 /**
580 * This sets custom DTDHandler for the <code>Builder</code>. Setting a null
581 * value indicates that SAXBuilder should use the assigned SAXHandler for
582 * DTD processing.
583 *
584 * @param dtdHandler
585 * <code>DTDHandler</code>
586 */
587 public void setDTDHandler(final DTDHandler dtdHandler) {
588 saxDTDHandler = dtdHandler;
589 engine = null;
590 }
591
592 /**
593 * Returns the {@link XMLFilter} used during parsing, or null if none.
594 *
595 * @return the XMLFilter used during parsing
596 */
597 public XMLFilter getXMLFilter() {
598 return saxXMLFilter;
599 }
600
601 /**
602 * This sets a custom {@link org.xml.sax.XMLFilter} for the builder.
603 * <p>
604 * Care should be taken to ensure that the specified xmlFilter is reentrant
605 * and thread-safe.
606 * <p>
607 * SAXBuilder will set this instance as the parent instance for all
608 * XMLReaders that may be created, and these may (depending on SAXBuilder
609 * usage) be accessed concurrently. It is the responsibility of the JDOM
610 * user to ensure that if the XMLFilter is not thread-safe then neither the
611 * SAXBuilder nor any of it's SAXEngines are accessed concurrently.
612 *
613 * @param xmlFilter
614 * the XMLFilter to use
615 */
616 public void setXMLFilter(final XMLFilter xmlFilter) {
617 saxXMLFilter = xmlFilter;
618 engine = null;
619 }
620
621 /**
622 * Returns whether element content whitespace is to be ignored during the
623 * build.
624 *
625 * @return whether element content whitespace is to be ignored during the
626 * build
627 */
628 @Override
629 public boolean getIgnoringElementContentWhitespace() {
630 return ignoringWhite;
631 }
632
633 /**
634 * Specifies whether or not the parser should eliminate whitespace in
635 * element content (sometimes known as "ignorable whitespace") when building
636 * the document. Only whitespace which is contained within element content
637 * that has an element only content model will be eliminated (see XML Rec
638 * 3.2.1). For this setting to take effect requires that validation be
639 * turned on. The default value of this setting is <code>false</code>.
640 *
641 * @param ignoringWhite
642 * Whether to ignore ignorable whitespace
643 */
644 public void setIgnoringElementContentWhitespace(final boolean ignoringWhite) {
645 this.ignoringWhite = ignoringWhite;
646 engine = null;
647 }
648
649 /**
650 * Returns whether or not the parser will eliminate element content
651 * containing only whitespace.
652 *
653 * @return <code>boolean</code> - whether only whitespace content will be
654 * ignored during build.
655 * @see #setIgnoringBoundaryWhitespace
656 */
657 @Override
658 public boolean getIgnoringBoundaryWhitespace() {
659 return ignoringBoundaryWhite;
660 }
661
662 /**
663 * Specifies whether or not the parser should elminate boundary whitespace,
664 * a term that indicates whitespace-only text between element tags. This
665 * feature is a lot like
666 * {@link #setIgnoringElementContentWhitespace(boolean)} but this feature is
667 * more aggressive and doesn't require validation be turned on. The
668 * {@link #setIgnoringElementContentWhitespace(boolean)} call impacts the
669 * SAX parse process while this method impacts the JDOM build process, so it
670 * can be beneficial to turn both on for efficiency. For implementation
671 * efficiency, this method actually removes all whitespace-only text()
672 * nodes. That can, in some cases (like between an element tag and a
673 * comment) include whitespace that isn't just boundary whitespace. The
674 * default is <code>false</code>.
675 *
676 * @param ignoringBoundaryWhite
677 * Whether to ignore whitespace-only text nodes
678 */
679 public void setIgnoringBoundaryWhitespace(final boolean ignoringBoundaryWhite) {
680 this.ignoringBoundaryWhite = ignoringBoundaryWhite;
681 engine = null;
682 }
683
684 /**
685 * Returns whether or not entities are being expanded into normal text
686 * content.
687 *
688 * @return whether entities are being expanded
689 */
690 @Override
691 public boolean getExpandEntities() {
692 return expand;
693 }
694
695 /**
696 * <p>
697 * This sets whether or not to expand entities for the builder. A true means
698 * to expand entities as normal content. A false means to leave entities
699 * unexpanded as <code>EntityRef</code> objects. The default is true.
700 * </p>
701 * <p>
702 * When this setting is false, the internal DTD subset is retained; when
703 * this setting is true, the internal DTD subset is not retained.
704 * </p>
705 * <p>
706 * Note that Xerces (at least up to 1.4.4) has a bug where entities in
707 * attribute values will be incorrectly reported if this flag is turned off,
708 * resulting in entities appearing within element content. When turning
709 * entity expansion off either avoid entities in attribute values, or use
710 * another parser like Crimson.
711 * http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6111
712 * </p>
713 *
714 * @param expand
715 * <code>boolean</code> indicating whether entity expansion should
716 * occur.
717 */
718 public void setExpandEntities(final boolean expand) {
719 this.expand = expand;
720 engine = null;
721 }
722
723 /**
724 * Returns whether the contained SAX parser instance is reused across
725 * multiple parses. The default is true.
726 *
727 * @return whether the contained SAX parser instance is reused across
728 * multiple parses
729 */
730 public boolean getReuseParser() {
731 return reuseParser;
732 }
733
734 /**
735 * Specifies whether this builder will reuse the same SAX parser when
736 * performing subsequent parses or allocate a new parser for each parse. The
737 * default value of this setting is <code>true</code> (parser reuse).
738 * <p>
739 * <strong>Note</strong>: SAX parser instances are not thread safe (they are
740 * not even reentrant), and nor are SAXBuilder instances. Setting parser
741 * reuse does not imply the parser is thread-safe.
742 * </p>
743 *
744 * @param reuseParser
745 * Whether to reuse the SAX parser.
746 */
747 public void setReuseParser(final boolean reuseParser) {
748 this.reuseParser = reuseParser;
749 if (!reuseParser) {
750 engine = null;
751 }
752 }
753
754 /**
755 * Specifies whether this builder will do fast reconfiguration of the
756 * underlying SAX parser when reuseParser is true. This improves performance
757 * in cases where SAXBuilders are reused and lots of small documents are
758 * frequently parsed. This avoids attempting to set features on the SAX
759 * parser each time build() is called which result in
760 * SaxNotRecognizedExceptions. This should ONLY be set for builders where
761 * this specific case is an issue. The default value of this setting is
762 * <code>false</code> (no fast reconfiguration). If reuseParser is false,
763 * calling this has no effect.
764 *
765 * @param fastReconfigure
766 * Whether to do a fast reconfiguration of the parser
767 * @deprecated All reused Parsers are now fast-reconfigured. No need to set
768 * it.
769 */
770 @Deprecated
771 public void setFastReconfigure(final boolean fastReconfigure) {
772 // do nothing
773 }
774
775 /**
776 * This sets a feature on the SAX parser. See the SAX documentation for
777 * more information. </p>
778 * <p>
779 * NOTE: SAXBuilder requires that some particular features of the SAX parser
780 * be set up in certain ways for it to work properly. The list of such
781 * features may change in the future. Therefore, the use of this method may
782 * cause parsing to break, and even if it doesn't break anything today it
783 * might break parsing in a future JDOM version, because what JDOM parsers
784 * require may change over time. Use with caution.
785 * </p>
786 * JDOM uses {@link XMLReaderJDOMFactory} instances to provide XMLReader
787 * instances. If you require special configuration on your XMLReader you
788 * should consider extending or implementing an XMLReaderJDOMFactory in the
789 * {@link org.jdom.input.sax} package.
790 *
791 * @param name
792 * The feature name, which is a fully-qualified URI.
793 * @param value
794 * The requested state of the feature (true or false).
795 */
796 public void setFeature(final String name, final boolean value) {
797 // Save the specified feature for later.
798 features.put(name, value ? Boolean.TRUE : Boolean.FALSE);
799 engine = null;
800 }
801
802 /**
803 * This sets a property on the SAX parser. See the SAX documentation for
804 * more information.
805 * <p>
806 * NOTE: SAXBuilder requires that some particular properties of the SAX
807 * parser be set up in certain ways for it to work properly. The list of
808 * such properties may change in the future. Therefore, the use of this
809 * method may cause parsing to break, and even if it doesn't break anything
810 * today it might break parsing in a future JDOM version, because what JDOM
811 * parsers require may change over time. Use with caution.
812 * </p>
813 * JDOM uses {@link XMLReaderJDOMFactory} instances to provide XMLReader
814 * instances. If you require special configuration on your XMLReader you
815 * should consider extending or implementing an XMLReaderJDOMFactory in the
816 * {@link org.jdom.input.sax} package.
817 *
818 * @param name
819 * The property name, which is a fully-qualified URI.
820 * @param value
821 * The requested value for the property.
822 */
823 public void setProperty(final String name, final Object value) {
824 // Save the specified property for later.
825 properties.put(name, value);
826 engine = null;
827 }
828
829 /**
830 * This method builds a new and reusable {@link SAXEngine}.
831 * Each time this method is called a new instance of a SAXEngine will be
832 * returned.
833 * <p>
834 * This method is used internally by the various SAXBuilder.build(*) methods
835 * (if any configuration has changed) but can also be used as a mechanism
836 * for creating SAXEngines to be used in parsing pools or other optimised
837 * structures.
838 *
839 * @return a {@link SAXEngine} representing the current state of the
840 * current SAXBuilder settings.
841 * @throws JDOMException
842 * if there is any problem initialising the engine.
843 */
844 public SAXEngine buildEngine() throws JDOMException {
845
846 // Create and configure the content handler.
847 final SAXHandler contentHandler = handlerfac.createSAXHandler(jdomfac);
848
849 contentHandler.setExpandEntities(expand);
850 contentHandler.setIgnoringElementContentWhitespace(ignoringWhite);
851 contentHandler.setIgnoringBoundaryWhitespace(ignoringBoundaryWhite);
852
853 final XMLReader parser = createParser();
854 // Configure parser
855 configureParser(parser, contentHandler);
856 final boolean valid = readerfac.isValidating();
857
858 return new SAXBuilderEngine(parser, contentHandler, valid);
859 }
860
861 /**
862 * Allow overriding classes access to the Parser before it is used in a
863 * SAXBuilderEngine.
864 *
865 * @return a XMLReader parser.
866 * @throws JDOMException
867 * if there is a problem
868 */
869 protected XMLReader createParser() throws JDOMException {
870 XMLReader parser = readerfac.createXMLReader();
871
872 // Install optional filter
873 if (saxXMLFilter != null) {
874 // Connect filter chain to parser
875 XMLFilter root = saxXMLFilter;
876 while (root.getParent() instanceof XMLFilter) {
877 root = (XMLFilter) root.getParent();
878 }
879 root.setParent(parser);
880
881 // Read from filter
882 parser = saxXMLFilter;
883 }
884
885 return parser;
886 }
887
888 /**
889 * This method retrieves (or builds) a SAXBuilderEngine that represents the
890 * current SAXBuilder state.
891 *
892 * @return a {@link SAXBuilderEngine} representing the current state of the
893 * current SAXBuilder settings.
894 * @throws JDOMException
895 * if there is any problem initializing the engine.
896 */
897 private SAXEngine getEngine() throws JDOMException {
898
899 if (engine != null) {
900 return engine;
901 }
902
903 engine = buildEngine();
904 return engine;
905 }
906
907 /**
908 * This configures the XMLReader to be used for reading the XML document.
909 * <p>
910 * The default implementation sets various options on the given XMLReader,
911 * such as validation, DTD resolution, entity handlers, etc., according to
912 * the options that were set (e.g. via <code>setEntityResolver</code>) and
913 * set various SAX properties and features that are required for JDOM
914 * internals. These features may change in future releases, so change this
915 * behavior at your own risk.
916 * </p>
917 *
918 * @param parser
919 * the XMLReader to configure.
920 * @param contentHandler
921 * The SAXHandler to use for the XMLReader
922 * @throws JDOMException
923 * if configuration fails.
924 */
925 protected void configureParser(final XMLReader parser, final SAXHandler contentHandler)
926 throws JDOMException {
927
928 // Setup SAX handlers.
929
930 parser.setContentHandler(contentHandler);
931
932 if (saxEntityResolver != null) {
933 parser.setEntityResolver(saxEntityResolver);
934 }
935
936 if (saxDTDHandler != null) {
937 parser.setDTDHandler(saxDTDHandler);
938 } else {
939 parser.setDTDHandler(contentHandler);
940 }
941
942 if (saxErrorHandler != null) {
943 parser.setErrorHandler(saxErrorHandler);
944 } else {
945 parser.setErrorHandler(new BuilderErrorHandler());
946 }
947
948 boolean success = false;
949
950 try {
951 parser.setProperty(SAX_PROPERTY_LEXICAL_HANDLER,
952 contentHandler);
953 success = true;
954 } catch (final SAXNotSupportedException e) {
955 // No lexical reporting available
956 } catch (final SAXNotRecognizedException e) {
957 // No lexical reporting available
958 }
959
960 // Some parsers use alternate property for lexical handling (grr...)
961 if (!success) {
962 try {
963 parser.setProperty(SAX_PROPERTY_LEXICAL_HANDLER_ALT,
964 contentHandler);
965 success = true;
966 } catch (final SAXNotSupportedException e) {
967 // No lexical reporting available
968 } catch (final SAXNotRecognizedException e) {
969 // No lexical reporting available
970 }
971 }
972
973 // Set any user-specified features on the parser.
974 for (final Map.Entry<String, Boolean> me : features.entrySet()) {
975 internalSetFeature(parser, me.getKey(), me.getValue().booleanValue(), me.getKey());
976 }
977
978 // Set any user-specified properties on the parser.
979 for (final Map.Entry<String, Object> me : properties.entrySet()) {
980 internalSetProperty(parser, me.getKey(), me.getValue(), me.getKey());
981 }
982
983 // Set entity expansion
984 // Note SAXHandler can work regardless of how this is set, but when
985 // entity expansion it's worth it to try to tell the parser not to
986 // even bother with external general entities.
987 // Apparently no parsers yet support this feature.
988 // XXX It might make sense to setEntityResolver() with a resolver
989 // that simply ignores external general entities
990 try {
991 if (parser.getFeature(SAX_FEATURE_EXTERNAL_ENT) != expand) {
992 parser.setFeature(SAX_FEATURE_EXTERNAL_ENT, expand);
993 }
994 } catch (final SAXException e) { /* Ignore... */
995 }
996
997 // Try setting the DeclHandler if entity expansion is off
998 if (!expand) {
999 try {
1000 parser.setProperty(SAX_PROPERTY_DECLARATION_HANDLER,
1001 contentHandler);
1002 success = true;
1003 } catch (final SAXNotSupportedException e) {
1004 // No lexical reporting available
1005 } catch (final SAXNotRecognizedException e) {
1006 // No lexical reporting available
1007 }
1008 }
1009
1010 }
1011
1012 /**
1013 * Tries to set a feature on the parser. If the feature cannot be set,
1014 * throws a JDOMException describing the problem.
1015 */
1016 private void internalSetFeature(final XMLReader parser, final String feature,
1017 final boolean value, final String displayName) throws JDOMException {
1018 try {
1019 parser.setFeature(feature, value);
1020 } catch (final SAXNotSupportedException e) {
1021 throw new JDOMException(
1022 displayName + " feature not supported for SAX driver " + parser.getClass().getName());
1023 } catch (final SAXNotRecognizedException e) {
1024 throw new JDOMException(
1025 displayName + " feature not recognized for SAX driver " + parser.getClass().getName());
1026 }
1027 }
1028
1029 /**
1030 * <p>
1031 * Tries to set a property on the parser. If the property cannot be set,
1032 * throws a JDOMException describing the problem.
1033 * </p>
1034 */
1035 private void internalSetProperty(final XMLReader parser, final String property,
1036 final Object value, final String displayName) throws JDOMException {
1037 try {
1038 parser.setProperty(property, value);
1039 } catch (final SAXNotSupportedException e) {
1040 throw new JDOMException(
1041 displayName + " property not supported for SAX driver " + parser.getClass().getName());
1042 } catch (final SAXNotRecognizedException e) {
1043 throw new JDOMException(
1044 displayName + " property not recognized for SAX driver " + parser.getClass().getName());
1045 }
1046 }
1047
1048 /**
1049 * This builds a document from the supplied input source.
1050 *
1051 * @param in
1052 * <code>InputSource</code> to read from
1053 * @return <code>Document</code> resultant Document object
1054 * @throws JDOMException
1055 * when errors occur in parsing
1056 * @throws IOException
1057 * when an I/O error prevents a document from being fully parsed
1058 */
1059 @Override
1060 public Document build(final InputSource in)
1061 throws JDOMException, IOException {
1062
1063 try {
1064 return getEngine().build(in);
1065 } finally {
1066 if (!reuseParser) {
1067 engine = null;
1068 }
1069 }
1070
1071 }
1072
1073 /**
1074 * <p>
1075 * This builds a document from the supplied input stream.
1076 * </p>
1077 *
1078 * @param in
1079 * <code>InputStream</code> to read from
1080 * @return <code>Document</code> resultant Document object
1081 * @throws JDOMException
1082 * when errors occur in parsing
1083 * @throws IOException
1084 * when an I/O error prevents a document from being fully parsed.
1085 */
1086 @Override
1087 public Document build(final InputStream in)
1088 throws JDOMException, IOException {
1089 try {
1090 return getEngine().build(in);
1091 } finally {
1092 if (!reuseParser) {
1093 engine = null;
1094 }
1095 }
1096 }
1097
1098 /**
1099 * <p>
1100 * This builds a document from the supplied filename.
1101 * </p>
1102 *
1103 * @param file
1104 * <code>File</code> to read from
1105 * @return <code>Document</code> resultant Document object
1106 * @throws JDOMException
1107 * when errors occur in parsing
1108 * @throws IOException
1109 * when an I/O error prevents a document from being fully parsed
1110 */
1111 @Override
1112 public Document build(final File file)
1113 throws JDOMException, IOException {
1114 try {
1115 return getEngine().build(file);
1116 } finally {
1117 if (!reuseParser) {
1118 engine = null;
1119 }
1120 }
1121 }
1122
1123 /**
1124 * <p>
1125 * This builds a document from the supplied URL.
1126 * </p>
1127 *
1128 * @param url
1129 * <code>URL</code> to read from.
1130 * @return <code>Document</code> - resultant Document object.
1131 * @throws JDOMException
1132 * when errors occur in parsing
1133 * @throws IOException
1134 * when an I/O error prevents a document from being fully parsed.
1135 */
1136 @Override
1137 public Document build(final URL url)
1138 throws JDOMException, IOException {
1139 try {
1140 return getEngine().build(url);
1141 } finally {
1142 if (!reuseParser) {
1143 engine = null;
1144 }
1145 }
1146 }
1147
1148 /**
1149 * <p>
1150 * This builds a document from the supplied input stream.
1151 * </p>
1152 *
1153 * @param in
1154 * <code>InputStream</code> to read from.
1155 * @param systemId
1156 * base for resolving relative URIs
1157 * @return <code>Document</code> resultant Document object
1158 * @throws JDOMException
1159 * when errors occur in parsing
1160 * @throws IOException
1161 * when an I/O error prevents a document from being fully parsed
1162 */
1163 @Override
1164 public Document build(final InputStream in, final String systemId)
1165 throws JDOMException, IOException {
1166 try {
1167 return getEngine().build(in, systemId);
1168 } finally {
1169 if (!reuseParser) {
1170 engine = null;
1171 }
1172 }
1173 }
1174
1175 /**
1176 * <p>
1177 * This builds a document from the supplied Reader. It's the programmer's
1178 * responsibility to make sure the reader matches the encoding of the file.
1179 * It's often easier and safer to use an InputStream rather than a Reader,
1180 * and to let the parser auto-detect the encoding from the XML declaration.
1181 * </p>
1182 *
1183 * @param characterStream
1184 * <code>Reader</code> to read from
1185 * @return <code>Document</code> resultant Document object
1186 * @throws JDOMException
1187 * when errors occur in parsing
1188 * @throws IOException
1189 * when an I/O error prevents a document from being fully parsed
1190 */
1191 @Override
1192 public Document build(final Reader characterStream)
1193 throws JDOMException, IOException {
1194 try {
1195 return getEngine().build(characterStream);
1196 } finally {
1197 if (!reuseParser) {
1198 engine = null;
1199 }
1200 }
1201 }
1202
1203 /**
1204 * <p>
1205 * This builds a document from the supplied Reader. It's the programmer's
1206 * responsibility to make sure the reader matches the encoding of the file.
1207 * It's often easier and safer to use an InputStream rather than a Reader,
1208 * and to let the parser auto-detect the encoding from the XML declaration.
1209 * </p>
1210 *
1211 * @param characterStream
1212 * <code>Reader</code> to read from.
1213 * @param systemId
1214 * base for resolving relative URIs
1215 * @return <code>Document</code> resultant Document object
1216 * @throws JDOMException
1217 * when errors occur in parsing
1218 * @throws IOException
1219 * when an I/O error prevents a document from being fully parsed
1220 */
1221 @Override
1222 public Document build(final Reader characterStream, final String systemId)
1223 throws JDOMException, IOException {
1224
1225 try {
1226 return getEngine().build(characterStream, systemId);
1227 } finally {
1228 if (!reuseParser) {
1229 engine = null;
1230 }
1231 }
1232 }
1233
1234 /**
1235 * <p>
1236 * This builds a document from the supplied URI. The URI is typically a file name, or a URL.
1237 * Do not use this method for parsing XML content that is in a Java String variable.
1238 * <p>
1239 * <ul>
1240 * <li><Strong>Right:</Strong> <code>....build("path/to/file.xml");</code>
1241 * <li><Strong>Right:</Strong> <code>....build("http://my.example.com/xmlfile");</code>
1242 * <li><Strong>Wrong:</Strong> <code>....build("&lt;root>data&lt/root>");</code>
1243 * </ul>
1244 * </p>
1245 * If your XML content is in a Java String variable and you want to parse it, then use:<br/>
1246 * <code> ....build(new StringReader("&lt;root>data&lt/root>"));</code>
1247 * <p>
1248 *
1249 * @param systemId
1250 * URI for the input
1251 * @return <code>Document</code> resultant Document object
1252 * @throws JDOMException
1253 * when errors occur in parsing
1254 * @throws IOException
1255 * when an I/O error prevents a document from being fully parsed
1256 */
1257 @Override
1258 public Document build(final String systemId)
1259 throws JDOMException, IOException {
1260 if (systemId == null) {
1261 throw new NullPointerException(
1262 "Unable to build a URI from a null systemID.");
1263 }
1264 try {
1265 return getEngine().build(systemId);
1266 } catch (IOException ioe) {
1267 // OK, Issue #63
1268 // it is common for people to pass in raw XML content instead of
1269 // a SystemID. To make troubleshooting easier, we do a simple check
1270 // all valid XML documents start with a '<' character.
1271 // no URI ever has an '<' character.
1272 // if we think an XML document was passed in, we wrap the exception
1273 // Typically this problem causes a MalformedURLException to be
1274 // thrown, but that is not particular specified that way. Of
1275 // interest, depending on the broken systemID, you could get a
1276 // FileNotFoundException which is also an IOException, which will
1277 // also be processed by this handler....
1278
1279 final int len = systemId.length();
1280 int i = 0;
1281 while (i < len && Verifier.isXMLWhitespace(systemId.charAt(i))) {
1282 i++;
1283 }
1284 if (i < len && '<' == systemId.charAt(i)) {
1285 // our systemID URI has a '<' - this is likely the problem.
1286 MalformedURLException mx = new MalformedURLException(
1287 "SAXBuilder.build(String) expects the String to be " +
1288 "a systemID, but in this instance it appears to be " +
1289 "actual XML data.");
1290 // include the original problem for accountability, and perhaps
1291 // a false positive.... though very unlikely
1292 mx.initCause(ioe);
1293 throw mx;
1294 }
1295 // it is likely not an XML document - re-throw the exception
1296 throw ioe;
1297 } finally {
1298 if (!reuseParser) {
1299 engine = null;
1300 }
1301 }
1302 }
1303
1304 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input;
55
56 import java.util.Iterator;
57
58 import javax.xml.namespace.QName;
59 import javax.xml.stream.XMLEventReader;
60 import javax.xml.stream.XMLStreamConstants;
61 import javax.xml.stream.XMLStreamException;
62 import javax.xml.stream.events.Characters;
63 import javax.xml.stream.events.StartElement;
64 import javax.xml.stream.events.XMLEvent;
65
66 import org.jdom.AttributeType;
67 import org.jdom.Comment;
68 import org.jdom.DefaultJDOMFactory;
69 import org.jdom.DocType;
70 import org.jdom.Document;
71 import org.jdom.Element;
72 import org.jdom.JDOMException;
73 import org.jdom.JDOMFactory;
74 import org.jdom.Namespace;
75 import org.jdom.ProcessingInstruction;
76 import org.jdom.input.stax.DTDParser;
77
78 /**
79 * Builds a JDOM Document from a StAX-based XMLEventReader.
80 * <p>
81 * XMLEventReaders are pre-configured and as a result JDOM is not able to
82 * alter whether the input is validated, or whether the Events have escaped
83 * entities or not. These (and other) characteristics are configurable by
84 * setting the correct features and properties on the XMLInputFactory when it
85 * is used to create the XMLStreamReader.
86 * <p>
87 * Useful configuration to set, or know about is:
88 * <ul>
89 * <li>StAX Events seldom differentiate between Text and CDATA content. You
90 * will likely want to configure your StAX factory (XMLInputFactory) with
91 * <code>http://java.sun.com/xml/stream/properties/report-cdata-event</code>
92 * for the default Java StAX implementation, or the equivalent property for your
93 * StAX engine.
94 * <li>The remaining XMLInputFactory settings are likely to work fine at their
95 * default values.
96 * <li>StAX is not likely to be your best option if you want a validating
97 * parser, at least not with the default (built-in Java implementation in Java6
98 * which does not support it). Consider a SAX parser.
99 * </ul>
100 * <p>
101 * From a JDOM perspective XMLStreamReaders are more efficient than
102 * XMLEventReaders. Where possible use an XMLStreamReader.
103 * <p>
104 * If you happen to be looking at the source code, pay careful attention to the
105 * imports so you know what type of instance is being processed, whether it is
106 * a StAX class, or a JDOM class, because there are name conflicts.
107 *
108 * @author Rolf Lear
109 *
110 */
111 public class StAXEventBuilder {
112
113
114 /**
115 * Create a Document from an XMLEventReader
116 * @param factory the {@link JDOMFactory} to use
117 * @param stream the XMLEventReader to read from
118 * @return the parsed Document
119 * @throws JDOMException if there is any issue
120 * (XMLStreamExceptions are wrapped).
121 */
122 private static final Document process(final JDOMFactory factory,
123 final XMLEventReader events) throws JDOMException {
124 try {
125
126 final Document document = factory.document(null);
127 Element current = null;
128
129 XMLEvent event = events.peek();
130
131 if (XMLStreamConstants.START_DOCUMENT != event.getEventType()) {
132 throw new JDOMException("JDOM requires that XMLStreamReaders " +
133 "are at their beginning when being processed.");
134 }
135
136
137
138 while (event.getEventType() != XMLStreamConstants.END_DOCUMENT) {
139 if (event.isStartDocument()) {
140 document.setBaseURI(event.getLocation().getSystemId());
141 document.setProperty("ENCODING_SCHEME",
142 ((javax.xml.stream.events.StartDocument)event).getCharacterEncodingScheme());
143 document.setProperty("STANDALONE", String.valueOf(
144 ((javax.xml.stream.events.StartDocument)event).isStandalone()));
145 // document.setProperty("ENCODING",
146 // ((StartDocument)event).getEncoding());
147 } else if (event instanceof javax.xml.stream.events.DTD) {
148 //List<?> list = (List<?>)reader.getProperty("javax.xml.stream.entities");
149 //System.out.println(list);
150 final DocType dtype = DTDParser.parse(((javax.xml.stream.events.DTD)event).getDocumentTypeDeclaration(), factory);
151 document.setDocType(dtype);
152 } else if (event.isStartElement()) {
153 final Element emt = processElement(factory, event.asStartElement());
154 if (current == null) {
155 document.setRootElement(emt);
156 final DocType dt = document.getDocType();
157 if (dt != null) {
158 dt.setElementName(emt.getName());
159 }
160 } else {
161 current.addContent(emt);
162 }
163 current = emt;
164 } else if (event.isCharacters() && current != null) {
165 // ignore any character-based content (should only be spaces)
166 // outside of the root element.
167 final Characters chars = event.asCharacters();
168 if (chars.isCData()) {
169 current.addContent(factory.cdata(
170 ((Characters)event).getData()));
171 } else {
172 current.addContent(factory.text(
173 ((Characters)event).getData()));
174 }
175 } else if (event instanceof javax.xml.stream.events.Comment) {
176 final Comment comment = factory.comment(
177 ((javax.xml.stream.events.Comment)event).getText());
178 if (current == null) {
179 document.addContent(comment);
180 } else {
181 current.addContent(comment);
182 }
183 } else if (event.isEntityReference()) {
184 current.addContent(factory.entityRef(
185 ((javax.xml.stream.events.EntityReference)event).getName()));
186 } else if (event.isProcessingInstruction()) {
187 final ProcessingInstruction pi = factory.processingInstruction(
188 ((javax.xml.stream.events.ProcessingInstruction)event).getTarget(),
189 ((javax.xml.stream.events.ProcessingInstruction)event).getData());
190 if (current == null) {
191 document.addContent(pi);
192 } else {
193 current.addContent(pi);
194 }
195 } else if (event.isEndElement()) {
196 current = current.getParentElement();
197 }
198 if (events.hasNext()) {
199 event = events.nextEvent();
200 } else {
201 break;
202 }
203 }
204 return document;
205 } catch (final XMLStreamException xse) {
206 throw new JDOMException("Unable to process XMLStream. See Cause.", xse);
207 }
208 }
209
210 private static final Element processElement(final JDOMFactory factory,
211 final StartElement event) {
212 final QName qname = event.getName();
213
214 final Element element = factory.element(qname.getLocalPart(),
215 Namespace.getNamespace(qname.getPrefix(), qname.getNamespaceURI()));
216
217 // Handle attributes
218 for (final Iterator<?> it = event.getAttributes();
219 it.hasNext(); ) {
220
221 final javax.xml.stream.events.Attribute att =
222 (javax.xml.stream.events.Attribute)it.next();
223
224 final QName aqname = att.getName();
225
226 final Namespace attNs = Namespace.getNamespace(aqname.getPrefix(),
227 aqname.getNamespaceURI());
228
229 factory.setAttribute(element, factory.attribute(
230 aqname.getLocalPart(), att.getValue(),
231 AttributeType.getAttributeType(att.getDTDType()), attNs));
232 }
233
234 for (final Iterator<?> it = event.getNamespaces(); it.hasNext();) {
235 final javax.xml.stream.events.Namespace ns =
236 (javax.xml.stream.events.Namespace)it.next();
237
238 element.addNamespaceDeclaration(Namespace.getNamespace(
239 ns.getPrefix(), ns.getNamespaceURI()));
240 }
241
242 return element;
243 }
244
245
246
247 /** The factory to use for parsing */
248 private JDOMFactory factory = new DefaultJDOMFactory();
249
250 /**
251 * Returns the current {@link org.jdom.JDOMFactory} in use.
252 * @return the factory in use
253 */
254 public JDOMFactory getFactory() {
255 return factory;
256 }
257
258 /**
259 * This sets a custom JDOMFactory for the builder. Use this to build
260 * the tree with your own subclasses of the JDOM classes.
261 *
262 * @param factory <code>JDOMFactory</code> to use
263 */
264 public void setFactory(JDOMFactory factory) {
265 this.factory = factory;
266 }
267
268 /**
269 * This builds a document from the supplied
270 * XMLEventReader.
271 * <p>
272 * The JDOMContent will be built by the current JDOMFactory.
273 *
274 * @param events <code>XMLEventReader</code> to read from
275 * @return <code>Document</code> resultant Document object
276 * @throws JDOMException when errors occur in parsing
277 */
278 public Document build(XMLEventReader events) throws JDOMException {
279 return process(factory, events);
280 }
281
282 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input;
55
56 import static javax.xml.stream.XMLStreamConstants.*;
57
58 import java.util.ArrayList;
59 import java.util.List;
60
61 import javax.xml.namespace.QName;
62 import javax.xml.stream.XMLStreamException;
63 import javax.xml.stream.XMLStreamReader;
64
65 import org.jdom.AttributeType;
66 import org.jdom.Content;
67 import org.jdom.DefaultJDOMFactory;
68 import org.jdom.Document;
69 import org.jdom.Element;
70 import org.jdom.JDOMException;
71 import org.jdom.JDOMFactory;
72 import org.jdom.Namespace;
73 import org.jdom.Verifier;
74 import org.jdom.input.stax.DTDParser;
75 import org.jdom.input.stax.StAXFilter;
76
77 /**
78 * Builds a JDOM Document from a StAX-based XMLStreamReader.
79 * <p>
80 * XMLStreamReaders are pre-configured and as a result JDOM is not able to
81 * alter whether the input is validated, or whether the Stream has escaped
82 * entities or not. These (and other) characteristics are configurable by
83 * setting the correct features and properties on the XMLInputFactory when it
84 * is used to create the XMLStreamReader.
85 * <p>
86 * Useful configuration to set, or know about is:
87 * <ul>
88 * <li>StAX streams seldom differentiate between Text and CDATA content. You
89 * will likely want to configure your StAX factory (XMLInputFactory) with
90 * <code>http://java.sun.com/xml/stream/properties/report-cdata-event</code>
91 * for the default Java StAX implementation, or the equivalent property for your
92 * StAX engine.
93 * <li>The remaining XMLInputFactory settings are likely to work fine at their
94 * default values.
95 * <li>StAX is not likely to be your best option if you want a validating
96 * parser, at least not with the default (built-in Java implementation in Java6
97 * which does not support it). Consider a SAX parser.
98 * </ul>
99 * <p>
100 * From a JDOM perspective XMLStreamReaders are more efficient than
101 * XMLEventReaders. Where possible use an XMLStreamReader.
102 * <p>
103 * If you happen to be looking at the source code, pay careful attention to the
104 * imports so you know what type of instance is being processed, whether it is
105 * a StAX class, or a JDOM class, because there are name conflicts.
106 *
107 * @author Rolf Lear
108 *
109 */
110 public class StAXStreamBuilder {
111
112 /**
113 * Create a Document from an XMLStreamReader
114 * @param factory The {@link JDOMFactory} to use
115 * @param stream The XMLStreamReader to read from
116 * @return the parsed Document
117 * @throws JDOMException if there is any issue
118 * (XMLStreamExceptions are wrapped).
119 */
120 private static final Document process(final JDOMFactory factory,
121 final XMLStreamReader stream) throws JDOMException {
122 try {
123
124 int state = stream.getEventType();
125
126 if (START_DOCUMENT != state) {
127 throw new JDOMException("JDOM requires that XMLStreamReaders " +
128 "are at their beginning when being processed.");
129 }
130
131 final Document document = factory.document(null);
132
133 while (state != END_DOCUMENT) {
134 switch (state) {
135
136 case START_DOCUMENT:
137 // for the <?xml version="..." standalone=".."?>
138 document.setBaseURI(stream.getLocation().getSystemId());
139 document.setProperty("ENCODING_SCHEME",
140 stream.getCharacterEncodingScheme());
141 document.setProperty("STANDALONE",
142 String.valueOf(stream.isStandalone()));
143 document.setProperty("ENCODING",
144 stream.getEncoding());
145 break;
146
147 case DTD:
148 document.setDocType(DTDParser.parse(
149 stream.getText(), factory));
150 break;
151
152 case START_ELEMENT:
153 document.setRootElement(processElementFragment(factory, stream));
154 break;
155
156 case END_ELEMENT:
157 throw new JDOMException("Unexpected XMLStream event at Document level: END_ELEMENT");
158 case ENTITY_REFERENCE:
159 throw new JDOMException("Unexpected XMLStream event at Document level: ENTITY_REFERENCE");
160 case CDATA:
161 throw new JDOMException("Unexpected XMLStream event at Document level: CDATA");
162 case SPACE:
163 // Can happen when XMLInputFactory2.P_REPORT_PROLOG_WHITESPACE is set to true
164 document.addContent(factory.text(stream.getText()));
165 break;
166 case CHARACTERS:
167 final String badtxt = stream.getText();
168 if (!Verifier.isAllXMLWhitespace(badtxt)) {
169 throw new JDOMException("Unexpected XMLStream event at Document level: CHARACTERS (" + badtxt + ")");
170 }
171 // otherwise ignore the chars.
172 break;
173
174 case COMMENT:
175 document.addContent(
176 factory.comment(stream.getText()));
177 break;
178
179 case PROCESSING_INSTRUCTION:
180 document.addContent(factory.processingInstruction(
181 stream.getPITarget(), stream.getPIData()));
182 break;
183
184 default:
185 throw new JDOMException("Unexpected XMLStream event " + state);
186
187 }
188 if (stream.hasNext()) {
189 state = stream.next();
190 } else {
191 throw new JDOMException("Unexpected end-of-XMLStreamReader");
192 }
193 }
194 return document;
195 } catch (final XMLStreamException xse) {
196 throw new JDOMException("Unable to process XMLStream. See Cause.", xse);
197 }
198 }
199
200 private List<Content> processFragments(JDOMFactory factory, XMLStreamReader stream, StAXFilter filter) throws JDOMException {
201
202 int state = stream.getEventType();
203
204 if (START_DOCUMENT != state) {
205 throw new JDOMException("JDOM requires that XMLStreamReaders " +
206 "are at their beginning when being processed.");
207 }
208 List<Content> ret = new ArrayList<Content>();
209
210 int depth = 0;
211 String text = null;
212
213 try {
214 while (stream.hasNext() && (state = stream.next()) != END_DOCUMENT) {
215 switch (state) {
216 case START_DOCUMENT:
217 throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state START_DOCUMENT" );
218 case END_DOCUMENT:
219 throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state END_DOCUMENT" );
220 case END_ELEMENT:
221 throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state END_ELEMENT" );
222
223 case START_ELEMENT:
224 final QName qn = stream.getName();
225 if (filter.includeElement(depth, qn.getLocalPart(),
226 Namespace.getNamespace(qn.getPrefix(), qn.getNamespaceURI()))) {
227 ret.add(processPrunableElement(factory, stream, depth, filter));
228 } else {
229 final int back = depth;
230 depth++;
231
232 while (depth > back && stream.hasNext()) {
233 state = stream.next();
234 if (state == START_ELEMENT) {
235 depth++;
236 } else if (state == END_ELEMENT) {
237 depth--;
238 }
239 }
240 }
241 break;
242
243 case DTD:
244 if (filter.includeDocType()) {
245 ret.add(DTDParser.parse(stream.getText(), factory));
246 }
247 break;
248
249 case CDATA:
250 if ((text = filter.includeCDATA(depth, stream.getText())) != null) {
251 ret.add(factory.cdata(text));
252 }
253 break;
254
255 case SPACE:
256 case CHARACTERS:
257 if ((text = filter.includeText(depth, stream.getText())) != null) {
258 ret.add(factory.text(text));
259 }
260 break;
261
262 case COMMENT:
263 if ((text = filter.includeComment(depth, stream.getText())) != null) {
264 ret.add(factory.comment(text));
265 }
266 break;
267
268 case ENTITY_REFERENCE:
269 if (filter.includeEntityRef(depth, stream.getLocalName())) {
270 ret.add(factory.entityRef(stream.getLocalName()));
271 }
272 break;
273
274 case PROCESSING_INSTRUCTION:
275 if (filter.includeProcessingInstruction(depth, stream.getPITarget())) {
276 ret.add(factory.processingInstruction(
277 stream.getPITarget(), stream.getPIData()));
278 }
279 break;
280
281 default:
282 throw new JDOMException("Unexpected XMLStream event " + stream.getEventType());
283 }
284 }
285 } catch (XMLStreamException e) {
286 throw new JDOMException("Unable to process fragments from XMLStreamReader.", e);
287 }
288
289 return ret;
290 }
291
292
293 private static final Element processPrunableElement(final JDOMFactory factory,
294 final XMLStreamReader reader, final int topdepth, StAXFilter filter)
295 throws XMLStreamException, JDOMException {
296
297 if (START_ELEMENT != reader.getEventType()) {
298 throw new JDOMException("JDOM requires that the XMLStreamReader " +
299 "is at the START_ELEMENT state when retrieving an " +
300 "Element Fragment.");
301 }
302
303 final Element fragment = processElement(factory, reader);
304 Element current = fragment;
305 int depth = topdepth + 1;
306 String text = null;
307 while (depth > topdepth && reader.hasNext()) {
308 switch(reader.next()) {
309 case START_ELEMENT:
310 QName qn = reader.getName();
311 if (!filter.pruneElement(depth, qn.getLocalPart(),
312 Namespace.getNamespace(
313 qn.getPrefix(), qn.getNamespaceURI()))) {
314 Element tmp = processElement(factory, reader);
315 current.addContent(tmp);
316 current = tmp;
317 depth++;
318 } else {
319 final int edepth = depth;
320 depth++;
321 int state = 0;
322 while (depth > edepth && reader.hasNext() &&
323 (state = reader.next()) != END_DOCUMENT) {
324 if (state == START_ELEMENT) {
325 depth++;
326 } else if (state == END_ELEMENT) {
327 depth--;
328 }
329 }
330 }
331 break;
332 case END_ELEMENT:
333 current = current.getParentElement();
334 depth--;
335 break;
336 case CDATA:
337 if ((text = filter.pruneCDATA(depth, reader.getText())) != null) {
338 current.addContent(factory.cdata(text));
339 }
340 break;
341
342 case SPACE:
343 case CHARACTERS:
344 if ((text = filter.pruneText(depth, reader.getText())) != null) {
345 current.addContent(factory.text(text));
346 }
347 break;
348
349 case COMMENT:
350 if ((text = filter.pruneComment(depth, reader.getText())) != null) {
351 current.addContent(factory.comment(text));
352 }
353 break;
354
355 case ENTITY_REFERENCE:
356 if (!filter.pruneEntityRef(depth, reader.getLocalName())) {
357 current.addContent(factory.entityRef(reader.getLocalName()));
358 }
359 break;
360
361 case PROCESSING_INSTRUCTION:
362 if (!filter.pruneProcessingInstruction(depth, reader.getPITarget())) {
363 current.addContent(factory.processingInstruction(
364 reader.getPITarget(), reader.getPIData()));
365 }
366 break;
367
368 default:
369 throw new JDOMException("Unexpected XMLStream event " + reader.getEventType());
370 }
371
372 }
373
374 return fragment;
375 }
376
377 /**
378 * Create a Content from an XMLStreamReader
379 * The stream is advanced to the event after the current event (or to the
380 * event after the matching END_ELEMENT for an Element fragment).
381 * @param factory The {@link JDOMFactory} to use
382 * @param stream The XMLStreamReader to read from
383 * @return the parsed Document
384 * @throws JDOMException if there is any issue
385 * (XMLStreamExceptions are wrapped).
386 */
387 private static final Content processFragment(final JDOMFactory factory,
388 final XMLStreamReader stream) throws JDOMException {
389 try {
390
391 switch (stream.getEventType()) {
392
393 case START_DOCUMENT:
394 throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state START_DOCUMENT" );
395 case END_DOCUMENT:
396 throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state END_DOCUMENT" );
397 case END_ELEMENT:
398 throw new JDOMException("Illegal state for XMLStreamReader. Cannot get XML Fragment for state END_ELEMENT" );
399
400 case START_ELEMENT:
401 Element emt = processElementFragment(factory, stream);
402 stream.next();
403 return emt;
404
405 case DTD:
406 Content dt = DTDParser.parse(stream.getText(), factory);
407 stream.next();
408 return dt;
409
410 case CDATA:
411 Content cd = factory.cdata(stream.getText());
412 stream.next();
413 return cd;
414
415 case SPACE:
416 case CHARACTERS:
417 Content txt = factory.text(stream.getText());
418 stream.next();
419 return txt;
420
421 case COMMENT:
422 Content comment = factory.comment(stream.getText());
423 stream.next();
424 return comment;
425
426 case ENTITY_REFERENCE:
427 Content er = factory.entityRef(stream.getLocalName());
428 stream.next();
429 return er;
430
431 case PROCESSING_INSTRUCTION:
432 Content pi = factory.processingInstruction(
433 stream.getPITarget(), stream.getPIData());
434 stream.next();
435 return pi;
436
437 default:
438 throw new JDOMException("Unexpected XMLStream event " + stream.getEventType());
439
440 }
441 } catch (final XMLStreamException xse) {
442 throw new JDOMException("Unable to process XMLStream. See Cause.", xse);
443 }
444 }
445
446 private static final Element processElementFragment(final JDOMFactory factory,
447 final XMLStreamReader reader) throws XMLStreamException, JDOMException {
448
449 if (START_ELEMENT != reader.getEventType()) {
450 throw new JDOMException("JDOM requires that the XMLStreamReader " +
451 "is at the START_ELEMENT state when retrieving an " +
452 "Element Fragment.");
453 }
454
455 final Element fragment = processElement(factory, reader);
456 Element current = fragment;
457 int depth = 1;
458 while (depth > 0 && reader.hasNext()) {
459 switch(reader.next()) {
460 case START_ELEMENT:
461 Element tmp = processElement(factory, reader);
462 current.addContent(tmp);
463 current = tmp;
464 depth++;
465 break;
466 case END_ELEMENT:
467 current = current.getParentElement();
468 depth--;
469 break;
470 case CDATA:
471 current.addContent(factory.cdata(reader.getText()));
472 break;
473
474 case SPACE:
475 case CHARACTERS:
476 current.addContent(factory.text(reader.getText()));
477 break;
478
479 case COMMENT:
480 current.addContent(factory.comment(reader.getText()));
481 break;
482
483 case ENTITY_REFERENCE:
484 current.addContent(factory.entityRef(reader.getLocalName()));
485 break;
486
487 case PROCESSING_INSTRUCTION:
488 current.addContent(factory.processingInstruction(
489 reader.getPITarget(), reader.getPIData()));
490 break;
491
492 default:
493 throw new JDOMException("Unexpected XMLStream event " + reader.getEventType());
494 }
495
496 }
497
498 return fragment;
499 }
500
501 private static final Element processElement(final JDOMFactory factory,
502 final XMLStreamReader reader) {
503
504 final Element element = factory.element(reader.getLocalName(),
505 Namespace.getNamespace(reader.getPrefix(),
506 reader.getNamespaceURI()));
507
508 // Handle attributes
509 for (int i=0, len=reader.getAttributeCount(); i<len; i++) {
510 factory.setAttribute(element, factory.attribute(
511 reader.getAttributeLocalName(i),
512 reader.getAttributeValue(i),
513 AttributeType.getAttributeType(reader.getAttributeType(i)),
514 Namespace.getNamespace(reader.getAttributePrefix(i),
515 reader.getAttributeNamespace(i))));
516 }
517
518 // Handle Namespaces
519 for (int i = 0, len = reader.getNamespaceCount(); i < len; i++) {
520 element.addNamespaceDeclaration(Namespace.getNamespace(
521 reader.getNamespacePrefix(i), reader.getNamespaceURI(i)));
522 }
523
524 return element;
525 }
526
527
528 /** The factory to use for parsing */
529 private JDOMFactory builderfactory = new DefaultJDOMFactory();
530
531 /**
532 * Returns the current {@link org.jdom.JDOMFactory} in use.
533 * @return the factory in use
534 */
535 public JDOMFactory getFactory() {
536 return builderfactory;
537 }
538
539 /**
540 * This sets a custom JDOMFactory for the builder. Use this to build
541 * the tree with your own subclasses of the JDOM classes.
542 *
543 * @param factory <code>JDOMFactory</code> to use
544 */
545 public void setFactory(JDOMFactory factory) {
546 this.builderfactory = factory;
547 }
548
549 /**
550 * This builds a document from the supplied
551 * XMLStreamReader.
552 * <p>
553 * The JDOMContent will be built by the current JDOMFactory.
554 *
555 * @param reader <code>XMLStreamReader</code> to read from
556 * @return <code>Document</code> resultant Document object
557 * @throws JDOMException when errors occur in parsing
558 */
559 public Document build(XMLStreamReader reader) throws JDOMException {
560 return process(builderfactory, reader);
561 }
562
563 /**
564 * Read the entire XMLStreamReader and from it build a list of Content that
565 * conforms to the rules in the supplied StAXFilter.
566 * @param reader The XMLStreamReader to parse
567 * @param filter The Filter to use for the Content
568 * @return a List of Content that were identified by the supplied filter
569 * @throws JDOMException if there was a parsing problem.
570 */
571 public List<Content> buildFragments(XMLStreamReader reader, StAXFilter filter) throws JDOMException {
572 return processFragments(builderfactory, reader, filter);
573 }
574
575
576 /**
577 * Read the current XML Fragment from the XMLStreamReader.
578 * The XMLStreamReader must be at some 'content' state, it cannot be
579 * at START_DOCUMENT, for example.
580 * @param reader The XMLStreamReader to read the next fragment from
581 * @return The JDOM fragment at the current position in the reader
582 * @throws JDOMException if there is an issue with the state of the
583 * XMLStreamReader or some other issue with the processing.
584 */
585 public Content fragment(XMLStreamReader reader) throws JDOMException {
586 return processFragment(builderfactory, reader);
587 }
588
589 }
0 <body>
1
2 Classes to build JDOM documents from various sources.
3 <p>
4 The most commonly used builder is SAXBuilder which constructs a JDOM document
5 using a SAX parser and can pull content from files, streams, sockets, readers,
6 and so on. It can use any underlying SAX parser to handle the parsing chores.
7 <p>
8 DOMBuilder lets you build JDOM content from existing <code>org.w3c.dom.*</code>
9 instances.
10 <p>
11 The StAXStreamBuilder and StAXEventBuilder classes allow you to build JDOM
12 content from StAX-based XMLStreamReader and XMLEventReader instances.
13
14 </body>
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import javax.xml.parsers.ParserConfigurationException;
57 import javax.xml.parsers.SAXParserFactory;
58 import javax.xml.validation.Schema;
59
60 import org.xml.sax.SAXException;
61 import org.xml.sax.XMLReader;
62
63 import org.jdom.JDOMException;
64
65 /**
66 * This {@link AbstractReaderSchemaFactory} class returns XMLReaders configured to
67 * validate against the supplied Schema instance. The Schema could be an XSD
68 * schema or some other schema supported by SAX (e.g. RelaxNG). It takes a pre-declared
69 * <p>
70 * If you want to validate an XML document against the XSD references embedded
71 * in the XML itself (xsdSchemaLocation) then you do not want to use this class
72 * but rather use an alternate means like
73 * {@link XMLReaders#XSDVALIDATING}.
74 * <p>
75 * See the {@link org.jdom.input.sax package documentation} for the best
76 * alternatives.
77 *
78 * @see org.jdom.input.sax
79 * @author Rolf Lear
80 */
81 public abstract class AbstractReaderSchemaFactory implements XMLReaderJDOMFactory {
82
83 private final SAXParserFactory saxfac;
84
85 /**
86 * XMLReader instances from this class will be configured to validate using
87 * the supplied Schema instance.
88 *
89 * @param fac
90 * The SAXParserFactory to use for creating XMLReader instances.
91 * @param schema
92 * The Schema to use for validation.
93 */
94 public AbstractReaderSchemaFactory(final SAXParserFactory fac, final Schema schema) {
95 if (schema == null) {
96 throw new NullPointerException("Cannot create a " +
97 "SchemaXMLReaderFactory with a null schema");
98 }
99 saxfac = fac;
100 if (saxfac != null) {
101 saxfac.setNamespaceAware(true);
102 saxfac.setValidating(false);
103 saxfac.setSchema(schema);
104 }
105 }
106
107 @Override
108 public XMLReader createXMLReader() throws JDOMException {
109 if (saxfac == null) {
110 throw new JDOMException("It was not possible to configure a " +
111 "suitable XMLReader to support " + this);
112 }
113
114 try {
115 return saxfac.newSAXParser().getXMLReader();
116 } catch (SAXException e) {
117 throw new JDOMException(
118 "Could not create a new Schema-Validating XMLReader.", e);
119 } catch (ParserConfigurationException e) {
120 throw new JDOMException(
121 "Could not create a new Schema-Validating XMLReader.", e);
122 }
123 }
124
125 @Override
126 public boolean isValidating() {
127 return true;
128 }
129
130 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import java.io.File;
57 import java.io.IOException;
58 import java.io.InputStream;
59 import java.net.URL;
60 import java.util.Arrays;
61
62 import javax.xml.parsers.SAXParserFactory;
63 import javax.xml.transform.Source;
64 import javax.xml.transform.stream.StreamSource;
65 import javax.xml.validation.Schema;
66 import javax.xml.validation.SchemaFactory;
67
68 import org.xml.sax.SAXException;
69
70 import org.jdom.JDOMException;
71
72 /**
73 * This AbstractReaderJDOMFactory class returns XMLReaders configured to validate
74 * against the supplied XML Schema (XSD) instance.
75 * <p>
76 * This class has var-arg constructors, accepting potentially many XSD sources.
77 * It is just as simple though to have a single source:
78 *
79 * <pre>
80 * File xsdfile = new File(&quot;schema.xsd&quot;);
81 * XMLReaderJDOMFactory schemafac = new XMLReaderXSDFactory(xsdfile);
82 * SAXBuilder builder = new SAXBuilder(schemafac);
83 * File xmlfile = new File(&quot;data.xml&quot;);
84 * Document validdoc = builder.build(xmlfile);
85 * </pre>
86 *
87 * @see org.jdom.input.sax
88 * @author Rolf Lear
89 */
90 public class AbstractReaderXSDFactory extends AbstractReaderSchemaFactory {
91
92 /**
93 * Simple interface makes it easier to pass logic around in static methods.
94 * @author Rolf Lear
95 *
96 */
97 protected interface SchemaFactoryProvider {
98 /**
99 * Return a SchemaFactory
100 * @return a SchemaFactory
101 */
102 SchemaFactory getSchemaFactory();
103 }
104
105 /**
106 * Compile an array of String URLs in to Sources which are then compiled in
107 * to a single Schema
108 *
109 * @param systemID
110 * The source URLs to compile
111 * @return the resulting Schema
112 * @throws JDOMException
113 * if there is a problem with the Sources
114 */
115 private static final Schema getSchemaFromString(final SchemaFactoryProvider sfp,
116 String... systemID) throws JDOMException {
117 if (systemID == null) {
118 throw new NullPointerException("Cannot specify a null input array");
119 }
120 if (systemID.length == 0) {
121 throw new IllegalArgumentException("You need at least one " +
122 "XSD source for an XML Schema validator");
123 }
124 Source[] urls = new Source[systemID.length];
125 for (int i = 0; i < systemID.length; i++) {
126 if (systemID[i] == null) {
127 throw new NullPointerException("Cannot specify a null SystemID");
128 }
129 urls[i] = new StreamSource(systemID[i]);
130 }
131 return getSchemaFromSource(sfp, urls);
132 }
133
134 /**
135 * Compile an array of Files in to URLs which are then compiled in to a
136 * single Schema
137 *
138 * @param systemID
139 * The source Files to compile
140 * @return the resulting Schema
141 * @throws JDOMException
142 * if there is a problem with the Sources
143 */
144 private static final Schema getSchemaFromFile(final SchemaFactoryProvider sfp,
145 File... systemID) throws JDOMException {
146 if (systemID == null) {
147 throw new NullPointerException("Cannot specify a null input array");
148 }
149 if (systemID.length == 0) {
150 throw new IllegalArgumentException("You need at least one " +
151 "XSD source for an XML Schema validator");
152 }
153 Source[] sources = new Source[systemID.length];
154 for (int i = 0; i < systemID.length; i++) {
155 if (systemID[i] == null) {
156 throw new NullPointerException("Cannot specify a null SystemID");
157 }
158 sources[i] = new StreamSource(systemID[i]);
159 }
160 return getSchemaFromSource(sfp, sources);
161 }
162
163 /**
164 * Compile an array of URLs in to Sources which are then compiled in to a
165 * single Schema
166 *
167 * @param systemID
168 * The source URLs to compile
169 * @return the resulting Schema
170 * @throws JDOMException
171 * if there is a problem with the Sources
172 */
173 private static final Schema getSchemaFromURL(final SchemaFactoryProvider sfp,
174 URL... systemID) throws JDOMException {
175 if (systemID == null) {
176 throw new NullPointerException("Cannot specify a null input array");
177 }
178 if (systemID.length == 0) {
179 throw new IllegalArgumentException("You need at least one " +
180 "XSD source for an XML Schema validator");
181 }
182 InputStream[] streams = new InputStream[systemID.length];
183 try {
184 Source[] sources = new Source[systemID.length];
185 for (int i = 0; i < systemID.length; i++) {
186 if (systemID[i] == null) {
187 throw new NullPointerException("Cannot specify a null SystemID");
188 }
189 InputStream is = null;
190 try {
191 is = systemID[i].openStream();
192 } catch (IOException e) {
193 throw new JDOMException("Unable to read Schema URL " +
194 systemID[i].toString(), e);
195 }
196 streams[i] = is;
197 sources[i] = new StreamSource(is, systemID[i].toString());
198 }
199 return getSchemaFromSource(sfp, sources);
200 } finally {
201 for (InputStream is : streams) {
202 if (is != null) {
203 try {
204 is.close();
205 } catch (IOException ioe) {
206 // swallow it.
207 }
208 }
209 }
210 }
211 }
212
213 /**
214 * Compile an array of Sources in to a single Schema
215 *
216 * @param sources
217 * The sources to compile
218 * @return the resulting Schema
219 * @throws JDOMException
220 * if there is a problem with the Sources
221 */
222 private static final Schema getSchemaFromSource(final SchemaFactoryProvider sfp,
223 Source... sources) throws JDOMException {
224 if (sources == null) {
225 throw new NullPointerException("Cannot specify a null input array");
226 }
227 if (sources.length == 0) {
228 throw new IllegalArgumentException("You need at least one " +
229 "XSD Source for an XML Schema validator");
230 }
231 try {
232 SchemaFactory sfac = sfp.getSchemaFactory();
233 if (sfac == null) {
234 throw new JDOMException("Unable to create XSDSchema validator.");
235 }
236 return sfac.newSchema(sources);
237 } catch (SAXException e) {
238 String msg = Arrays.toString(sources);
239 throw new JDOMException("Unable to create a Schema for Sources " +
240 msg, e);
241 }
242 }
243
244 /**
245 * Create an XML Schema validating XMLReader factory using one or more XSD
246 * sources from SystemID references.
247 *
248 * @param fac
249 * The SAXParserFactory used to create the XMLReader instances.
250 * @param sfp
251 * The SchemaFactoryProvider instance that gives us Schema Factories
252 * @param systemid
253 * The var-arg array of at least one SystemID reference (URL) to
254 * locate the XSD's used to validate
255 * @throws JDOMException
256 * If the Schemas could not be loaded from the SystemIDs This will
257 * wrap a SAXException that contains the actual fault.
258 */
259 public AbstractReaderXSDFactory(final SAXParserFactory fac,
260 final SchemaFactoryProvider sfp, String... systemid) throws JDOMException {
261 super(fac, getSchemaFromString(sfp, systemid));
262 }
263
264 /**
265 * Create an XML Schema validating XMLReader factory using one or more XSD
266 * sources from URL references.
267 *
268 * @param fac
269 * The SAXParserFactory used to create the XMLReader instances.
270 * @param sfp
271 * The SchemaFactoryProvider instance that gives us Schema Factories
272 * @param systemid
273 * The var-arg array of at least one SystemID reference (URL) to
274 * locate the XSD's used to validate
275 * @throws JDOMException
276 * If the Schemas could not be loaded from the SystemIDs This will
277 * wrap a SAXException that contains the actual fault.
278 */
279 public AbstractReaderXSDFactory(final SAXParserFactory fac,
280 final SchemaFactoryProvider sfp, URL... systemid) throws JDOMException {
281 super(fac, getSchemaFromURL(sfp, systemid));
282 }
283
284 /**
285 * Create an XML Schema validating XMLReader factory using one or more XSD
286 * sources from File references.
287 *
288 * @param fac
289 * The SAXParserFactory used to create the XMLReader instances.
290 * @param sfp
291 * The SchemaFactoryProvider instance that gives us Schema Factories
292 * @param systemid
293 * The var-arg array of at least one SystemID reference (File) to
294 * locate the XSD's used to validate
295 * @throws JDOMException
296 * If the Schemas could not be loaded from the SystemIDs This will
297 * wrap a SAXException that contains the actual fault.
298 */
299 public AbstractReaderXSDFactory(final SAXParserFactory fac,
300 final SchemaFactoryProvider sfp, File... systemid) throws JDOMException {
301 super(fac, getSchemaFromFile(sfp, systemid));
302 }
303
304 /**
305 * Create an XML Schema validating XMLReader factory using one or more XSD
306 * sources from Transform Source references.
307 *
308 * @param fac
309 * The SAXParserFactory used to create the XMLReader instances.
310 * @param sfp
311 * The SchemaFactoryProvider instance that gives us Schema Factories
312 * @param sources
313 * The var-arg array of at least one transform Source reference to
314 * locate the XSD's used to validate
315 * @throws JDOMException
316 * If the Schemas could not be loaded from the Sources This will
317 * wrap a SAXException that contains the actual fault.
318 */
319 public AbstractReaderXSDFactory(final SAXParserFactory fac,
320 final SchemaFactoryProvider sfp, Source... sources) throws JDOMException {
321 super(fac, getSchemaFromSource(sfp, sources));
322 }
323
324 }
0 /*--
1
2 Copyright (C) 2000-2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import org.xml.sax.*;
57
58 /**
59 * The standard JDOM error handler implementation.
60 *
61 * @author Jason Hunter
62 */
63
64 public class BuilderErrorHandler implements ErrorHandler {
65
66 /**
67 * This method is called when a warning has occurred; this indicates that
68 * while no XML rules were broken, something appears to be incorrect or
69 * missing. The implementation of this method here is a "no op".
70 *
71 * @param exception
72 * <code>SAXParseException</code> that occurred.
73 * @throws SAXException
74 * when things go wrong
75 */
76 @Override
77 public void warning(SAXParseException exception) throws SAXException {
78 // nothing
79 }
80
81 /**
82 * This method is called in response to an error that has occurred; this
83 * indicates that a rule was broken, typically in validation, but that
84 * parsing could reasonably continue. The implementation of this method here
85 * is to rethrow the exception.
86 *
87 * @param exception
88 * <code>SAXParseException</code> that occurred.
89 * @throws SAXException
90 * when things go wrong
91 */
92 @Override
93 public void error(SAXParseException exception) throws SAXException {
94 throw exception;
95 }
96
97 /**
98 * This method is called in response to a fatal error; this indicates that a
99 * rule has been broken that makes continued parsing either impossible or an
100 * almost certain waste of time. The implementation of this method here is
101 * to rethrow the exception.
102 *
103 * @param exception
104 * <code>SAXParseException</code> that occurred.
105 * @throws SAXException
106 * when things go wrong
107 */
108 @Override
109 public void fatalError(SAXParseException exception) throws SAXException {
110 throw exception;
111 }
112 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import org.jdom.JDOMFactory;
57
58 /**
59 * This SAXHandlerFactory instance provides default-configured SAXHandler
60 * instances for all non-custom situations.
61 *
62 * @author Rolf Lear
63 */
64 public final class DefaultSAXHandlerFactory
65 implements SAXHandlerFactory {
66 /**
67 * For performance reasons it helps to use 'final' instances of classes.
68 * This makes the SAXHandler class a 'final' class for all normal
69 * SAXBuilders. It adds no other functionality.
70 *
71 * @author Rolf Lear
72 */
73 private static final class DefaultSAXHandler extends SAXHandler {
74 public DefaultSAXHandler(final JDOMFactory factory) {
75 super(factory);
76 }
77 }
78
79 @Override
80 public SAXHandler createSAXHandler(final JDOMFactory factory) {
81 return new DefaultSAXHandler(factory);
82 }
83 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import java.io.File;
57 import java.io.IOException;
58 import java.io.InputStream;
59 import java.io.Reader;
60 import java.net.MalformedURLException;
61 import java.net.URL;
62
63 import org.xml.sax.DTDHandler;
64 import org.xml.sax.EntityResolver;
65 import org.xml.sax.ErrorHandler;
66 import org.xml.sax.InputSource;
67 import org.xml.sax.SAXException;
68 import org.xml.sax.SAXParseException;
69 import org.xml.sax.XMLReader;
70
71 import org.jdom.Document;
72 import org.jdom.JDOMException;
73 import org.jdom.JDOMFactory;
74 import org.jdom.input.JDOMParseException;
75
76 /**
77 * Builds a JDOM document from files, streams, readers, URLs, or a SAX
78 * {@link org.xml.sax.InputSource} instance using a SAX parser. This Engine is
79 * built by the SAXBuilder based on the state of the SAXBuilder when the engine
80 * was produced. It is not possible to reconfigure the engine once built, but it
81 * can be reused many times (though not concurrently). This makes it the fastest
82 * way to process many multitudes of XML documents (if those documents are all
83 * parsed the same way). If you want to process in multiple threads you can
84 * safely have one SAXBuilderEngine in each thread on the condition that:
85 * <ol>
86 * <li>The JDOMFactory is thread-safe (the JDOM-supplied JDOMFactories are)
87 * <li>There is no XMLFilter given to the SAXBuilder, or, if there is, then it
88 * is thread-safe.
89 * <li>If you have a custom {@link XMLReaderJDOMFactory} that it supplies a new
90 * instance of an XMLReader on each call (the JDOM-supplied ones all do).
91 * <li>If you have a custom {@link SAXHandlerFactory} that it supplies a new
92 * instance of a SAXHanfler on each call (the JDOM-supplied one does)
93 * </ol>
94 *
95 * @see org.jdom.input.sax
96 * @author Rolf Lear
97 */
98 public class SAXBuilderEngine implements SAXEngine {
99
100 /** The SAX XMLReader. */
101 private final XMLReader saxParser;
102
103 /** The SAXHandler */
104 private final SAXHandler saxHandler;
105
106 /** indicates whether this is a validating parser */
107 private final boolean validating;
108
109 /**
110 * Creates a new SAXBuilderEngine.
111 *
112 * @param reader
113 * The XMLReader this Engine parses with
114 * @param handler
115 * The SAXHandler that processes the SAX Events.
116 * @param validating
117 * True if this is a validating system.
118 */
119 public SAXBuilderEngine(final XMLReader reader, final SAXHandler handler,
120 final boolean validating) {
121 saxParser = reader;
122 saxHandler = handler;
123 this.validating = validating;
124 }
125
126 /*
127 * (non-Javadoc)
128 *
129 * @see org.jdom.input.sax.SAXEngine#getJDOMFactory()
130 */
131 @Override
132 public JDOMFactory getJDOMFactory() {
133 return saxHandler.getFactory();
134 }
135
136 /*
137 * (non-Javadoc)
138 *
139 * @see org.jdom.input.sax.SAXEngine#isValidating()
140 */
141 @Override
142 public boolean isValidating() {
143 return validating;
144 }
145
146 /*
147 * (non-Javadoc)
148 *
149 * @see org.jdom.input.sax.SAXEngine#getErrorHandler()
150 */
151 @Override
152 public ErrorHandler getErrorHandler() {
153 return saxParser.getErrorHandler();
154 }
155
156 /*
157 * (non-Javadoc)
158 *
159 * @see org.jdom.input.sax.SAXEngine#getEntityResolver()
160 */
161 @Override
162 public EntityResolver getEntityResolver() {
163 return saxParser.getEntityResolver();
164 }
165
166 /*
167 * (non-Javadoc)
168 *
169 * @see org.jdom.input.sax.SAXEngine#getDTDHandler()
170 */
171 @Override
172 public DTDHandler getDTDHandler() {
173 return saxParser.getDTDHandler();
174 }
175
176 /*
177 * (non-Javadoc)
178 *
179 * @see org.jdom.input.sax.SAXEngine#isIgnoringElementContentWhitespace()
180 */
181 @Override
182 public boolean getIgnoringElementContentWhitespace() {
183 return saxHandler.getIgnoringElementContentWhitespace();
184 }
185
186 /*
187 * (non-Javadoc)
188 *
189 * @see org.jdom.input.sax.SAXEngine#isIgnoringBoundaryWhitespace()
190 */
191 @Override
192 public boolean getIgnoringBoundaryWhitespace() {
193 return saxHandler.getIgnoringBoundaryWhitespace();
194 }
195
196 /*
197 * (non-Javadoc)
198 *
199 * @see org.jdom.input.sax.SAXEngine#isExpandEntities()
200 */
201 @Override
202 public boolean getExpandEntities() {
203 return saxHandler.getExpandEntities();
204 }
205
206 /*
207 * (non-Javadoc)
208 *
209 * @see org.jdom.input.sax.SAXEngine#build(org.xml.sax.InputSource)
210 */
211 @Override
212 public Document build(final InputSource in)
213 throws JDOMException, IOException {
214 try {
215 // Parse the document.
216 saxParser.parse(in);
217
218 return saxHandler.getDocument();
219 } catch (final SAXParseException e) {
220 Document doc = saxHandler.getDocument();
221 if (doc.hasRootElement() == false) {
222 doc = null;
223 }
224
225 final String systemId = e.getSystemId();
226 if (systemId != null) {
227 throw new JDOMParseException("Error on line " +
228 e.getLineNumber() + " of document " + systemId + ": " +
229 e.getMessage(), e, doc);
230 }
231 throw new JDOMParseException("Error on line " +
232 e.getLineNumber() + ": " +
233 e.getMessage(), e, doc);
234 } catch (final SAXException e) {
235 throw new JDOMParseException("Error in building: " +
236 e.getMessage(), e, saxHandler.getDocument());
237 } finally {
238 // Explicitly nullify the handler to encourage GC
239 // It's a stack var so this shouldn't be necessary, but it
240 // seems to help on some JVMs
241 saxHandler.reset();
242 }
243 }
244
245 /*
246 * (non-Javadoc)
247 *
248 * @see org.jdom.input.sax.SAXEngine#build(java.io.InputStream)
249 */
250 @Override
251 public Document build(final InputStream in) throws JDOMException, IOException {
252 return build(new InputSource(in));
253 }
254
255 /*
256 * (non-Javadoc)
257 *
258 * @see org.jdom.input.sax.SAXEngine#build(java.io.File)
259 */
260 @Override
261 public Document build(final File file) throws JDOMException, IOException {
262 try {
263 return build(fileToURL(file));
264 } catch (final MalformedURLException e) {
265 throw new JDOMException("Error in building", e);
266 }
267 }
268
269 /*
270 * (non-Javadoc)
271 *
272 * @see org.jdom.input.sax.SAXEngine#build(java.net.URL)
273 */
274 @Override
275 public Document build(final URL url) throws JDOMException, IOException {
276 return build(new InputSource(url.toExternalForm()));
277 }
278
279 /*
280 * (non-Javadoc)
281 *
282 * @see org.jdom.input.sax.SAXEngine#build(java.io.InputStream,
283 * java.lang.String)
284 */
285 @Override
286 public Document build(final InputStream in, final String systemId)
287 throws JDOMException, IOException {
288
289 final InputSource src = new InputSource(in);
290 src.setSystemId(systemId);
291 return build(src);
292 }
293
294 /*
295 * (non-Javadoc)
296 *
297 * @see org.jdom.input.sax.SAXEngine#build(java.io.Reader)
298 */
299 @Override
300 public Document build(final Reader characterStream)
301 throws JDOMException, IOException {
302 return build(new InputSource(characterStream));
303 }
304
305 /*
306 * (non-Javadoc)
307 *
308 * @see org.jdom.input.sax.SAXEngine#build(java.io.Reader,
309 * java.lang.String)
310 */
311 @Override
312 public Document build(final Reader characterStream, final String systemId)
313 throws JDOMException, IOException {
314
315 final InputSource src = new InputSource(characterStream);
316 src.setSystemId(systemId);
317 return build(src);
318 }
319
320 /*
321 * (non-Javadoc)
322 *
323 * @see org.jdom.input.sax.SAXEngine#build(java.lang.String)
324 */
325 @Override
326 public Document build(final String systemId)
327 throws JDOMException, IOException {
328 return build(new InputSource(systemId));
329 }
330
331 /**
332 * Custom File.toUrl() implementation to handle special chars in file names
333 * Actually, we can now rely on the core Java toURI function,
334 *
335 * @param file
336 * file object whose path will be converted
337 * @return URL form of the file, with special characters handled
338 * @throws MalformedURLException
339 * if there's a problem constructing a URL
340 */
341 private static URL fileToURL(final File file) throws MalformedURLException {
342
343 return file.getAbsoluteFile().toURI().toURL();
344
345 }
346
347 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import java.io.File;
57 import java.io.IOException;
58 import java.io.InputStream;
59 import java.io.Reader;
60 import java.net.URL;
61
62 import org.xml.sax.DTDHandler;
63 import org.xml.sax.EntityResolver;
64 import org.xml.sax.ErrorHandler;
65 import org.xml.sax.InputSource;
66
67 import org.jdom.Document;
68 import org.jdom.JDOMException;
69 import org.jdom.JDOMFactory;
70
71 /**
72 * SAXEngine provides an interface to interact with either the SAXBuilder or the
73 * SAXBuilderEngine. This makes it possible to do pooling of SAXEngines for
74 * parsing using instances of either SAXBuilder or SAXBuilderEngine.
75 *
76 * @see org.jdom.input.sax
77 * @author Rolf Lear
78 */
79 public interface SAXEngine {
80
81 /**
82 * Returns the current {@link org.jdom.JDOMFactory} in use.
83 *
84 * @return the factory in use
85 */
86 public abstract JDOMFactory getJDOMFactory();
87
88 /**
89 * Returns whether validation is to be performed during the build.
90 *
91 * @return whether validation is to be performed during the build
92 */
93 public abstract boolean isValidating();
94
95 /**
96 * Returns the {@link ErrorHandler} assigned, or null if none.
97 *
98 * @return the ErrorHandler assigned, or null if none
99 */
100 public abstract ErrorHandler getErrorHandler();
101
102 /**
103 * Returns the {@link EntityResolver} assigned, or null if none.
104 *
105 * @return the EntityResolver assigned
106 */
107 public abstract EntityResolver getEntityResolver();
108
109 /**
110 * Returns the {@link DTDHandler} assigned, or null if none.
111 *
112 * @return the DTDHandler assigned
113 */
114 public abstract DTDHandler getDTDHandler();
115
116 /**
117 * Returns whether element content whitespace is to be ignored during the
118 * build.
119 *
120 * @return whether element content whitespace is to be ignored during the
121 * build
122 */
123 public abstract boolean getIgnoringElementContentWhitespace();
124
125 /**
126 * Returns whether or not the parser will elminate element content
127 * containing only whitespace.
128 *
129 * @return <code>boolean</code> - whether only whitespace content will be
130 * ignored during build.
131 */
132 public abstract boolean getIgnoringBoundaryWhitespace();
133
134 /**
135 * Returns whether or not entities are being expanded into normal text
136 * content.
137 *
138 * @return whether entities are being expanded
139 */
140 public abstract boolean getExpandEntities();
141
142 /**
143 * This builds a document from the supplied input source.
144 *
145 * @param in
146 * <code>InputSource</code> to read from
147 * @return <code>Document</code> resultant Document object
148 * @throws JDOMException
149 * when errors occur in parsing
150 * @throws IOException
151 * when an I/O error prevents a document from being fully parsed
152 */
153 public abstract Document build(InputSource in)
154 throws JDOMException, IOException;
155
156 /**
157 * <p>
158 * This builds a document from the supplied input stream.
159 * </p>
160 *
161 * @param in
162 * <code>InputStream</code> to read from
163 * @return <code>Document</code> resultant Document object
164 * @throws JDOMException
165 * when errors occur in parsing
166 * @throws IOException
167 * when an I/O error prevents a document from being fully parsed.
168 */
169 public abstract Document build(InputStream in) throws JDOMException, IOException;
170
171 /**
172 * <p>
173 * This builds a document from the supplied filename.
174 * </p>
175 *
176 * @param file
177 * <code>File</code> to read from
178 * @return <code>Document</code> resultant Document object
179 * @throws JDOMException
180 * when errors occur in parsing
181 * @throws IOException
182 * when an I/O error prevents a document from being fully parsed
183 */
184 public abstract Document build(final File file) throws JDOMException, IOException;
185
186 /**
187 * <p>
188 * This builds a document from the supplied URL.
189 * </p>
190 *
191 * @param url
192 * <code>URL</code> to read from.
193 * @return <code>Document</code> - resultant Document object.
194 * @throws JDOMException
195 * when errors occur in parsing
196 * @throws IOException
197 * when an I/O error prevents a document from being fully parsed.
198 */
199 public abstract Document build(final URL url) throws JDOMException, IOException;
200
201 /**
202 * <p>
203 * This builds a document from the supplied input stream.
204 * </p>
205 *
206 * @param in
207 * <code>InputStream</code> to read from.
208 * @param systemId
209 * base for resolving relative URIs
210 * @return <code>Document</code> resultant Document object
211 * @throws JDOMException
212 * when errors occur in parsing
213 * @throws IOException
214 * when an I/O error prevents a document from being fully parsed
215 */
216 public abstract Document build(final InputStream in, final String systemId)
217 throws JDOMException, IOException;
218
219 /**
220 * <p>
221 * This builds a document from the supplied Reader. It's the programmer's
222 * responsibility to make sure the reader matches the encoding of the file.
223 * It's often easier and safer to use an InputStream rather than a Reader,
224 * and to let the parser auto-detect the encoding from the XML declaration.
225 * </p>
226 *
227 * @param characterStream
228 * <code>Reader</code> to read from
229 * @return <code>Document</code> resultant Document object
230 * @throws JDOMException
231 * when errors occur in parsing
232 * @throws IOException
233 * when an I/O error prevents a document from being fully parsed
234 */
235 public abstract Document build(final Reader characterStream)
236 throws JDOMException, IOException;
237
238 /**
239 * <p>
240 * This builds a document from the supplied Reader. It's the programmer's
241 * responsibility to make sure the reader matches the encoding of the file.
242 * It's often easier and safer to use an InputStream rather than a Reader,
243 * and to let the parser auto-detect the encoding from the XML declaration.
244 * </p>
245 *
246 * @param characterStream
247 * <code>Reader</code> to read from.
248 * @param systemId
249 * base for resolving relative URIs
250 * @return <code>Document</code> resultant Document object
251 * @throws JDOMException
252 * when errors occur in parsing
253 * @throws IOException
254 * when an I/O error prevents a document from being fully parsed
255 */
256 public abstract Document build(final Reader characterStream, final String systemId)
257 throws JDOMException, IOException;
258
259 /**
260 * <p>
261 * This builds a document from the supplied URI.
262 * </p>
263 *
264 * @param systemId
265 * URI for the input
266 * @return <code>Document</code> resultant Document object
267 * @throws JDOMException
268 * when errors occur in parsing
269 * @throws IOException
270 * when an I/O error prevents a document from being fully parsed
271 */
272 public abstract Document build(final String systemId)
273 throws JDOMException, IOException;
274
275 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import java.util.ArrayList;
57 import java.util.HashMap;
58 import java.util.List;
59 import java.util.Map;
60
61 import javax.xml.XMLConstants;
62
63 import org.xml.sax.Attributes;
64 import org.xml.sax.DTDHandler;
65 import org.xml.sax.Locator;
66 import org.xml.sax.SAXException;
67 import org.xml.sax.ext.Attributes2;
68 import org.xml.sax.ext.DeclHandler;
69 import org.xml.sax.ext.LexicalHandler;
70 import org.xml.sax.helpers.DefaultHandler;
71
72 import org.jdom.Attribute;
73 import org.jdom.AttributeType;
74 import org.jdom.CDATA;
75 import org.jdom.Comment;
76 import org.jdom.DefaultJDOMFactory;
77 import org.jdom.DocType;
78 import org.jdom.Document;
79 import org.jdom.Element;
80 import org.jdom.EntityRef;
81 import org.jdom.JDOMFactory;
82 import org.jdom.Namespace;
83 import org.jdom.Parent;
84 import org.jdom.ProcessingInstruction;
85 import org.jdom.Text;
86 import org.jdom.input.SAXBuilder;
87
88 /**
89 * A support class for {@link SAXBuilder} which listens for SAX events.
90 * <p>
91 * People overriding this class are cautioned to ensure that the implementation
92 * of the cleanUp() method resets to a virgin state. The cleanUp() method will
93 * be called when this SAXHandler is reset(), which may happen multiple times
94 * between parses. The cleanUp() method must ensure that there are no references
95 * remaining to any external instances.
96 * <p>
97 * Overriding of this class is permitted to allow for different handling of SAX
98 * events. Once you have created a subclass of this, you also need to create a
99 * custom implementation of {@link SAXHandlerFactory} to supply your instances
100 * to {@link SAXBuilder}
101 * <p>
102 * If the XMLReader producing the SAX Events supports a document Locator, then
103 * this instance will use the locator to supply the line and column data from
104 * the SAX locator to the JDOMFactory. <strong>Note:</strong> the SAX
105 * specification for the SAX Locator indicates that the line and column
106 * represent the position of the <strong>end</strong> of the SAX Event. For
107 * example, the line and column of the simple XML <code>&lt;root /&gt;</code>
108 * would be line 1, column 9.
109 *
110 * @see org.jdom.input.sax
111 * @author Brett McLaughlin
112 * @author Jason Hunter
113 * @author Philip Nelson
114 * @author Bradley S. Huffman
115 * @author phil@triloggroup.com
116 * @author Rolf Lear
117 */
118 public class SAXHandler extends DefaultHandler implements LexicalHandler,
119 DeclHandler, DTDHandler {
120
121 /** The JDOMFactory used for JDOM object creation */
122 private final JDOMFactory factory;
123
124 /**
125 * Temporary holder for namespaces that have been declared with
126 * startPrefixMapping, but are not yet available on the element
127 */
128 private final List<Namespace> declaredNamespaces = new ArrayList<Namespace>(
129 32);
130
131 /** Temporary holder for the internal subset */
132 private final StringBuilder internalSubset = new StringBuilder();
133
134 /** Temporary holder for Text and CDATA */
135 private final TextBuffer textBuffer = new TextBuffer();
136
137 /** The external entities defined in this document */
138 private final Map<String, String[]> externalEntities = new HashMap<String, String[]>();
139
140 /** <code>Document</code> object being built - must be cleared on reset() */
141 private Document currentDocument = null;
142
143 /** <code>Element</code> object being built - must be cleared on reset() */
144 private Element currentElement = null;
145
146 /** The SAX Locator object provided by the parser */
147 private Locator currentLocator = null;
148
149 /** Indicator of where in the document we are - must be reset() */
150 private boolean atRoot = true;
151
152 /**
153 * Indicator of whether we are in the DocType. Note that the DTD consists of
154 * both the internal subset (inside the <!DOCTYPE> tag) and the external
155 * subset (in a separate .dtd file). - must be reset()
156 */
157 private boolean inDTD = false;
158
159 /** Indicator of whether we are in the internal subset - must be reset() */
160 private boolean inInternalSubset = false;
161
162 /** Indicator of whether we previously were in a CDATA - must be reset() */
163 private boolean previousCDATA = false;
164
165 /** Indicator of whether we are in a CDATA - must be reset() */
166 private boolean inCDATA = false;
167
168 /** Indicator of whether we should expand entities */
169 private boolean expand = true;
170
171 /**
172 * Indicator of whether we are actively suppressing (non-expanding) a
173 * current entity - must be reset()
174 */
175 private boolean suppress = false;
176
177 /** How many nested entities we're currently within - must be reset() */
178 private int entityDepth = 0; // XXX may not be necessary anymore?
179
180 /** Whether to ignore ignorable whitespace */
181 private boolean ignoringWhite = false;
182
183 /** Whether to ignore text containing all whitespace */
184 private boolean ignoringBoundaryWhite = false;
185
186 private int lastline = 0, lastcol = 0;
187
188 /**
189 * This will create a new <code>SAXHandler</code> that listens to SAX events
190 * and creates a JDOM Document. The objects will be constructed using the
191 * default factory.
192 */
193 public SAXHandler() {
194 this(null);
195 }
196
197 /**
198 * This will create a new <code>SAXHandler</code> that listens to SAX events
199 * and creates a JDOM Document. The objects will be constructed using the
200 * provided factory.
201 *
202 * @param factory
203 * <code>JDOMFactory</code> to be used for constructing objects
204 */
205 public SAXHandler(final JDOMFactory factory) {
206 this.factory = factory != null ? factory : new DefaultJDOMFactory();
207 reset();
208 }
209
210 /**
211 * Override this method if you are a subclasser, and you want to clear the
212 * state of your SAXHandler instance in preparation for a new parse.
213 */
214 protected void resetSubCLass() {
215 // override this if you subclass SAXHandler.
216 // it will be called after the base core SAXHandler is reset.
217 }
218
219 /**
220 * Restore this SAXHandler to a clean state ready for another parse round.
221 * All internal variables are cleared to an initialized state, and then the
222 * resetSubClass() method is called to clear any methods that a subclass may
223 * need to have reset.
224 */
225 public final void reset() {
226 currentLocator = null;
227 currentDocument = factory.document(null);
228 currentElement = null;
229 atRoot = true;
230 inDTD = false;
231 inInternalSubset = false;
232 previousCDATA = false;
233 inCDATA = false;
234 suppress = false;
235 entityDepth = 0;
236 declaredNamespaces.clear();
237 internalSubset.setLength(0);
238 textBuffer.clear();
239 externalEntities.clear();
240 resetSubCLass();
241 }
242
243 /**
244 * Pushes an element onto the tree under construction. Allows subclasses to
245 * put content under a dummy root element which is useful for building
246 * content that would otherwise be a non-well formed document.
247 *
248 * @param element
249 * root element under which content will be built
250 */
251 protected void pushElement(final Element element) {
252 if (atRoot) {
253 currentDocument.setRootElement(element); // XXX should we use a
254 // factory call?
255 atRoot = false;
256 } else {
257 factory.addContent(currentElement, element);
258 }
259 currentElement = element;
260 }
261
262 /**
263 * Returns the document. Should be called after parsing is complete.
264 *
265 * @return <code>Document</code> - Document that was built
266 */
267 public Document getDocument() {
268 return currentDocument;
269 }
270
271 /**
272 * Returns the factory used for constructing objects.
273 *
274 * @return <code>JDOMFactory</code> - the factory used for constructing
275 * objects.
276 * @see #SAXHandler(org.jdom.JDOMFactory)
277 */
278 public JDOMFactory getFactory() {
279 return factory;
280 }
281
282 /**
283 * This sets whether or not to expand entities during the build. A true
284 * means to expand entities as normal content. A false means to leave
285 * entities unexpanded as <code>EntityRef</code> objects. The default is
286 * true.
287 *
288 * @param expand
289 * <code>boolean</code> indicating whether entity expansion should
290 * occur.
291 */
292 public void setExpandEntities(final boolean expand) {
293 this.expand = expand;
294 }
295
296 /**
297 * Returns whether or not entities will be expanded during the build.
298 *
299 * @return <code>boolean</code> - whether entity expansion will occur during
300 * build.
301 * @see #setExpandEntities
302 */
303 public boolean getExpandEntities() {
304 return expand;
305 }
306
307 /**
308 * Specifies whether or not the parser should elminate whitespace in element
309 * content (sometimes known as "ignorable whitespace") when building the
310 * document. Only whitespace which is contained within element content that
311 * has an element only content model will be eliminated (see XML Rec 3.2.1).
312 * For this setting to take effect requires that validation be turned on.
313 * The default value of this setting is <code>false</code>.
314 *
315 * @param ignoringWhite
316 * Whether to ignore ignorable whitespace
317 */
318 public void setIgnoringElementContentWhitespace(final boolean ignoringWhite) {
319 this.ignoringWhite = ignoringWhite;
320 }
321
322 /**
323 * Specifies whether or not the parser should eliminate text() nodes
324 * containing only whitespace when building the document. See
325 * {@link SAXBuilder#setIgnoringBoundaryWhitespace(boolean)}.
326 *
327 * @param ignoringBoundaryWhite
328 * Whether to ignore only whitespace content
329 */
330 public void setIgnoringBoundaryWhitespace(
331 final boolean ignoringBoundaryWhite) {
332 this.ignoringBoundaryWhite = ignoringBoundaryWhite;
333 }
334
335 /**
336 * Returns whether or not the parser will elminate element content
337 * containing only whitespace.
338 *
339 * @return <code>boolean</code> - whether only whitespace content will be
340 * ignored during build.
341 * @see #setIgnoringBoundaryWhitespace
342 */
343 public boolean getIgnoringBoundaryWhitespace() {
344 return ignoringBoundaryWhite;
345 }
346
347 /**
348 * Returns whether or not the parser will elminate whitespace in element
349 * content (sometimes known as "ignorable whitespace") when building the
350 * document.
351 *
352 * @return <code>boolean</code> - whether ignorable whitespace will be
353 * ignored during build.
354 * @see #setIgnoringElementContentWhitespace
355 */
356 public boolean getIgnoringElementContentWhitespace() {
357 return ignoringWhite;
358 }
359
360 @Override
361 public void startDocument() {
362 if (currentLocator != null) {
363 currentDocument.setBaseURI(currentLocator.getSystemId());
364 }
365 }
366
367 /**
368 * This is called when the parser encounters an external entity declaration.
369 *
370 * @param name
371 * entity name
372 * @param publicID
373 * public id
374 * @param systemID
375 * system id
376 * @throws SAXException
377 * when things go wrong
378 */
379 @Override
380 public void externalEntityDecl(final String name, final String publicID,
381 final String systemID) throws SAXException {
382 // Store the public and system ids for the name
383 externalEntities.put(name, new String[] { publicID, systemID });
384
385 if (!inInternalSubset)
386 return;
387
388 internalSubset.append(" <!ENTITY ").append(name);
389 appendExternalId(publicID, systemID);
390 internalSubset.append(">\n");
391 }
392
393 /**
394 * This handles an attribute declaration in the internal subset.
395 *
396 * @param eName
397 * <code>String</code> element name of attribute
398 * @param aName
399 * <code>String</code> attribute name
400 * @param type
401 * <code>String</code> attribute type
402 * @param valueDefault
403 * <code>String</code> default value of attribute
404 * @param value
405 * <code>String</code> value of attribute
406 */
407 @Override
408 public void attributeDecl(final String eName, final String aName,
409 final String type, final String valueDefault, final String value) {
410
411 if (!inInternalSubset)
412 return;
413
414 internalSubset.append(" <!ATTLIST ").append(eName).append(' ')
415 .append(aName).append(' ').append(type).append(' ');
416 if (valueDefault != null) {
417 internalSubset.append(valueDefault);
418 } else {
419 internalSubset.append('\"').append(value).append('\"');
420 }
421 if ((valueDefault != null) && (valueDefault.equals("#FIXED"))) {
422 internalSubset.append(" \"").append(value).append('\"');
423 }
424 internalSubset.append(">\n");
425 }
426
427 /**
428 * Handle an element declaration in a DTD.
429 *
430 * @param name
431 * <code>String</code> name of element
432 * @param model
433 * <code>String</code> model of the element in DTD syntax
434 */
435 @Override
436 public void elementDecl(final String name, final String model) {
437 // Skip elements that come from the external subset
438 if (!inInternalSubset)
439 return;
440
441 internalSubset.append(" <!ELEMENT ").append(name).append(' ')
442 .append(model).append(">\n");
443 }
444
445 /**
446 * Handle an internal entity declaration in a DTD.
447 *
448 * @param name
449 * <code>String</code> name of entity
450 * @param value
451 * <code>String</code> value of the entity
452 */
453 @Override
454 public void internalEntityDecl(final String name, final String value) {
455
456 // Skip entities that come from the external subset
457 if (!inInternalSubset)
458 return;
459
460 internalSubset.append(" <!ENTITY ");
461 if (name.startsWith("%")) {
462 internalSubset.append("% ").append(name.substring(1));
463 } else {
464 internalSubset.append(name);
465 }
466 internalSubset.append(" \"").append(value).append("\">\n");
467 }
468
469 /**
470 * This will indicate that a processing instruction has been encountered.
471 * (The XML declaration is not a processing instruction and will not be
472 * reported.)
473 *
474 * @param target
475 * <code>String</code> target of PI
476 * @param data
477 * <code>String</code> containing all data sent to the PI. This
478 * typically looks like one or more attribute value pairs.
479 * @throws SAXException
480 * when things go wrong
481 */
482 @Override
483 public void processingInstruction(final String target, final String data)
484 throws SAXException {
485
486 if (suppress)
487 return;
488
489 flushCharacters();
490
491 final ProcessingInstruction pi = (currentLocator == null) ? factory
492 .processingInstruction(target, data) : factory
493 .processingInstruction(currentLocator.getLineNumber(),
494 currentLocator.getColumnNumber(), target, data);
495
496 if (atRoot) {
497 factory.addContent(currentDocument, pi);
498 } else {
499 factory.addContent(getCurrentElement(), pi);
500 }
501 }
502
503 /**
504 * This indicates that an unresolvable entity reference has been
505 * encountered, normally because the external DTD subset has not been read.
506 *
507 * @param name
508 * <code>String</code> name of entity
509 * @throws SAXException
510 * when things go wrong
511 */
512 @Override
513 public void skippedEntity(final String name) throws SAXException {
514
515 // We don't handle parameter entity references.
516 if (name.startsWith("%"))
517 return;
518
519 flushCharacters();
520
521 final EntityRef er = currentLocator == null ? factory.entityRef(name)
522 : factory.entityRef(currentLocator.getLineNumber(),
523 currentLocator.getColumnNumber(), name);
524
525 factory.addContent(getCurrentElement(), er);
526 }
527
528 /**
529 * This will add the prefix mapping to the JDOM <code>Document</code>
530 * object.
531 *
532 * @param prefix
533 * <code>String</code> namespace prefix.
534 * @param uri
535 * <code>String</code> namespace URI.
536 */
537 @Override
538 public void startPrefixMapping(final String prefix, final String uri)
539 throws SAXException {
540
541 if (suppress)
542 return;
543
544 final Namespace ns = Namespace.getNamespace(prefix, uri);
545 declaredNamespaces.add(ns);
546 }
547
548 /**
549 * This reports the occurrence of an actual element. It will include the
550 * element's attributes, with the exception of XML vocabulary specific
551 * attributes, such as <code>xmlns:[namespace prefix]</code> and
552 * <code>xsi:schemaLocation</code>.
553 *
554 * @param namespaceURI
555 * <code>String</code> namespace URI this element is associated with,
556 * or an empty <code>String</code>
557 * @param localName
558 * <code>String</code> name of element (with no namespace prefix, if
559 * one is present)
560 * @param qName
561 * <code>String</code> XML 1.0 version of element name: [namespace
562 * prefix]:[localName]
563 * @param atts
564 * <code>Attributes</code> list for this element
565 * @throws SAXException
566 * when things go wrong
567 */
568 @Override
569 public void startElement(final String namespaceURI, String localName,
570 final String qName, final Attributes atts) throws SAXException {
571 if (suppress)
572 return;
573
574 String prefix = "";
575
576 // If QName is set, then set prefix and local name as necessary
577 if (!"".equals(qName)) {
578 final int colon = qName.indexOf(':');
579
580 if (colon > 0) {
581 prefix = qName.substring(0, colon);
582 }
583
584 // If local name is not set, try to get it from the QName
585 if ((localName == null) || (localName.equals(""))) {
586 localName = qName.substring(colon + 1);
587 }
588 }
589 // At this point either prefix and localName are set correctly or
590 // there is an error in the parser.
591
592 final Namespace namespace = Namespace
593 .getNamespace(prefix, namespaceURI);
594 final Element element = currentLocator == null ? factory.element(
595 localName, namespace) : factory.element(
596 currentLocator.getLineNumber(),
597 currentLocator.getColumnNumber(), localName, namespace);
598
599 // Take leftover declared namespaces and add them to this element's
600 // map of namespaces
601 if (declaredNamespaces.size() > 0) {
602 transferNamespaces(element);
603 }
604
605 flushCharacters();
606
607 if (atRoot) {
608 factory.setRoot(currentDocument, element); // Yes, use a factory
609 // call...
610 atRoot = false;
611 } else {
612 factory.addContent(getCurrentElement(), element);
613 }
614 currentElement = element;
615
616 // Handle attributes
617 for (int i = 0, len = atts.getLength(); i < len; i++) {
618
619 String attPrefix = "";
620 String attLocalName = atts.getLocalName(i);
621 final String attQName = atts.getQName(i);
622 final boolean specified = (atts instanceof Attributes2) ? ((Attributes2)atts).isSpecified(i) : true;
623
624 // If attribute QName is set, then set attribute prefix and
625 // attribute local name as necessary
626 if (!attQName.equals("")) {
627 // Bypass any xmlns attributes which might appear, as we got
628 // them already in startPrefixMapping(). This is sometimes
629 // necessary when SAXHandler is used with another source than
630 // SAXBuilder, as with JDOMResult.
631 if (attQName.startsWith("xmlns:") || attQName.equals("xmlns")) {
632 continue;
633 }
634
635 final int attColon = attQName.indexOf(':');
636
637 if (attColon > 0) {
638 attPrefix = attQName.substring(0, attColon);
639 }
640
641 // If localName is not set, try to get it from the QName
642 if ("".equals(attLocalName)) {
643 attLocalName = attQName.substring(attColon + 1);
644 }
645 }
646
647 final AttributeType attType = AttributeType.getAttributeType(atts
648 .getType(i));
649 final String attValue = atts.getValue(i);
650 final String attURI = atts.getURI(i);
651
652 if (XMLConstants.XMLNS_ATTRIBUTE.equals(attLocalName)
653 || XMLConstants.XMLNS_ATTRIBUTE.equals(attPrefix)
654 || XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attURI)) {
655 // use the actual Namespace to check too, because, in theory, a
656 // namespace-aware parser does not need to set the qName unless
657 // the namespace-prefixes feature is set as well.
658 continue;
659 }
660 // At this point either attPrefix and attLocalName are set
661 // correctly or there is an error in the parser.
662
663 // just one thing to sort out....
664 // the prefix for the namespace.
665 if (!"".equals(attURI) && "".equals(attPrefix)) {
666 // the localname and qName are the same, but there is a
667 // Namspace URI. We need to figure out the namespace prefix.
668 // this is an unusual condition. Currently the only known
669 // trigger
670 // is when there is a fixed/defaulted attribute from a
671 // validating
672 // XMLSchema, and the attribute is in a different namespace
673 // than the rest of the document, this happens whenever there
674 // is an attribute definition that has form="qualified".
675 // <xs:attribute name="attname" form="qualified" ... />
676 // or the schema sets attributeFormDefault="qualified"
677 final HashMap<String, Namespace> tmpmap = new HashMap<String, Namespace>();
678 for (final Namespace nss : element.getNamespacesInScope()) {
679 if (nss.getPrefix().length() > 0
680 && nss.getURI().equals(attURI)) {
681 attPrefix = nss.getPrefix();
682 break;
683 }
684 tmpmap.put(nss.getPrefix(), nss);
685 }
686
687 if ("".equals(attPrefix)) {
688 // we cannot find a 'prevailing' namespace that has a prefix
689 // that is for this namespace.
690 // This basically means that there's an XMLSchema, for the
691 // DEFAULT namespace, and there's a defaulted/fixed
692 // attribute definition in the XMLSchema that's targeted
693 // for this namespace,... but, the user has either not
694 // declared a prefixed version of the namespace, or has
695 // re-declared the same prefix at a lower level with a
696 // different namespace.
697 // All of these things are possible.
698 // Create some sort of default prefix.
699 int cnt = 0;
700 final String base = "attns";
701 String pfx = base + cnt;
702 while (tmpmap.containsKey(pfx)) {
703 cnt++;
704 pfx = base + cnt;
705 }
706 attPrefix = pfx;
707 }
708 }
709 final Namespace attNs = Namespace.getNamespace(attPrefix, attURI);
710
711 final Attribute attribute = factory.attribute(attLocalName,
712 attValue, attType, attNs);
713 if (!specified) {
714 // it is a DTD defaulted value.
715 attribute.setSpecified(false);
716 }
717 factory.setAttribute(element, attribute);
718 }
719
720 }
721
722 /**
723 * This will take the supplied <code>{@link Element}</code> and transfer its
724 * namespaces to the global namespace storage.
725 *
726 * @param element
727 * <code>Element</code> to read namespaces from.
728 */
729 private void transferNamespaces(final Element element) {
730 for (final Namespace ns : declaredNamespaces) {
731 if (ns != element.getNamespace()) {
732 element.addNamespaceDeclaration(ns);
733 }
734 }
735 declaredNamespaces.clear();
736 }
737
738 /**
739 * This will report character data (within an element).
740 *
741 * @param ch
742 * <code>char[]</code> character array with character data
743 * @param start
744 * <code>int</code> index in array where data starts.
745 * @param length
746 * <code>int</code> length of data.
747 */
748 @Override
749 public void characters(final char[] ch, final int start, final int length)
750 throws SAXException {
751
752 if (suppress || (length == 0 && !inCDATA))
753 return;
754
755 if (previousCDATA != inCDATA) {
756 flushCharacters();
757 }
758
759 textBuffer.append(ch, start, length);
760
761 if (currentLocator != null) {
762 lastline = currentLocator.getLineNumber();
763 lastcol = currentLocator.getColumnNumber();
764 }
765 }
766
767 /**
768 * Capture ignorable whitespace as text. If
769 * setIgnoringElementContentWhitespace(true) has been called then this
770 * method does nothing.
771 *
772 * @param ch
773 * <code>[]</code> - char array of ignorable whitespace
774 * @param start
775 * <code>int</code> - starting position within array
776 * @param length
777 * <code>int</code> - length of whitespace after start
778 * @throws SAXException
779 * when things go wrong
780 */
781 @Override
782 public void ignorableWhitespace(final char[] ch, final int start,
783 final int length) throws SAXException {
784 if (!ignoringWhite) {
785 characters(ch, start, length);
786 }
787 }
788
789 /**
790 * This will flush any characters from SAX character calls we've been
791 * buffering.
792 *
793 * @throws SAXException
794 * when things go wrong
795 */
796 protected void flushCharacters() throws SAXException {
797 if (ignoringBoundaryWhite) {
798 if (!textBuffer.isAllWhitespace()) {
799 flushCharacters(textBuffer.toString());
800 }
801 } else {
802 flushCharacters(textBuffer.toString());
803 }
804 textBuffer.clear();
805 }
806
807 /**
808 * Flush the given string into the document. This is a protected method so
809 * subclassers can control text handling without knowledge of the internals
810 * of this class.
811 *
812 * @param data
813 * string to flush
814 * @throws SAXException
815 * if the state of the handler does not allow this.
816 */
817 protected void flushCharacters(final String data) throws SAXException {
818 if (data.length() == 0 && !inCDATA) {
819 previousCDATA = inCDATA;
820 return;
821 }
822
823 /**
824 * This is commented out because of some problems with the inline DTDs
825 * that Xerces seems to have. if (!inDTD) { if (inEntity) {
826 * getCurrentElement().setContent(factory.text(data)); } else {
827 * getCurrentElement().addContent(factory.text(data)); }
828 */
829
830 if (previousCDATA) {
831 final CDATA cdata = currentLocator == null ? factory.cdata(data)
832 : factory.cdata(lastline, lastcol, data);
833 factory.addContent(getCurrentElement(), cdata);
834 } else if (data.length() != 0) {
835 final Text text = currentLocator == null ? factory.text(data)
836 : factory.text(lastline, lastcol, data);
837 factory.addContent(getCurrentElement(), text);
838 }
839
840 previousCDATA = inCDATA;
841 }
842
843 /**
844 * Indicates the end of an element (<code>&lt;/[element name]&gt;</code>) is
845 * reached. Note that the parser does not distinguish between empty elements
846 * and non-empty elements, so this will occur uniformly.
847 *
848 * @param namespaceURI
849 * <code>String</code> URI of namespace this element is associated
850 * with
851 * @param localName
852 * <code>String</code> name of element without prefix
853 * @param qName
854 * <code>String</code> name of element in XML 1.0 form
855 * @throws SAXException
856 * when things go wrong
857 */
858 @Override
859 public void endElement(final String namespaceURI, final String localName,
860 final String qName) throws SAXException {
861
862 if (suppress)
863 return;
864
865 flushCharacters();
866
867 if (!atRoot) {
868 final Parent p = currentElement.getParent();
869 if (p instanceof Document) {
870 atRoot = true;
871 } else {
872 currentElement = (Element) p;
873 }
874 } else {
875 throw new SAXException(
876 "Ill-formed XML document (missing opening tag for "
877 + localName + ")");
878 }
879 }
880
881 /**
882 * This will signify that a DTD is being parsed, and can be used to ensure
883 * that comments and other lexical structures in the DTD are not added to
884 * the JDOM <code>Document</code> object.
885 *
886 * @param name
887 * <code>String</code> name of element listed in DTD
888 * @param publicID
889 * <code>String</code> public ID of DTD
890 * @param systemID
891 * <code>String</code> system ID of DTD
892 */
893 @Override
894 public void startDTD(final String name, final String publicID,
895 final String systemID) throws SAXException {
896
897 flushCharacters(); // Is this needed here?
898
899 final DocType doctype = currentLocator == null ? factory.docType(name,
900 publicID, systemID) : factory.docType(
901 currentLocator.getLineNumber(),
902 currentLocator.getColumnNumber(), name, publicID, systemID);
903 factory.addContent(currentDocument, doctype);
904 inDTD = true;
905 inInternalSubset = true;
906 }
907
908 /**
909 * This signifies that the reading of the DTD is complete.
910 */
911 @Override
912 public void endDTD() {
913
914 currentDocument.getDocType().setInternalSubset(
915 internalSubset.toString());
916 inDTD = false;
917 inInternalSubset = false;
918 }
919
920 @Override
921 public void startEntity(final String name) throws SAXException {
922 entityDepth++;
923
924 if (expand || entityDepth > 1) {
925 // Short cut out if we're expanding or if we're nested
926 return;
927 }
928
929 // A "[dtd]" entity indicates the beginning of the external subset
930 if (name.equals("[dtd]")) {
931 inInternalSubset = false;
932 return;
933 }
934
935 // Ignore DTD references, and translate the standard 5
936 if ((!inDTD) && (!name.equals("amp")) && (!name.equals("lt"))
937 && (!name.equals("gt")) && (!name.equals("apos"))
938 && (!name.equals("quot"))) {
939
940 if (!expand) {
941 String pub = null;
942 String sys = null;
943 final String[] ids = externalEntities.get(name);
944 if (ids != null) {
945 pub = ids[0]; // may be null, that's OK
946 sys = ids[1]; // may be null, that's OK
947 }
948 /**
949 * if no current element, this entity belongs to an attribute in
950 * these cases, it is an error on the part of the parser to call
951 * startEntity but this will help in some cases. See
952 * org/xml/sax/
953 * ext/LexicalHandler.html#startEntity(java.lang.String) for
954 * more information
955 */
956 if (!atRoot) {
957 flushCharacters();
958 final EntityRef entity = currentLocator == null ? factory
959 .entityRef(name, pub, sys) : factory.entityRef(
960 currentLocator.getLineNumber(),
961 currentLocator.getColumnNumber(), name, pub, sys);
962
963 // no way to tell if the entity was from an attribute or
964 // element so just assume element
965 factory.addContent(getCurrentElement(), entity);
966 }
967 suppress = true;
968 }
969 }
970 }
971
972 @Override
973 public void endEntity(final String name) throws SAXException {
974 entityDepth--;
975 if (entityDepth == 0) {
976 // No way are we suppressing if not in an entity,
977 // regardless of the "expand" value
978 suppress = false;
979 }
980 if (name.equals("[dtd]")) {
981 inInternalSubset = true;
982 }
983 }
984
985 /**
986 * Report a CDATA section
987 */
988 @Override
989 public void startCDATA() {
990 if (suppress)
991 return;
992
993 inCDATA = true;
994 }
995
996 /**
997 * Report a CDATA section
998 */
999 @Override
1000 public void endCDATA() throws SAXException {
1001 if (suppress)
1002 return;
1003
1004 previousCDATA = true;
1005 flushCharacters();
1006 previousCDATA = false;
1007 inCDATA = false;
1008 }
1009
1010 /**
1011 * This reports that a comments is parsed. If not in the DTD, this comment
1012 * is added to the current JDOM <code>Element</code>, or the
1013 * <code>Document</code> itself if at that level.
1014 *
1015 * @param ch
1016 * <code>ch[]</code> array of comment characters.
1017 * @param start
1018 * <code>int</code> index to start reading from.
1019 * @param length
1020 * <code>int</code> length of data.
1021 * @throws SAXException
1022 * if the state of the handler disallows this call
1023 */
1024 @Override
1025 public void comment(final char[] ch, final int start, final int length)
1026 throws SAXException {
1027
1028 if (suppress)
1029 return;
1030
1031 flushCharacters();
1032
1033 final String commentText = new String(ch, start, length);
1034 if (inDTD && inInternalSubset && (expand == false)) {
1035 internalSubset.append(" <!--").append(commentText).append("-->\n");
1036 return;
1037 }
1038 if ((!inDTD) && (!commentText.equals(""))) {
1039 final Comment comment = currentLocator == null ? factory
1040 .comment(commentText) : factory.comment(
1041 currentLocator.getLineNumber(),
1042 currentLocator.getColumnNumber(), commentText);
1043 if (atRoot) {
1044 factory.addContent(currentDocument, comment);
1045 } else {
1046 factory.addContent(getCurrentElement(), comment);
1047 }
1048 }
1049 }
1050
1051 /**
1052 * Handle the declaration of a Notation in a DTD
1053 *
1054 * @param name
1055 * name of the notation
1056 * @param publicID
1057 * the public ID of the notation
1058 * @param systemID
1059 * the system ID of the notation
1060 */
1061 @Override
1062 public void notationDecl(final String name, final String publicID,
1063 final String systemID) throws SAXException {
1064
1065 if (!inInternalSubset)
1066 return;
1067
1068 internalSubset.append(" <!NOTATION ").append(name);
1069 appendExternalId(publicID, systemID);
1070 internalSubset.append(">\n");
1071 }
1072
1073 /**
1074 * Handler for unparsed entity declarations in the DTD
1075 *
1076 * @param name
1077 * <code>String</code> of the unparsed entity decl
1078 * @param publicID
1079 * <code>String</code> of the unparsed entity decl
1080 * @param systemID
1081 * <code>String</code> of the unparsed entity decl
1082 * @param notationName
1083 * <code>String</code> of the unparsed entity decl
1084 */
1085 @Override
1086 public void unparsedEntityDecl(final String name, final String publicID,
1087 final String systemID, final String notationName) {
1088
1089 if (!inInternalSubset)
1090 return;
1091
1092 internalSubset.append(" <!ENTITY ").append(name);
1093 appendExternalId(publicID, systemID);
1094 internalSubset.append(" NDATA ").append(notationName);
1095 internalSubset.append(">\n");
1096 }
1097
1098 /**
1099 * Appends an external ID to the internal subset buffer. Either publicID or
1100 * systemID may be null, but not both.
1101 *
1102 * @param publicID
1103 * the public ID
1104 * @param systemID
1105 * the system ID
1106 */
1107 private void appendExternalId(final String publicID, final String systemID) {
1108 if (publicID != null) {
1109 internalSubset.append(" PUBLIC \"").append(publicID).append('\"');
1110 }
1111 if (systemID != null) {
1112 if (publicID == null) {
1113 internalSubset.append(" SYSTEM ");
1114 } else {
1115 internalSubset.append(' ');
1116 }
1117 internalSubset.append('\"').append(systemID).append('\"');
1118 }
1119 }
1120
1121 /**
1122 * Returns the being-parsed element.
1123 *
1124 * @return <code>Element</code> - element being built.
1125 * @throws SAXException
1126 * if the state of the handler disallows this call
1127 */
1128 public Element getCurrentElement() throws SAXException {
1129 if (currentElement == null) {
1130 throw new SAXException(
1131 "Ill-formed XML document (multiple root elements detected)");
1132 }
1133 return currentElement;
1134 }
1135
1136 /**
1137 * Receives an object for locating the origin of SAX document events. This
1138 * method is invoked by the SAX parser.
1139 * <p>
1140 * {@link org.jdom.JDOMFactory} implementations can use the
1141 * {@link #getDocumentLocator} method to get access to the {@link Locator}
1142 * during parse.
1143 * </p>
1144 *
1145 * @param locator
1146 * <code>Locator</code> an object that can return the location of any
1147 * SAX document event.
1148 */
1149 @Override
1150 public void setDocumentLocator(final Locator locator) {
1151 this.currentLocator = locator;
1152 }
1153
1154 /**
1155 * Provides access to the {@link Locator} object provided by the SAX parser.
1156 *
1157 * @return <code>Locator</code> an object that can return the location of
1158 * any SAX document event.
1159 */
1160 public Locator getDocumentLocator() {
1161 return currentLocator;
1162 }
1163 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import org.jdom.JDOMFactory;
57
58 /**
59 * Provides SAXBuilder with SAXHandler instances to support SAX parsing. Users
60 * wanting to customise the way that JDOM processes the SAX events should
61 * override the {@link SAXHandler} class, and then use an implementation of this
62 * factory to feed instances of that new class to SAXBuilder.
63 *
64 * @see SAXHandler
65 * @see org.jdom.input.sax
66 * @author Rolf Lear
67 */
68 public interface SAXHandlerFactory {
69 /**
70 * Create a new SAXHandler instance for SAXBuilder to use.
71 *
72 * @param factory
73 * The {@link JDOMFactory} to use for creating JDOM content.
74 * @return a new instance of a SAXHandler (or subclass) class.
75 */
76 public SAXHandler createSAXHandler(JDOMFactory factory);
77 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import org.jdom.Verifier;
57 import org.jdom.internal.ArrayCopy;
58
59 /**
60 * A non-public utility class similar to StringBuilder but optimized for XML
61 * parsing where the common case is that you get only one chunk of characters
62 * per text section. TextBuffer stores the first chunk of characters in a
63 * String, which can just be returned directly if no second chunk is received.
64 * Subsequent chunks are stored in a supplemental char array (like StringBuilder
65 * uses). In this case, the returned text will be the first String chunk,
66 * concatenated with the subsequent chunks stored in the char array. This
67 * provides optimal performance in the common case, while still providing very
68 * good performance in the uncommon case. Furthermore, avoiding StringBuilder
69 * means that no extra unused char array space will be kept around after parsing
70 * is through.
71 *
72 * @author Bradley S. Huffman
73 * @author Alex Rosen
74 */
75 final class TextBuffer {
76
77 /**
78 * The text value. Only the first <code>arraySize</code> characters are
79 * valid.
80 */
81 private char[] array = new char[1024];
82
83 /** The size of the text value. */
84 private int arraySize = 0;
85
86 /** Constructor */
87 TextBuffer() {
88 }
89
90 /**
91 * Append the specified text to the text value of this buffer.
92 *
93 * @param source
94 * The char[] data to add
95 * @param start
96 * The offset in the data to start adding from
97 * @param count
98 * The number of chars to add.
99 */
100 void append(final char[] source, final int start, final int count) {
101 if ((count + arraySize) > array.length) {
102 // Fixes #112
103 array = ArrayCopy.copyOf(array, count + arraySize + (array.length >> 2));
104 }
105 System.arraycopy(source, start, array, arraySize, count);
106 arraySize += count;
107 }
108
109 /**
110 * Clears the text value and prepares the TextBuffer for reuse.
111 */
112 void clear() {
113 arraySize = 0;
114 }
115
116 /**
117 * Inspects the character data for non-whitespace
118 *
119 * @return true if all chars are whitespace
120 */
121 boolean isAllWhitespace() {
122 int i = arraySize;
123 while (--i >= 0) {
124 if (!Verifier.isXMLWhitespace(array[i])) {
125 return false;
126 }
127 }
128 return true;
129 }
130
131 /** Returns the text value stored in the buffer. */
132 @Override
133 public String toString() {
134 if (arraySize == 0) {
135 return "";
136 }
137 return String.valueOf(array, 0, arraySize);
138 }
139
140 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import javax.xml.parsers.ParserConfigurationException;
57 import javax.xml.parsers.SAXParserFactory;
58
59 import org.xml.sax.SAXException;
60 import org.xml.sax.XMLReader;
61
62 import org.jdom.JDOMException;
63
64 /**
65 * Create XMLReaders directly from the javax.xml.parsers.SAXParserFactory API using an explicit
66 * implementation of the parser instead of relying on the default JAXP search path.
67 * <p>
68 * If you want to rely on the default JAXP search mechanism you should instead use one of the simple
69 * members of the {@link XMLReaders} enumeration, or use one of the simple constructors on
70 * {@link XMLReaderXSDFactory} or {@link XMLReaderSchemaFactory}.
71 * <p>
72 * See the documentation for {@link SAXParserFactory} for the details on what the factoryClassName
73 * and classLoader should be.
74 *
75 * @see org.jdom.input.sax
76 * @since 2.0.3
77 * @author Rolf Lear
78 */
79 public class XMLReaderJAXPFactory implements XMLReaderJDOMFactory {
80
81 private final SAXParserFactory instance;
82 private final boolean validating;
83
84 /**
85 * Create an XMLReaderJAXPFactory using the specified factory name, classloader, and
86 * dtdvalidating flag.
87 * @param factoryClassName The name of the implementation to use for the SAXParserFactory.
88 * @param classLoader The classloader to use for locating the SAXParserFactory (may be null).
89 * @param dtdvalidate Whether this should create DTD Validating XMLReaders.
90 */
91 public XMLReaderJAXPFactory(final String factoryClassName, final ClassLoader classLoader,
92 boolean dtdvalidate) {
93 instance = SAXParserFactory.newInstance(factoryClassName, classLoader);
94 instance.setNamespaceAware(true);
95 instance.setValidating(dtdvalidate);
96 validating = dtdvalidate;
97 }
98
99 @Override
100 public XMLReader createXMLReader() throws JDOMException {
101 try {
102 return instance.newSAXParser().getXMLReader();
103 } catch (SAXException e) {
104 throw new JDOMException(
105 "Unable to create a new XMLReader instance", e);
106 } catch (ParserConfigurationException e) {
107 throw new JDOMException(
108 "Unable to create a new XMLReader instance", e);
109 }
110 }
111
112 @Override
113 public boolean isValidating() {
114 return validating;
115 }
116
117 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import org.xml.sax.XMLReader;
57
58 import org.jdom.JDOMException;
59 import org.jdom.input.SAXBuilder;
60
61 /**
62 * This interface can be used to supply custom XMLReaders to {@link SAXBuilder}.
63 * <p>
64 * See the {@link org.jdom.input.sax package documentation} for details on what
65 * XMLReaderJDOMFactory implementations are available and when they are
66 * recommended.
67 *
68 * @see org.jdom.input.sax
69 * @author Rolf Lear
70 */
71 public interface XMLReaderJDOMFactory {
72 /**
73 * Return a new XMLReader according to the implementation of this
74 * XMLReaderJDOMFactory instance. The XMLReader is expected to be a new
75 * instance that is unrelated to any other XMLReaders, and can be reused at
76 * will by {@link SAXBuilder}.
77 *
78 * @return a new XMLReader
79 * @throws JDOMException
80 * if an XMLReader was not available.
81 */
82 public XMLReader createXMLReader() throws JDOMException;
83
84 /**
85 * Does an XMLReader from this factory do more than just well-formed checks.
86 *
87 * @return true if the XMLReader validates
88 */
89 public boolean isValidating();
90 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import static org.jdom.JDOMConstants.*;
57
58 import org.xml.sax.SAXException;
59 import org.xml.sax.XMLReader;
60 import org.xml.sax.helpers.XMLReaderFactory;
61
62 import org.jdom.JDOMException;
63
64 /**
65 * Create XMLReaders directly from the SAX2.0 API using a SAX Driver class name
66 * or the default SAX2.0 location process.
67 * <p>
68 * Unless you have good reason to use this mechanism you should rather use the
69 * JAXP-based processes. Read the {@link org.jdom.input.sax package
70 * documentation} for other alternatives.
71 *
72 * @see org.jdom.input.sax
73 * @author Rolf Lear
74 */
75 public class XMLReaderSAX2Factory implements XMLReaderJDOMFactory {
76
77 private final boolean validate;
78 private final String saxdriver;
79
80 /**
81 * The required details for SAX2.0-based XMLReader creation.
82 *
83 * @param validate
84 * whether to validate against the DocType
85 * @see XMLReaders#NONVALIDATING
86 * @see XMLReaders#DTDVALIDATING
87 * @see XMLReaders#XSDVALIDATING
88 */
89 public XMLReaderSAX2Factory(boolean validate) {
90 this(validate, null);
91 }
92
93 /**
94 * The required details for SAX2.0-based XMLReader creation.
95 *
96 * @param validate
97 * whether to validate against the DocType
98 * @param saxdriver
99 * The SAX2.0 Driver classname (null to use the SAX2.0 default parser
100 * searching algorithm - if you specify null you should probably be
101 * using JAXP anyway).
102 * @see XMLReaders#NONVALIDATING
103 * @see XMLReaders#DTDVALIDATING
104 * @see XMLReaders#XSDVALIDATING
105 */
106 public XMLReaderSAX2Factory(final boolean validate, final String saxdriver) {
107 super();
108 this.validate = validate;
109 this.saxdriver = saxdriver;
110 }
111
112 @Override
113 public XMLReader createXMLReader() throws JDOMException {
114 try {
115 XMLReader reader = saxdriver == null
116 ? XMLReaderFactory.createXMLReader()
117 : XMLReaderFactory.createXMLReader(saxdriver);
118 reader.setFeature(
119 SAX_FEATURE_VALIDATION, validate);
120 // Setup some namespace features.
121 reader.setFeature(
122 SAX_FEATURE_NAMESPACES, true);
123 reader.setFeature(
124 SAX_FEATURE_NAMESPACE_PREFIXES, true);
125
126 return reader;
127 } catch (SAXException e) {
128 throw new JDOMException("Unable to create SAX2 XMLReader.", e);
129 }
130
131 }
132
133 /**
134 * Get the SAX Driver class name used to boostrap XMLReaders.
135 *
136 * @return The name of the SAX Driver class (null for SAX2 default class).
137 */
138 public String getDriverClassName() {
139 return saxdriver;
140 }
141
142 @Override
143 public boolean isValidating() {
144 return validate;
145 }
146
147 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import javax.xml.parsers.SAXParserFactory;
57 import javax.xml.validation.Schema;
58
59 /**
60 * This {@link XMLReaderJDOMFactory} class returns XMLReaders configured to
61 * validate against the supplied Schema instance. The Schema could be an XSD
62 * schema or some other schema supported by SAX (e.g. RelaxNG). The SAX Parser
63 * is obtained through the JAXP process.
64 * <p>
65 * If you want to validate an XML document against the XSD references embedded
66 * in the XML itself (xsdSchemaLocation) then you do not want to use this class
67 * but rather use an alternate means like
68 * {@link XMLReaders#XSDVALIDATING}.
69 * <p>
70 * See the {@link org.jdom.input.sax package documentation} for the best
71 * alternatives.
72 *
73 * @see org.jdom.input.sax
74 * @author Rolf Lear
75 */
76 public class XMLReaderSchemaFactory extends AbstractReaderSchemaFactory {
77
78 /**
79 * XMLReader instances from this class will be configured to validate using
80 * the supplied Schema instance.
81 *
82 * @param schema
83 * The Schema to use for validation.
84 */
85 public XMLReaderSchemaFactory(final Schema schema) {
86 super(SAXParserFactory.newInstance(), schema);
87 }
88
89 /**
90 * XMLReader instances from this class will be configured to validate using
91 * the supplied Schema instance, and use the specified JAXP SAXParserFactory.
92 *
93 * @param factoryClassName The name of the SAXParserFactory class to use
94 * @param classloader The classLoader to use for loading the SAXParserFactory.
95 * @param schema
96 * The Schema to use for validation.
97 * @since 2.0.3
98 */
99 public XMLReaderSchemaFactory(final String factoryClassName, final ClassLoader classloader,
100 final Schema schema) {
101 super(SAXParserFactory.newInstance(factoryClassName, classloader), schema);
102 }
103
104 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import java.io.File;
57 import java.net.URL;
58
59 import javax.xml.XMLConstants;
60 import javax.xml.parsers.SAXParserFactory;
61 import javax.xml.transform.Source;
62 import javax.xml.validation.SchemaFactory;
63
64 import org.jdom.JDOMException;
65
66 /**
67 * This XMLReaderJDOMFactory class returns XMLReaders configured to validate
68 * against the supplied XML Schema (XSD) instance. The SAX Parser is obtained through
69 * the JAXP process.
70 *
71 * <p>
72 * This class has var-arg constructors, accepting potentially many XSD sources.
73 * It is just as simple though to have a single source:
74 *
75 * <pre>
76 * File xsdfile = new File(&quot;schema.xsd&quot;);
77 * XMLReaderJDOMFactory schemafac = new XMLReaderXSDFactory(xsdfile);
78 * SAXBuilder builder = new SAXBuilder(schemafac);
79 * File xmlfile = new File(&quot;data.xml&quot;);
80 * Document validdoc = builder.build(xmlfile);
81 * </pre>
82 *
83 * @see org.jdom.input.sax
84 * @author Rolf Lear
85 */
86 public class XMLReaderXSDFactory extends AbstractReaderXSDFactory {
87
88 private static final SchemaFactoryProvider xsdschemas = new SchemaFactoryProvider() {
89 /**
90 * Use a Thread-Local system to manage SchemaFactory. SchemaFactory is not
91 * thread-safe, so we need some mechanism to isolate it, and thread-local is
92 * a logical way because it only creates an instance when needed in each
93 * thread, and they die when the thread dies. Does not need any
94 * synchronisation either.
95 */
96 private final ThreadLocal<SchemaFactory> schemafactl = new ThreadLocal<SchemaFactory>();
97
98 @Override
99 public SchemaFactory getSchemaFactory() {
100 SchemaFactory sfac = schemafactl.get();
101 if (sfac == null) {
102 sfac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
103 schemafactl.set(sfac);
104 }
105 return sfac;
106 }
107 };
108
109
110 /**
111 * Create an XML Schema validating XMLReader factory using one or more XSD
112 * sources from SystemID references.
113 *
114 * @param systemid
115 * The var-arg array of at least one SystemID reference (URL) to
116 * locate the XSD's used to validate
117 * @throws JDOMException
118 * If the Schemas could not be loaded from the SystemIDs This will
119 * wrap a SAXException that contains the actual fault.
120 */
121 public XMLReaderXSDFactory(String... systemid)
122 throws JDOMException {
123 super(SAXParserFactory.newInstance(), xsdschemas, systemid);
124 }
125
126 /**
127 * Create an XML Schema validating XMLReader factory using one or more XSD
128 * sources from SystemID references, and use the specified JAXP SAXParserFactory.
129 *
130 * @param factoryClassName The name of the SAXParserFactory class to use
131 * @param classloader The classLoader to use for loading the SAXParserFactory.
132 * @param systemid
133 * The var-arg array of at least one SystemID reference (URL) to
134 * locate the XSD's used to validate
135 * @throws JDOMException
136 * If the Schemas could not be loaded from the SystemIDs This will
137 * wrap a SAXException that contains the actual fault.
138 * @since 2.0.3
139 */
140 public XMLReaderXSDFactory(final String factoryClassName, final ClassLoader classloader,
141 final String... systemid) throws JDOMException {
142 super(SAXParserFactory.newInstance(factoryClassName, classloader), xsdschemas, systemid);
143 }
144
145 /**
146 * Create an XML Schema validating XMLReader factory using one or more XSD
147 * sources from URL references.
148 *
149 * @param systemid
150 * The var-arg array of at least one SystemID reference (URL) to
151 * locate the XSD's used to validate
152 * @throws JDOMException
153 * If the Schemas could not be loaded from the SystemIDs This will
154 * wrap a SAXException that contains the actual fault.
155 */
156 public XMLReaderXSDFactory(URL... systemid) throws JDOMException {
157 super(SAXParserFactory.newInstance(), xsdschemas, systemid);
158 }
159
160 /**
161 * Create an XML Schema validating XMLReader factory using one or more XSD
162 * sources from URL references, and use the specified JAXP SAXParserFactory.
163 *
164 * @param factoryClassName The name of the SAXParserFactory class to use
165 * @param classloader The classLoader to use for loading the SAXParserFactory.
166 * @param systemid
167 * The var-arg array of at least one SystemID reference (URL) to
168 * locate the XSD's used to validate
169 * @throws JDOMException
170 * If the Schemas could not be loaded from the SystemIDs This will
171 * wrap a SAXException that contains the actual fault.
172 * @since 2.0.3
173 */
174 public XMLReaderXSDFactory(final String factoryClassName, final ClassLoader classloader,
175 URL... systemid) throws JDOMException {
176 super(SAXParserFactory.newInstance(factoryClassName, classloader), xsdschemas, systemid);
177 }
178
179 /**
180 * Create an XML Schema validating XMLReader factory using one or more XSD
181 * sources from File references.
182 *
183 * @param systemid
184 * The var-arg array of at least one SystemID reference (File) to
185 * locate the XSD's used to validate
186 * @throws JDOMException
187 * If the Schemas could not be loaded from the SystemIDs This will
188 * wrap a SAXException that contains the actual fault.
189 */
190 public XMLReaderXSDFactory(File... systemid) throws JDOMException {
191 super(SAXParserFactory.newInstance(), xsdschemas, systemid);
192 }
193
194 /**
195 * Create an XML Schema validating XMLReader factory using one or more XSD
196 * sources from File references, and use the specified JAXP SAXParserFactory.
197 *
198 * @param factoryClassName The name of the SAXParserFactory class to use
199 * @param classloader The classLoader to use for loading the SAXParserFactory.
200 * @param systemid
201 * The var-arg array of at least one SystemID reference (File) to
202 * locate the XSD's used to validate
203 * @throws JDOMException
204 * If the Schemas could not be loaded from the SystemIDs This will
205 * wrap a SAXException that contains the actual fault.
206 * @since 2.0.3
207 */
208 public XMLReaderXSDFactory(final String factoryClassName, final ClassLoader classloader,
209 File... systemid) throws JDOMException {
210 super(SAXParserFactory.newInstance(factoryClassName, classloader), xsdschemas, systemid);
211 }
212
213 /**
214 * Create an XML Schema validating XMLReader factory using one or more XSD
215 * sources from Transform Source references.
216 *
217 * @param sources
218 * The var-arg array of at least one transform Source reference to
219 * locate the XSD's used to validate
220 * @throws JDOMException
221 * If the Schemas could not be loaded from the Sources This will
222 * wrap a SAXException that contains the actual fault.
223 */
224 public XMLReaderXSDFactory(Source... sources) throws JDOMException {
225 super(SAXParserFactory.newInstance(), xsdschemas, sources);
226 }
227
228 /**
229 * Create an XML Schema validating XMLReader factory using one or more XSD
230 * sources from Transform Source references, and use the specified JAXP SAXParserFactory.
231 *
232 * @param factoryClassName The name of the SAXParserFactory class to use
233 * @param classloader The classLoader to use for loading the SAXParserFactory.
234 * @param sources
235 * The var-arg array of at least one transform Source reference to
236 * locate the XSD's used to validate
237 * @throws JDOMException
238 * If the Schemas could not be loaded from the Sources This will
239 * wrap a SAXException that contains the actual fault.
240 * @since 2.0.3
241 */
242 public XMLReaderXSDFactory(final String factoryClassName, final ClassLoader classloader,
243 Source... sources) throws JDOMException {
244 super(SAXParserFactory.newInstance(factoryClassName, classloader), xsdschemas, sources);
245 }
246
247 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.sax;
55
56 import javax.xml.XMLConstants;
57 import javax.xml.parsers.ParserConfigurationException;
58 import javax.xml.parsers.SAXParserFactory;
59 import javax.xml.validation.Schema;
60 import javax.xml.validation.SchemaFactory;
61
62 import org.xml.sax.SAXException;
63 import org.xml.sax.XMLReader;
64
65 import org.jdom.JDOMException;
66
67 /**
68 * An enumeration of {@link XMLReaderJDOMFactory} that allows for a single
69 * central location to create XMLReaders. The Singletons (members) of this
70 * enumeration can produce the most common XMLReaders: non-validating, XSD
71 * validating, and DocType validating.
72 * <p>
73 * See the {@link org.jdom.input.sax package documentation} for details of how
74 * to create the SAXParser you desire.
75 *
76 * @see org.jdom.input.sax
77 * @author Rolf Lear
78 */
79 public enum XMLReaders implements XMLReaderJDOMFactory {
80
81 /**
82 * The non-validating singleton
83 */
84 NONVALIDATING(0),
85
86 /**
87 * The DTD-validating Singleton
88 */
89 DTDVALIDATING(1),
90
91 /**
92 * The XSD-validating Singleton
93 */
94 XSDVALIDATING(2);
95
96 private interface FactorySupplier {
97 SAXParserFactory supply() throws Exception;
98
99 boolean validates();
100 }
101
102 private enum NONSingleton implements FactorySupplier {
103 INSTANCE;
104
105 private final SAXParserFactory factory;
106
107 NONSingleton() {
108 SAXParserFactory fac = SAXParserFactory.newInstance();
109 // All JDOM parsers are namespace aware.
110 fac.setNamespaceAware(true);
111 fac.setValidating(false);
112 factory = fac;
113 }
114
115 @Override
116 public SAXParserFactory supply() throws Exception {
117 return factory;
118 }
119
120 @Override
121 public boolean validates() {
122 return false;
123 }
124
125 }
126
127 private enum DTDSingleton implements FactorySupplier {
128 INSTANCE;
129
130 private final SAXParserFactory factory;
131
132 DTDSingleton() {
133 SAXParserFactory fac = SAXParserFactory.newInstance();
134 // All JDOM parsers are namespace aware.
135 fac.setNamespaceAware(true);
136 // factory is validating (DTD)
137 fac.setValidating(true);
138 factory = fac;
139 }
140
141 @Override
142 public SAXParserFactory supply() throws Exception {
143 return factory;
144 }
145
146 @Override
147 public boolean validates() {
148 return true;
149 }
150
151 }
152
153 private enum XSDSingleton implements FactorySupplier {
154 INSTANCE;
155
156 private final Exception failcause;
157 private final SAXParserFactory factory;
158
159 XSDSingleton() {
160
161 SAXParserFactory fac = SAXParserFactory.newInstance();
162 Exception problem = null;
163 // All JDOM parsers are namespace aware.
164 fac.setNamespaceAware(true);
165 // factory is not validating (DTD), but the Reader is validating
166 // (XSD)
167 fac.setValidating(false);
168
169 try {
170 SchemaFactory sfac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
171 Schema schema = sfac.newSchema();
172 fac.setSchema(schema);
173 } catch (SAXException se) {
174 // we could not get a validating system, set the fac to null
175 fac = null;
176 problem = se;
177 } catch (IllegalArgumentException iae) {
178 // this system does not support XSD Validation.... which is true
179 // for android!
180 // we could not get a validating system, set the fac to null
181 fac = null;
182 problem = iae;
183 } catch (UnsupportedOperationException uoe) {
184 // SAXParserFactory throws this exception when setSchema is
185 // called.
186 // Therefore every factory throws this exception unless it
187 // overrides
188 // setSchema. A popular example is Apache Xerces
189 // SAXParserFactoryImpl
190 // before version 2.7.0.
191 fac = null;
192 problem = uoe;
193 }
194 factory = fac;
195 failcause = problem;
196
197 }
198
199 @Override
200 public SAXParserFactory supply() throws Exception {
201 if (factory == null) {
202 throw failcause;
203 }
204 return factory;
205 }
206
207 @Override
208 public boolean validates() {
209 return true;
210 }
211
212 };
213
214 /** the actual SAXParserFactory in the respective singletons. */
215 private final int singletonID;
216
217 /** Private constructor */
218 private XMLReaders(int singletonID) {
219 this.singletonID = singletonID;
220 }
221
222 private FactorySupplier getSupplier() {
223 switch (singletonID) {
224 case 0:
225 return NONSingleton.INSTANCE;
226 case 1:
227 return DTDSingleton.INSTANCE;
228 case 2:
229 return XSDSingleton.INSTANCE;
230 }
231 throw new IllegalStateException("Unknown singletonID: " + singletonID);
232 }
233
234 /**
235 * Get a new XMLReader from this JAXP-based {@link XMLReaderJDOMFactory}.
236 * <p>
237 *
238 * @return a new XMLReader instance.
239 * @throws JDOMException
240 * if there is a problem creating the XMLReader
241 */
242 @Override
243 public XMLReader createXMLReader() throws JDOMException {
244 try {
245 FactorySupplier supplier = getSupplier();
246 return supplier.supply().newSAXParser().getXMLReader();
247 } catch (SAXException e) {
248 throw new JDOMException(
249 "Unable to create a new XMLReader instance", e);
250 } catch (ParserConfigurationException e) {
251 throw new JDOMException(
252 "Unable to create a new XMLReader instance", e);
253 } catch (Exception e) {
254 throw new JDOMException("It was not possible to configure a "
255 + "suitable XMLReader to support " + this, e);
256 }
257 }
258
259 @Override
260 public boolean isValidating() {
261 return getSupplier().validates();
262 }
263
264 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 /**
55 Support classes for building JDOM documents and content using SAX parsers.
56
57 <h2>Introduction</h2>
58 Skip to the <a href="#Examples">Examples</a> section for a quick bootstrap.
59 <p>
60 The {@link org.jdom.input.SAXBuilder} class parses input and produces JDOM
61 output. It does this using three 'pillars' of functionality, which when combined
62 constitute a 'parse'.
63 <p>
64 The three pillars are:
65 <ol>
66 <li>The SAX Parser - this is a 'third-party' parser such as Xerces.
67 <li>The SAX Event Handler - which reads the data produced by the parser
68 <li>The JDOMFactory - which converts the resulting data in to JDOM content
69 </ol>
70 There are many different ways of parsing the document from its input state
71 (DocType-validating, etc.), and there are also different ways to interpret
72 the SAX events. Finally there are different ways to produce JDOM Content using
73 different implementations of the JDOMFactory.
74 <p>
75 SAXBuilder provides a central location where these three pillars are configured.
76 Some configuration settings require coordinated changes to both the SAX parser
77 and the SAX handler, and SAXBuilder ensures the coordination is maintained.
78
79 <h2>Setting the Pillars</h2>
80 SAXBuilder provides a number of different mechanisms for stipulating what the
81 three pillars will be:
82 <ul>
83 <li>A Constructor: {@link org.jdom.input.SAXBuilder#SAXBuilder(XMLReaderJDOMFactory, SAXHandlerFactory, org.jdom.JDOMFactory)}
84 <li>A default constructor {@link org.jdom.input.SAXBuilder#SAXBuilder()}
85 that chooses a non-validating JAXP sourced XMLReader Factory
86 {@link org.jdom.input.sax.XMLReaders#NONVALIDATING} which it
87 mates with a Default {@link org.jdom.input.sax.SAXHandler} factory, and the
88 {@link org.jdom.DefaultJDOMFactory}.
89 <li>A number of other constructors that are mostly for backward-compatibility
90 with JDOM 1.x. These other constructors affect what
91 {@link org.jdom.input.sax.XMLReaderJDOMFactory} will be used but still use
92 the default SAXHandler and JDOMFactory values.
93 <li>Methods to change whatever was constructed:
94 <ul>
95 <li>{@link org.jdom.input.SAXBuilder#setXMLReaderFactory(XMLReaderJDOMFactory)}
96 <li>{@link org.jdom.input.SAXBuilder#setSAXHandlerFactory(SAXHandlerFactory)}
97 <li>{@link org.jdom.input.SAXBuilder#setJDOMFactory(org.jdom.JDOMFactory)}
98 </ul>
99 </ul>
100
101
102 <h2>The XMLReaderJDOMFactory Pillar</h2>
103
104 A brief history of XML Parsers in Java:<br>
105 XML Parsers have been available in Java from essentially 'the beginning'. There
106 have been a number different ways to access these parsers though:
107 <ol>
108 <li>Create the parser directly 'by name'.
109 <li>Use the SAX (and later the SAX 2.0) API to locate a parser.
110 <li>Use JAXP (versions 1, through 1.4) API to locate a parser.
111 </ol>
112 <p>
113 In addition to the different ways of creating an XML parser, there have also
114 been updates to the way the actual SAX parsing API is exposed to Java (the Java
115 interface). The SAX specification was revised with version 2.0. The 'new' SAX
116 version introduced the XMLReader concept, which replaces the XMLParser concept.
117 These two concepts aim to accomplish the same goal, but do it in different
118 ways.
119 <p>
120 JDOM 2.x requires an XMLReader (SAX 2.0) interface, thus your XML parser needs
121 to be compatible with SAX 2.0 (for the XMLReader), but should be accessible
122 through JAXP which is the more modern and flexible access system.
123 <p>
124 The purpose of the XMLReaderJDOMFactory Pillar is to give the SAXBuilder an
125 XMLReader instance (a SAX 2.0 parser). To get an XMLReader the
126 SAXBuilder delegates to the {@link org.jdom.input.sax.XMLReaderJDOMFactory}
127 by calling {@link org.jdom.input.sax.XMLReaderJDOMFactory#createXMLReader()}
128 <p>
129 XMLReader instances can be created in a few different ways, and also they
130 can be set to perform the SAX parse in a number of different ways. The classes
131 in this package are designed to make it easier and faster to locate the XMLReader
132 that is suitable for the XML parsing you intend to do. At the same time, if the
133 parsing you intend to do is outside the normal bounds of how JDOM is used, you
134 still have the functionality to create a completely custom mechanism for setting
135 the XMLReader for SAXBuilder.
136 <p>
137 There are two typical ways to specify and create an XMLReader
138 instance: using JAXP, and using the SAX2.0 API. If necessary you can also create
139 direct instances of XMLReader implementations using 'new' constructors, but
140 each SAX implementation has different class names for their SAX drivers so doing
141 raw constructors is not portable and not recommended.
142 <p>
143 Where possible it is recommended that you use the JAXP mechanism for obtaining
144 XMLReaders because:
145 <ul>
146 <li>It is more 'modern'.
147 <li>It provides a more consistent interface to different SAX implementations
148 <li>It provides cleaner and more portable support for validating using the
149 {@link javax.xml.validation.Validator} mechanisms.
150 <li>It allows you to create differently-configured 'factories' that
151 create XMLReaders in a pre-specified format (SAX2.0 has a single global
152 factory that creates raw XMLReader instances that then need to be
153 re-configured for your task).
154 </ul>
155
156 <h3>JAXP Factories</h3>
157 JDOM exposes six factories that use JAXP to source XMLReaders. These factories
158 cover almost all conditions under which you would want a SAX parser:
159 <ol>
160 <li>A simple non-validating SAX parser
161 <li>A validating parser that uses the DOCTYPE references in the XML to validate
162 against.
163 <li>A validating parser that uses the XML Schema (XSD) references embedded in
164 the XML to validate against.
165 <li>A factory that uses a specific JAXP-based parser that can optionally
166 validate using the DTD DocType.
167 <li>A validating parser that uses an external Schema (XML Schema, Relax NG,
168 etc.) to validate the XML against.
169 <li>A special case of the Schema-validating factory that specialises in XML
170 Schema (XSD) validation and provides an easy way to create validating
171 XMLReaders based on single or multiple input XSD documents.
172 </ol>
173 The first three are all relatively simple, and are available as members of the
174 {@link org.jdom.input.sax.XMLReaders} enumeration. These members
175 are 'singletons' that can be used in a multi-threaded and concurrent way to
176 provide XMLReaders that are configured correctly for the respective behaviour.
177 <p>
178 To parse with a specific (rather than the default) JAXP-based XML Parser
179 you can use the {@link org.jdom.input.sax.XMLReaderJAXPFactory}. This factory
180 can optionally be set to do DTD validation during the parse.
181 <p>
182 To validate using an arbitrary external Schema you can use the
183 {@link org.jdom.input.sax.XMLReaderSchemaFactory} to create an instance for
184 the particular Schema you want to validate against. Because this requires an
185 input Schema it cannot be constructed as a singleton like the others. There
186 are constructors that allow you to use a specific (rather than the default)
187 JAXP-compatible parser.
188 <p>
189 {@link org.jdom.input.sax.XMLReaderXSDFactory} is a special case of
190 XMLReaderSchemaFactory which internally uses an efficient mechanism to
191 compile Schema instances from one or many input XSD documents which can come
192 from multiple sources. There are constructors that allow you to use a specific
193 (rather than the default) JAXP-compatible parser.
194
195 <h3>SAX 2.0 Factory</h3>
196
197 JDOM supports using the SAX 2.0 API for creating XMLReaders through using
198 either the 'default' SAX 2.0 implementation or a particular SAX Driver class.
199 SAX2.0 support is available by creating instances of the
200 {@link org.jdom.input.sax.XMLReaderSAX2Factory} class.
201 <p>
202 It should be noted that it is preferable to use JAXP in JDOM because it is a
203 more flexible API that allows more portable code to be created. The JAXP
204 interface in JDOM is also able to support a wider array of functionality
205 out-of-the-box, but the same functionality would require SAX-implementation
206 specific configuration.
207 <p>
208 JDOM does not provide a pre-configured way to do XML Schema validation through
209 the SAX2.0 API though. The SAX 2.0 API does not expose a convenient way to
210 configure different SAX implementations in a consistent way, so it is up to the
211 JDOM user to wrap the XMLReaderSAX2Factory in such a way that it reconfigures
212 the XMLReader to be appropriate for the task at hand.
213
214 <h3>Custom Factories</h3>
215 If your circumstances require it you can create your own implementation of the
216 {@link org.jdom.input.sax.XMLReaderJDOMFactory} to provide XMLReaders configured
217 as you like them. It will probably be best if you wrap an existing implementation
218 with your custom code though in order to get the best results fastest.
219 <p>
220 Note that the existing JDOM implementations described above all set the
221 generated XMLReaders to be namespace-aware and to supply namespace-prefixes.
222 Custom implementations should also ensure that this is set unless you absolutely
223 know what you are doing.
224
225
226 <h2>The SAXHandlerFactory Pillar</h2>
227
228 The SAXHandler interprets the SAX calls and provides the information to the
229 JDOMFactory to create JDOM content. SAXBuilder creates a SAXHandler from the
230 {@link org.jdom.input.sax.SAXHandlerFactory} pillar. It is unusual for a JDOM
231 user to need to customise the manner in which this happens, but, in the event
232 that you do you can create a subclass of the SAXHandler class, and then create
233 an instance of the SAXHandlerFactory that returns new subclass instances.
234 This new factory can become a pillar in SAXBuilder and supply custom SAXHandlers
235 to the parse process.
236
237
238 <h2>The JDOMFactory Pillar</h2>
239
240 There are a couple of reasons for changing the JDOMFactory pillar in SAXBuilder.
241 The default JDOMFactory used is the {@link org.jdom.DefaultJDOMFactory}. This
242 factory validates the values being used to create JDOM content. There is also
243 the {@link org.jdom.UncheckedJDOMFactory} which does not validate the data, so
244 it should only be used if you are absolutely certain that your SAX source can
245 never provide illegal content. You may have other reasons for creating a custom
246 JDOMFactory such as if you need to create custom versions of JDOM Content like
247 a custom Element subclass.
248
249 <h2>Configuring the Pillars</h2>
250
251 The JDOMFactory pillar is not configurable; you can only replace it entirely.
252 The other two pillars are configurable though, but you should inspect the
253 getters and setters on {@link org.jdom.input.SAXBuilder} to identify what can
254 (by default) be changed easily. Remember, if you have anything that needs to be
255 customised beyond what SAXBuilder offers you can always replace a pillar with a
256 custom implementation.
257
258 <h2>Execution Model</h2>
259 Once all the pillars are set and configured to your satisfaction you can 'build'
260 a JDOM Document from a source. The actual parse process consists of a 'setup',
261 'parse', and 'reset' phase.
262 <p>
263 The setup process involves obtaining an XMLReader from the XMLReaderJDOMFactory
264 and a SAXHandler (configured to use the JDOMFactory) from the SAXHandlerFactory.
265 These two instances are then configured to meet the settings specified on
266 SAXBuilder, and once configured they are 'compiled' in to a SAXBuilderEngine.
267 <p>
268 The SAXBuilderEngine is a non-configurable 'embodiment' of the configuration of
269 the SAXBuilder when the engine was created, and it contains the entire
270 'workflow' necessary to parse the input in to JDOM content. Further, it is a
271 guarantee that the XMLReader and SAXHandler instances in the SAXBuilderEngine
272 are never shared with any other engine or entity (assuming that the respective
273 factories never issue the same instances multiple times). There is no guarantee
274 made for the JDOMFactory being unique for each SAXBuilderEngine, but JDOMFactory
275 instances are supposed to be reentrant/thread-safe.
276 <p>
277 The 'parse' phase starts once the setup phase is complete and the
278 SAXBuilderEngine has been created. The created engine is used to parse the input,
279 and the resulting Document is returned to the client.
280 <p>
281 The 'reset' phase happens after the completion of the 'parse' phase, and it
282 resets the SAXBuilderEngine to its initial state, ready to process the next
283 parse request.
284
285 <h2>Parser Reuse</h2>
286 A large amount of the effort involved in parsing the document is actually the
287 creation of the XMLReader and the SAXHandler instances, as well as applying the
288 configuration to those instances (the 'setup' phase).
289 <p>
290 JDOM2 uses the new SAXBuilderEngine to represent the state of the SAXBuilder
291 at the moment prior to the parse. SAXBuilder will then 'remember' and reuse this
292 exact SAXBuilderEngine until something changes in the SAXBuilder configuration.
293 As soon as the configuration changes in any way the engine will be forgotten and
294 a new one will be created when the SAXBuilder next parses a document.
295 <p>
296 If you turn off parser reuse with
297 {@link org.jdom.input.SAXBuilder#setReuseParser(boolean)} then SAXBuilder will
298 immediately forget the engine, and it will also forget it after each build (i.e.
299 SAXBuilder will create a new SAXBuilderEngine each parse).
300 <p>
301 It follows then that as long as you do not change the SAXBuilder configuration
302 then the SAXBuilder will always reuse the same SAXBuilderEngine. This is very
303 efficient because there is no configuration management between parses, and the
304 procedure completely eliminates the 'setup' component for all but the first
305 parse.
306
307 <h2>Parser Pooling</h2>
308 In order to facilitate Parser pooling it is useful to export the
309 SAXBuilderEngine as a stand-alone reusable parser. At any time you can call
310 {@link org.jdom.input.SAXBuilder#buildEngine()} and you can get a newly
311 created SAXBuilderEngine instance. The SAXBuilderEngine has the same 'build'
312 methods as SAXBuilder, and these are exposed as the
313 {@link org.jdom.input.sax.SAXEngine} interface. Both SAXBuilder and
314 SAXBuilderEngine implement the SAXEngine interface. Thus, if you use Parser
315 pools you can pool either the SAXBuilder or the SAXBuilderEngine in the same
316 pool.
317 <p>
318 It is most likely though that what you will want to do is to create a single
319 SAXBuilder that represents the configuration you want, and then you can use this
320 single SAXBuilder to create multiple SAXEngines as you need them in the pool by
321 calling the <code>buildEngine()</code> method.
322
323 <h2>Examples</h2>
324 <a name="Examples" />
325 Create a simple SAXBuilder and parse a document:
326 <p>
327 <pre>
328 SAXBuilder sb = new SAXBuilder();
329 Document doc = sb.build(new File("file.xml"));
330 </pre>
331 <p>
332 Create a DTD validating SAXBuilder and parse a document:
333 <p>
334 <pre>
335 SAXBuilder sb = new SAXBuilder(XMLReaders.DTDVALIDATING);
336 Document doc = sb.build(new File("file.xml"));
337 </pre>
338 Create an XSD (XML Schema) validating SAXBuilder using the XSD references inside
339 the XML document and parse a document:
340 <p>
341 <pre>
342 SAXBuilder sb = new SAXBuilder(XMLReaders.XSDVALIDATING);
343 Document doc = sb.build(new File("file.xml"));
344 </pre>
345 <p>
346 Create an XSD (XML Schema) validating SAXBuilder the hard way (see the next
347 example for an easier way) using an external XSD and parse a document
348 (see {@link org.jdom.input.sax.XMLReaderSchemaFactory}):
349 <p>
350 <pre>
351 SchemaFactory schemafac =
352 SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
353 Schema schema = schemafac.newSchema(new File("myschema.xsd"));
354 XMLReaderJDOMFactory factory = new XMLReaderSchemaFactory(schema);
355 SAXBuilder sb = new SAXBuilder(factory);
356 Document doc = sb.build(new File("file.xml"));
357 </pre>
358 <p>
359 Create an XSD (XML Schema) validating SAXBuilder the easy way
360 (see {@link org.jdom.input.sax.XMLReaderXSDFactory}):
361 <p>
362 <pre>
363 File xsdfile = new File("myschema.xsd");
364 XMLReaderJDOMFactory factory = new XMLReaderXSDFactory(xsdfile);
365 SAXBuilder sb = new SAXBuilder(factory);
366 Document doc = sb.build(new File("file.xml"));
367 </pre>
368
369 */
370 package org.jdom.input.sax;
371
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.stax;
55
56 import java.util.HashMap;
57 import java.util.regex.Matcher;
58 import java.util.regex.Pattern;
59
60 import org.jdom.DocType;
61 import org.jdom.JDOMException;
62 import org.jdom.JDOMFactory;
63
64 /**
65 * Parses out key information from a single String representing a DOCTYPE
66 * declaration. StAX parsers supply a single string representing the DOCTYPE and
67 * this needs to be processed to get items like the SystemID, etc. Additionally
68 * it needs to be reformatted to create a standardised representation.
69 * <p>
70 * The assumption is that the DTD is valid.
71 * <p>
72 * We need to pull out 4 elements of data:
73 * <ol>
74 * <li>The root element name
75 * <li>The SystemID (if available)
76 * <li>The PublicID (if available)
77 * <li>The internal subset (if available)
78 * </ol>
79 *
80 * The internal-subset should be re-formatted to conform to the JDOM 'standard'
81 * where each declaration starts on a new line indented with 2 spaces. This
82 * 'standard' is defined by the way that JDOM formats the DTD declarations in the
83 * SAX parse process, which fires individual events for the content in the DTD.
84 * <p>
85 * We can do this all with a well-structured regular expression, which is
86 * actually simpler than trying to fish out all the components ourselves....
87 * <p>
88 *
89 * @author Rolf Lear
90 *
91 */
92 public class DTDParser {
93
94 /*
95 * =======================================================================
96 *
97 * READ THIS...
98 *
99 *
100 * This code works by using a reg-ex to parse a valid DTD document.
101 * The pattern is complicated (not as complicated as an actual parser).
102 *
103 * Because the pattern is complicated, this code creates a pattern 'database'
104 * and then 'pulls' patterns from the database to create the final regex.
105 * The database patterns are pulled to transform a pattern template into a
106 * final regular expression. This template is called the 'meta-pattern'.
107 *
108 * So, the pattern is not kept in its final form, but rather it is built
109 * up at class initialization time based on the meta-pattern, and the
110 * pattern database in the map.
111 *
112 * This is the final pattern: (broken over a few lines)
113 *
114 * [\s\r\n\t]*<!DOCTYPE[\s\r\n\t]+([^\s\r\n\t\[>]+)([\s\r\n\t]+
115 * ((SYSTEM[\s\r\n\t]+(('([^']*)')|("([^"]*)")))|
116 * (PUBLIC[\s\r\n\t]+(('([^']*)')|("([^"]*)"))([\s\r\n\t]+
117 * (('([^']*)')|("([^"]*)")))?)))?([\s\r\n\t]*\[(.*)\])?
118 * [\s\r\n\t]*>[\s\r\n\t]*
119 *
120 * You will agree that it's simpler to build the pattern than to read it....
121 *
122 * With the above in mind, you can easily follow the way the pattern is
123 * built as it is simply a repeating use of some of the base constructs.
124 * =======================================================================
125 */
126
127 /**
128 * This is the meta-pattern.
129 * <p>
130 * <ul>
131 * <li>Where you see ' os ' there is optional space.
132 * <li>Where you see ' name ' there is the element name.
133 * <li>Where you see ' ms ' there is mandatory space.
134 * <li>Where you see ' id ' there is some quoted identifier.
135 * <li>Where you see ' internal ' there is the internal subset.
136 * </ul>
137 * Anything else will become part of the final regex.
138 * <p>
139 * Space ('&nbsp;') was chosen for the token delimiter because it
140 * makes the meta-pattern easy to read. There are a couple of places in
141 * this expression where there are two ' ' together, and it is critical
142 * that it does not change because there will be missed token matches then.
143 */
144 private static final String metapattern =
145 // The lead-in and the Element name
146 " os <!DOCTYPE ms ( name )" +
147 // The Public/System references, if any
148 "( ms ((SYSTEM ms id )|(PUBLIC ms id ( ms id )?)))?" +
149 // The Internal Subset, if any.
150 "( os \\[( internal )\\])?" +
151 // The lead-out.
152 " os > os ";
153
154 /**
155 * This builds a substitution map containing the raw patterns for
156 * certain types of content we expect.
157 * @return The populated map.
158 */
159 private static final HashMap<String,String> populatePatterns() {
160 HashMap<String,String> p = new HashMap<String, String>();
161 // The name is important to understand. The assumption is that the
162 // doctype is valid, hence it is easier to search for what the name is
163 // not, and not what it is. The name will be terminated with either
164 // white-space, [ or >
165 p.put("name", "[^ \\n\\r\\t\\[>]+"); // element name.
166
167 // whitespace: S ::= (#x20 | #x9 | #xD | #xA)+
168 p.put("ms", "[ \\n\\r\\t]+"); // mandatory whitespace.
169 p.put("os", "[ \\n\\r\\t]*"); // optional whitespace.
170
171 // A quoted 'id'/"id" is anything except the quote
172 // we need to do parenthesis in this to get grouping to work.
173 // also need parenthesis to make the | or condition work
174 p.put("id", "(('([^']*)')|(\"([^\"]*)\"))"); // quoted id.
175
176 // The internal subset is treated differently by the code, and the
177 // [ ] bracing around the internal subset is specified in the main regex
178 p.put("internal", ".*"); // internal subset.
179 return p;
180 }
181
182 /**
183 * This method substitutes the simple tokens in the meta-pattern with
184 * the declared values in the map.
185 * @param map The map containing substitution tokens/patterns
186 * @param input The meta-pattern to do the substitutions on.
187 * @return The substituted pattern
188 */
189 private static final Pattern buildPattern(
190 HashMap<String,String> map, String input) {
191 // we are going to search for tokens. Each token is marked by a space.
192 // space was chosen because it makes the meta-pattern easy to read.
193 final Pattern search = Pattern.compile(" (\\w+) ");
194 final Matcher mat = search.matcher(input);
195 StringBuilder sb = new StringBuilder();
196 int pos = 0;
197 while (mat.find()) {
198 String rep = map.get(mat.group(1));
199 // we wrote this, it can't happen ;-). Live with a 'null' append.
200 // if (rep == null) {
201 // throw new IllegalArgumentException(
202 // "No definition of token '" + mat.group() + "'.");
203 // }
204 // can't use appendReplacement as we have to escape '\' chars.
205 // and Pattern.quote() does not help
206 // mat.appendReplacement(sb, rep);
207 sb.append(input.substring(pos, mat.start()));
208 sb.append(rep);
209 pos = mat.end();
210 }
211 sb.append(input.substring(pos));
212 return Pattern.compile(sb.toString(), Pattern.DOTALL);
213 }
214
215 /**
216 * The following Pattern is the final result after
217 * parsing/tokenizing/substituting the meta-pattern.
218 */
219 private static final Pattern pattern =
220 buildPattern(populatePatterns(), metapattern);
221
222 /*
223 * This pattern relies on pattern grouping to easily pull the values from
224 * the Matcher. Look at the following to get an idea of the groups that
225 * come from the reg-ex
226 *
227 * 0 -> <!DOCTYPE root SYSTEM "system" [internal] >
228 * 1 -> root
229 * 2 -> SYSTEM "system"
230 * 3 -> SYSTEM "system"
231 * 4 -> SYSTEM "system"
232 * 5 -> "system"
233 * 6 -> null
234 * 7 -> null
235 * 8 -> "system"
236 * 9 -> system
237 * 10 -> null
238 * 11 -> null
239 * 12 -> null
240 * 13 -> null
241 * 14 -> null
242 * 15 -> null
243 * 16 -> null
244 * 17 -> null
245 * 18 -> null
246 * 19 -> null
247 * 20 -> null
248 * 21 -> null
249 * 22 -> [internal]
250 * 23 -> internal
251 *
252 *
253 * 0 -> <!DOCTYPE root PUBLIC 'public' 'system' [internal] >
254 * 1 -> root
255 * 2 -> PUBLIC 'public' 'system'
256 * 3 -> PUBLIC 'public' 'system'
257 * 4 -> null
258 * 5 -> null
259 * 6 -> null
260 * 7 -> null
261 * 8 -> null
262 * 9 -> null
263 * 10 -> PUBLIC 'public' 'system'
264 * 11 -> 'public'
265 * 12 -> 'public'
266 * 13 -> public
267 * 14 -> null
268 * 15 -> null
269 * 16 -> 'system'
270 * 17 -> 'system'
271 * 18 -> 'system'
272 * 19 -> system
273 * 20 -> null
274 * 21 -> null
275 * 22 -> [internal]
276 * 23 -> internal
277 *
278 *
279 */
280
281 /**
282 * Looks in any number of matched groups for a value. Returns the first set
283 * value. The assumption is that, depending on the pattern matches, the
284 * value could be in a few different locations.
285 * @param mat The match that has succeeded
286 * @param groups The groups to check for a value.
287 * @return The first found value.
288 */
289 private static final String getGroup(final Matcher mat, final int...groups) {
290 for (final int g : groups) {
291 final String s = mat.group(g);
292 if (s != null) {
293 return s;
294 }
295 }
296 return null;
297 }
298
299 /**
300 * return true if the input character is one of the types recognized in the
301 * DTD spec.
302 * @param ch The char to check
303 * @return true if it is a space, tab, newline, or carriage-return.
304 */
305 private static final boolean isWhite(char ch) {
306 return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
307 }
308
309 /**
310 * Reformat an internal subset.... Each declaration starts on an indented
311 * newline.
312 * @param internal the input DocType declaration as found in a StAX Reader.
313 * @return the formatted input.
314 */
315 private static String formatInternal(String internal) {
316 StringBuilder sb = new StringBuilder(internal.length());
317 char quote = ' ';
318 boolean white = true;
319 for (char ch : internal.toCharArray()) {
320 if (quote == ' ') {
321 // we are not in a quoted value...
322 if (isWhite(ch)) {
323 if (!white) {
324 // this will be the first whitespace.
325 // replace it with a single ' '
326 sb.append(' ');
327 white = true;
328 }
329 // subsequent (unquoted) whitespace is ignored
330 } else {
331 if (ch == '\'' || ch == '"') {
332 // we are entering a quoted value.
333 quote = ch;
334 } else if (ch == '<') {
335 // we are starting some form of declaration.
336 sb.append(" ");
337 }
338
339 if (ch == '>') {
340 // we are ending a declaration.
341 if (white) {
342 // the declaration ended with whitespace, which we
343 // remove.
344 sb.setCharAt(sb.length() - 1, ch);
345 } else {
346 // the declaration had no whitespace at the end. OK
347 sb.append(ch);
348 }
349 // all declarations end with a new-line.
350 sb.append('\n');
351 // and subsequent lines start as trimmed whitespace.
352 white = true;
353 } else {
354 sb.append(ch);
355 white = false;
356 }
357 }
358 } else {
359 // we are in a quoted value...
360 if (ch == quote) {
361 //we are leaving the quoted value.
362 quote = ' ';
363 }
364 sb.append(ch);
365 }
366 }
367 return sb.toString();
368 }
369
370 /**
371 * Parse out a DOCTYPE declaration as supplied by the standard StAX
372 * readers.
373 * <p>
374 * Using 'XML' terminology, this method assumes that the input is
375 * both 'well-formed' and 'valid'. The assumptions that this class makes
376 * ensure that the 'right thing' is done for valid content, but invalid
377 * content may or may not fail with a JDOMException. The behaviour of this
378 * method with invalid input is 'undefined'.
379 *
380 * @param input the input DOCTYPE string to parse. Must be valid.
381 * @param factory The JDOM factory to use to build the JDOM DocType.
382 * @return The input string as a DocType.
383 * @throws JDOMException if the DocType is not generated.
384 */
385 public static DocType parse(final String input, final JDOMFactory factory)
386 throws JDOMException {
387
388 // Match the input to the DOCTYPE pattern matcher.
389 final Matcher mat = pattern.matcher(input);
390 if (!mat.matches()) {
391 throw new JDOMException("Doctype input does not appear to be valid: " + input);
392 }
393
394 // Get the four data components.
395 final String docemt = mat.group(1);
396 final String sysid = getGroup(mat, 7, 9, 19, 21);
397 final String pubid = getGroup(mat, 13, 15);
398 final String internal = getGroup(mat, 23);
399
400 // Use the appropriate constructor for the DocType.
401 DocType dt = null;
402 if (pubid != null) {
403 dt = factory.docType(docemt, pubid, sysid);
404 } else if (sysid != null) {
405 dt = factory.docType(docemt, sysid);
406 } else {
407 dt = factory.docType(docemt);
408 }
409 // Set the internal subset, if any.
410 if (internal != null) {
411 dt.setInternalSubset(formatInternal(internal));
412 }
413 return dt;
414 }
415
416 /**
417 * Make instances 'impossible'. Everything is static.
418 */
419 private DTDParser() {
420 // nothing, you are not allowed instances of this class.
421 }
422
423 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.stax;
55
56 import org.jdom.Namespace;
57
58 /**
59 * This DefaultStAXFilter includes all content and prunes nothing.
60 * <p>
61 * Override this class to make adjustments to get the results you need.
62 *
63 * @see StAXFilter
64 *
65 * @author Rolf Lear
66 */
67 public class DefaultStAXFilter implements StAXFilter {
68
69 @Override
70 public boolean includeDocType() {
71 return true;
72 }
73
74 @Override
75 public boolean includeElement(final int depth, final String name, final Namespace ns) {
76 return true;
77 }
78
79 @Override
80 public String includeComment(final int depth, final String comment) {
81 return comment;
82 }
83
84 @Override
85 public boolean includeEntityRef(final int depth, final String name) {
86 return true;
87 }
88
89 @Override
90 public String includeCDATA(final int depth, final String text) {
91 return text;
92 }
93
94 @Override
95 public String includeText(final int depth, final String text) {
96 return text;
97 }
98
99 @Override
100 public boolean includeProcessingInstruction(final int depth, final String target) {
101 return true;
102 }
103
104 @Override
105 public boolean pruneElement(final int depth, final String name, final Namespace ns) {
106 return false;
107 }
108
109 @Override
110 public String pruneComment(final int depth, final String comment) {
111 return comment;
112 }
113
114 @Override
115 public boolean pruneEntityRef(final int depth, final String name) {
116 return false;
117 }
118
119 @Override
120 public String pruneCDATA(final int depth, final String text) {
121 return text;
122 }
123
124 @Override
125 public String pruneText(final int depth, final String text) {
126 return text;
127 }
128
129 @Override
130 public boolean pruneProcessingInstruction(final int depth, final String target) {
131 return false;
132 }
133
134 }
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.input.stax;
55
56 import org.jdom.Namespace;
57
58 /**
59 * In StAX Processing it is possible to read fragments of XML. JDOM supports
60 * reading JDOM Content from StAX Readers in fragments. JDOM users can influence
61 * the content that is processed by the return values in this interface.
62 * <p>
63 * Using the StAXStreamBuilder or StAXEventBuilder you can parse a List of
64 * JDOM content by filtering that content with an instance of this filter.
65 * <p>
66 * There are two significant states in which methods in this interface will be
67 * called:
68 * <ul>
69 * <li> We are not currently including any content, and we want to know whether
70 * the current StAX content should be included.
71 * <li> We are currently inside an Element that this filter has indicated should
72 * be included, but perhaps you want to prune some content.
73 * </ul>
74 *
75 * @author Rolf Lear
76 *
77 */
78 public interface StAXFilter {
79
80 /**
81 * The current event is a DocType event.
82 * @return true if the DocType should become a JDOM Fragment.
83 */
84 public boolean includeDocType();
85
86 /**
87 * The current event is an Element event.
88 * <p>
89 * If the return value of this call is true, then this Element will be
90 * processed as a JDOM fragment. You may then get calls to the prune*
91 * methods to determine whether child content of this Element should be
92 * pruned.
93 *
94 * @param depth The depth of this content from the document root
95 * (the root Element is at depth 0)
96 * @param name The XML tag name of this Element
97 * @param ns The Namespace of this Element
98 * @return true if the Element should become a JDOM Fragment.
99 */
100 public boolean includeElement(int depth, String name, Namespace ns);
101
102 /**
103 * The current event is a Comment event.
104 * <p>
105 * A null return value will cause the Comment to be ignored, and a non-null
106 * return value will become the Comment's text.
107 * <p>
108 * To include the comment as-is, do:
109 * <br>
110 * <pre>
111 * public String includeComment(int depth, String comment) {
112 * return comment;
113 * }
114 * </pre>
115 * @param depth The depth of this content from the document root
116 * (the root Element is at depth 0)
117 * @param comment The Comment value
118 * @return null if you want to exclude this comment, or a non-null value
119 * which will become the new comment value.
120 */
121 public String includeComment(int depth, String comment);
122
123 /**
124 * The current event is an EntityRef event.
125 * <p>
126 * @param depth The depth of this content from the document root
127 * (the root Element is at depth 0)
128 * @param name The EntityRef name
129 * @return true if you want to include this EntityRef.
130 */
131 public boolean includeEntityRef(int depth, String name);
132
133 /**
134 * The current event is a CDATA event.
135 * <p>
136 * A null return value will cause the Comment to be ignored, and a non-null
137 * return value will become the CDATA's text.
138 * <p>
139 * To include the CDATA as-is, do:
140 * <br>
141 * <pre>
142 * public String includeCDATA(int depth, String text) {
143 * return text;
144 * }
145 * </pre>
146 * @param depth The depth of this content from the document root
147 * (the root Element is at depth 0)
148 * @param text The CDATA text value
149 * @return null if you want to exclude this CDATA, or a non-null value
150 * which will become the new CDATA text value.
151 */
152 public String includeCDATA(int depth, String text);
153
154 /**
155 * The current event is a TEXT event.
156 * <p>
157 * A null return value will cause the Comment to be ignored, and a non-null
158 * return value will become the Text's text.
159 * <p>
160 * To include the Text as-is, do:
161 * <br>
162 * <pre>
163 * public String includeText(int depth, String text) {
164 * return text;
165 * }
166 * </pre>
167 * @param depth The depth of this content from the document root
168 * (the root Element is at depth 0)
169 * @param text The Text value
170 * @return null if you want to exclude this Text, or a non-null value
171 * which will become the new Text value.
172 */
173 public String includeText(int depth, String text);
174
175 /**
176 * The current event is a ProcessingInstruction event.
177 * <p>
178 * @param depth The depth of this content from the document root
179 * (the root Element is at depth 0)
180 * @param target The ProcessingInstruction Target value
181 * @return true if you want to include this ProcessingInstruction.
182 */
183 public boolean includeProcessingInstruction(int depth, String target);
184
185 /**
186 * An Element is being included, and this is a child Element event of the
187 * included parent Element. Should this Child Element be pruned from the
188 * parent fragment?
189 * @param depth The depth of this content from the document root
190 * (the root Element is at depth 0)
191 * @param name The XML tag name of this child Element
192 * @param ns The Namespace of this child Element
193 * @return true if the child Element should be excluded.
194 */
195 public boolean pruneElement(int depth, String name, Namespace ns);
196
197
198 /**
199 * An Element is being included, and this is a child Comment event of the
200 * included parent Element. Should this child Comment be pruned from the
201 * parent fragment?
202 * <p>
203 * A non-null return value will become the Comment value. Return null to
204 * skip the Comment.
205 * <p>
206 * To include the Comment as-is, do:
207 * <br>
208 * <pre>
209 * public String pruneComment(int depth, String comment) {
210 * return comment;
211 * }
212 * </pre>
213 * @param depth The depth of this content from the document root
214 * (the root Element is at depth 0)
215 * @param comment The Comment value
216 * @return null if you want to exclude this Comment, or a non-null value
217 * which will become the new Comment value.
218 */
219 public String pruneComment(int depth, String comment);
220
221 /**
222 * An Element is being included, and this is a child EntityRef event of the
223 * included parent Element. Should this child EntityRef be pruned from the
224 * parent fragment?
225 * <p>
226 * @param depth The depth of this content from the document root
227 * (the root Element is at depth 0)
228 * @param name The EntityRef name
229 * @return true if you want to exclude this EntityRef.
230 */
231 public boolean pruneEntityRef(int depth, String name);
232
233 /**
234 * An Element is being included, and this is a child CDATA event of the
235 * included parent Element. Should this child CDATA be pruned from the
236 * parent fragment?
237 * <p>
238 * A non-null return value will become the CDATA text. Return null to skip
239 * the CDATA.
240 * <p>
241 * To include the CDATA as-is, do:
242 * <br>
243 * <pre>
244 * public String pruneCDATA(int depth, String text) {
245 * return text;
246 * }
247 * </pre>
248 * @param depth The depth of this content from the document root
249 * (the root Element is at depth 0)
250 * @param text The CDATA text value
251 * @return null if you want to exclude this CDATA, or a non-null value
252 * which will become the new CDATA text value.
253 */
254 public String pruneCDATA(int depth, String text);
255
256 /**
257 * An Element is being included, and this is a child Text event of the
258 * included parent Element. Should this child Text be pruned from the
259 * parent fragment?
260 * <p>
261 * A non-null return value will become the Text. Return null to skip
262 * the Text.
263 * <p>
264 * To include the Text as-is, do:
265 * <br>
266 * <pre>
267 * public String pruneText(int depth, String text) {
268 * return text;
269 * }
270 * </pre>
271 * @param depth The depth of this content from the document root
272 * (the root Element is at depth 0)
273 * @param text The Text value
274 * @return null if you want to exclude this Text, or a non-null value
275 * which will become the new Text value.
276 */
277 public String pruneText(int depth, String text);
278
279 /**
280 * An Element is being included, and this is a child ProcessingInstruction
281 * event of the included parent Element. Should this ProcessingInstruction
282 * be pruned from the parent fragment?
283 * <p>
284 * @param depth The depth of this content from the document root
285 * (the root Element is at depth 0)
286 * @param target The ProcessingInstruction Target value
287 * @return true if you want to exclude this ProcessingInstruction.
288 */
289 public boolean pruneProcessingInstruction(int depth, String target);
290
291 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 /**
55 Support classes for building JDOM documents and content using StAX readers.
56
57 */
58 package org.jdom.input.stax;
59
0 /*--
1
2 Copyright (C) 2011 - 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.internal;
55
56 import java.lang.reflect.Array;
57
58 /**
59 * The copyOf methods on java.util.Arrays are introduced in Java6. Need an
60 * alternative to support Java5.
61 *
62 * @author Rolf Lear
63 *
64 */
65 public final class ArrayCopy {
66
67 private ArrayCopy() {
68 // inaccessible constructor.
69 }
70
71 /**
72 * Arrays.copyOf(...) is a Java6 thing. This is a replacement.
73 * @param <E> The generic type of the array we are copying.
74 * @param source the source array.
75 * @param len the length of the new array copy.
76 * @return a new array that has the same elements as the source.
77 */
78 public static final <E> E[] copyOf(final E[] source, final int len) {
79 @SuppressWarnings("unchecked")
80 final E[] dest = (E[])Array.newInstance(source.getClass().getComponentType(), len);
81 System.arraycopy(source, 0, dest, 0, len < source.length ? len : source.length);
82 return dest;
83 }
84
85 /**
86 * Arrays.copyOf(...) is a Java6 thing. This is a replacement.
87 * @param <E> The generic type of the array we are copying.
88 * @param source the source array.
89 * @param from the start point of the copy (inclusive).
90 * @param to the end point of the copy (exclusive).
91 * @return a new array that has the same elements as the source.
92 */
93 public static final <E> E[] copyOfRange(final E[] source, final int from, int to) {
94 final int len = to - from;
95 if (len < 0) {
96 throw new IllegalArgumentException("From(" + from + ") > To (" + to + ")");
97 }
98 @SuppressWarnings("unchecked")
99 final E[] dest = (E[])Array.newInstance(source.getClass().getComponentType(), len);
100 final int tocopy = from + len > source.length ? source.length - from : len;
101 System.arraycopy(source, from, dest, 0, tocopy);
102 return dest;
103 }
104
105 /**
106 * Arrays.copyOf(...) is a Java6 thing. This is a replacement.
107 * @param source the source array.
108 * @param len the length of the new array copy.
109 * @return a new array that has the same elements as the source.
110 */
111 public static final char[] copyOf(final char[] source, final int len) {
112 final char[] dest = new char[len];
113 System.arraycopy(source, 0, dest, 0, len < source.length ? len : source.length);
114 return dest;
115 }
116
117 /**
118 * Arrays.copyOf(...) is a Java6 thing. This is a replacement.
119 * @param source the source array.
120 * @param len the length of the new array copy.
121 * @return a new array that has the same elements as the source.
122 */
123 public static final int[] copyOf(final int[] source, final int len) {
124 final int[] dest = new int[len];
125 System.arraycopy(source, 0, dest, 0, len < source.length ? len : source.length);
126 return dest;
127 }
128
129 /**
130 * Arrays.copyOf(...) is a Java6 thing. This is a replacement.
131 * @param source the source array.
132 * @param len the length of the new array copy.
133 * @return a new array that has the same elements as the source.
134 */
135 public static final boolean[] copyOf(final boolean[] source, final int len) {
136 final boolean[] dest = new boolean[len];
137 System.arraycopy(source, 0, dest, 0, len < source.length ? len : source.length);
138 return dest;
139 }
140
141
142 }
0 /*--
1
2 Copyright (C) 2011 - 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.internal;
55
56 import java.lang.reflect.Constructor;
57 import java.lang.reflect.InvocationTargetException;
58
59 /**
60 * Utility class that handles constructing a class using reflection, and a
61 * no-argument 'default' constructor.
62 *
63 * @author Rolf Lear
64 *
65 */
66 public class ReflectionConstructor {
67
68 /**
69 * Construct a new instance of the named class, and ensure it is cast
70 * to the type specified as the targetclass.
71 * @param <E> The generic type of the returned value.
72 * @param classname The class name of the instance to create.
73 * @param targetclass The return type of the created instance
74 * @return an instantiated class
75 * @throws IllegalArgumentException if there is a problem locating the class instance.
76 * @throws IllegalStateException if there is a problem instantiating a class instance.
77 */
78 public static final <E> E construct(String classname, Class<E> targetclass) {
79 try {
80 Class<?> sclass = Class.forName(classname);
81 if (!targetclass.isAssignableFrom(sclass)) {
82 throw new ClassCastException("Class '" + classname + "' is not assignable to '" + targetclass.getName() + "'.");
83 }
84 Constructor<?> constructor = sclass.getConstructor();
85 Object o = constructor.newInstance();
86 return targetclass.cast(o);
87 } catch (ClassNotFoundException e) {
88 throw new IllegalArgumentException("Unable to locate class '" + classname + "'.", e);
89 } catch (NoSuchMethodException e) {
90 throw new IllegalArgumentException("Unable to locate class no-arg constructor '" + classname + "'.", e);
91 } catch (SecurityException e) {
92 throw new IllegalStateException("Unable to access class constructor '" + classname + "'.", e);
93 } catch (IllegalAccessException e) {
94 throw new IllegalStateException("Unable to access class constructor '" + classname + "'.", e);
95 } catch (InstantiationException e) {
96 throw new IllegalStateException("Unable to instantiate class '" + classname + "'.", e);
97 } catch (InvocationTargetException e) {
98 throw new IllegalStateException("Unable to call class constructor '" + classname + "'.", e);
99 }
100 }
101 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.internal;
55
56 /**
57 * System.getProperty(...) requires security permissions in Applets, and some
58 * other cases and this class contains static methods that allow the security
59 * exceptions to fail silently.
60 *
61 * @author Rolf Lear
62 *
63 */
64 public final class SystemProperty {
65
66 /**
67 * Query the System properties for a particular property. If the property
68 * is not set, or not accessible, it returns the def value.
69 * @param property The property to get
70 * @param def The value to return if the property is not accessible or not set.
71 * @return the appropriate property value.
72 */
73 public static final String get(final String property, final String def) {
74 try {
75 return System.getProperty(property, def);
76 } catch (SecurityException se) {
77 return def;
78 }
79 }
80 }
0 <body>
1 Classes that implement reusable functionality that are not part of the
2 official JDOM API, but are used by many of the JDOM classes.
3 </body>
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.located;
55
56 /**
57 * Implementations of this class know about their location (line and column).
58 * <p>
59 * While it would seem intuitive that this represents the location where the
60 * content starts, in fact, if the data is populated by a SAX parser the line
61 * and column values represent the <strong>end</strong> of the SAX
62 * <strong>event</strong>.
63 * <p>
64 * SAX parsers may vary, but it typically means the
65 * character after the last character for Text and CDATA values, the character
66 * after EntityRef, Comment, and ProcessingInstruction data, and the character
67 * after the opening tag for Element content. For DocType content, it appears
68 * that Xerces is inconsistent in the location, with the location being set at
69 * what appears to be the start of the internal subset data (if any).
70 * <p>
71 * Finally, remember that the column value counts characters, and thus, if you
72 * have tab-indented values, the tab counts as a single character (regardless of
73 * how much it indents).
74 *
75 * @author Rolf Lear
76 *
77 */
78 public interface Located {
79 /**
80 * Get the line number
81 * @return the line number
82 */
83 public int getLine();
84 /**
85 * Get the column (character on the line).
86 * @return the column
87 */
88 public int getColumn();
89
90 /**
91 * Set the line number
92 * @param line the line.
93 */
94 public void setLine(int line);
95 /**
96 * Set the column (character on the line).
97 * @param col The column
98 */
99 public void setColumn(int col);
100 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.located;
55
56 import org.jdom.CDATA;
57 import org.jdom.IllegalDataException;
58 import org.jdom.Text;
59
60 /**
61 * An XML CDATA section. Represents character-based content within an XML
62 * document that should be output within special CDATA tags. Semantically it's
63 * identical to a simple {@link Text} object, but output behavior is different.
64 * CDATA makes no guarantees about the underlying textual representation of
65 * character data, but does expose that data as a Java String.
66 *
67 * @author Rolf Lear
68 */
69 public class LocatedCDATA extends CDATA implements Located {
70
71 /**
72 * This constructor creates a new <code>LocatedCDATA</code> node, with the
73 * supplied string value as it's character content.
74 *
75 * @param str the node's character content.
76 * @throws IllegalDataException if <code>str</code> contains an
77 * illegal character such as a vertical tab (as determined
78 * by {@link org.jdom.Verifier#checkCharacterData})
79 */
80 public LocatedCDATA(String str) {
81 super(str);
82 }
83
84 /**
85 * JDOM2 Serialization. In this case, DocType is simple.
86 */
87 private static final long serialVersionUID = 200L;
88
89 private int line, col;
90
91 @Override
92 public int getLine() {
93 return line;
94 }
95
96 @Override
97 public int getColumn() {
98 return col;
99 }
100
101 @Override
102 public void setLine(int line) {
103 this.line = line;
104 }
105
106 @Override
107 public void setColumn(int col) {
108 this.col = col;
109 }
110
111
112 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.located;
55
56 import org.jdom.Comment;
57
58 /**
59 * An XML comment. Methods allow the user to get and set the text of the
60 * comment.
61 *
62 * @author Rolf Lear
63 */
64 public class LocatedComment extends Comment implements Located {
65
66 /**
67 * This creates the comment with the supplied text.
68 *
69 * @param text <code>String</code> content of comment.
70 */
71 public LocatedComment(String text) {
72 super(text);
73 }
74
75 /**
76 * JDOM2 Serialization. In this case, DocType is simple.
77 */
78 private static final long serialVersionUID = 200L;
79
80 private int line, col;
81
82 @Override
83 public int getLine() {
84 return line;
85 }
86
87 @Override
88 public int getColumn() {
89 return col;
90 }
91
92 @Override
93 public void setLine(int line) {
94 this.line = line;
95 }
96
97 @Override
98 public void setColumn(int col) {
99 this.col = col;
100 }
101
102
103 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.located;
55
56 import org.jdom.DocType;
57 import org.jdom.IllegalDataException;
58 import org.jdom.IllegalNameException;
59
60 /**
61 * An XML DOCTYPE declaration. Method allow the user to get and set the
62 * root element name, public id, and system id.
63 *
64 * @author Rolf Lear
65 */
66 public class LocatedDocType extends DocType implements Located {
67
68 /**
69 * This will create the <code>DocType</code> with
70 * the specified element name and a reference to an
71 * external DTD.
72 *
73 * @param elementName <code>String</code> name of
74 * element being constrained.
75 * @param publicID <code>String</code> public ID of
76 * referenced DTD
77 * @param systemID <code>String</code> system ID of
78 * referenced DTD
79 * @throws IllegalDataException if the given system ID is not a legal
80 * system literal or the public ID is not a legal public ID.
81 * @throws IllegalNameException if the given root element name is not a
82 * legal XML element name.
83 */
84 public LocatedDocType(String elementName, String publicID, String systemID) {
85 super(elementName, publicID, systemID);
86 }
87
88 /**
89 * This will create the <code>DocType</code> with
90 * the specified element name and reference to an
91 * external DTD.
92 *
93 * @param elementName <code>String</code> name of
94 * element being constrained.
95 * @param systemID <code>String</code> system ID of
96 * referenced DTD
97 * @throws IllegalDataException if the given system ID is not a legal
98 * system literal.
99 * @throws IllegalNameException if the given root element name is not a
100 * legal XML element name.
101 */
102 public LocatedDocType(String elementName, String systemID) {
103 super(elementName, systemID);
104 }
105
106 /**
107 * This will create the <code>DocType</code> with
108 * the specified element name
109 *
110 * @param elementName <code>String</code> name of
111 * element being constrained.
112 * @throws IllegalNameException if the given root element name is not a
113 * legal XML element name.
114 */
115 public LocatedDocType(String elementName) {
116 super(elementName);
117 }
118
119 /**
120 * JDOM2 Serialization. In this case, DocType is simple.
121 */
122 private static final long serialVersionUID = 200L;
123
124 private int line, col;
125
126 @Override
127 public int getLine() {
128 return line;
129 }
130
131 @Override
132 public int getColumn() {
133 return col;
134 }
135
136 @Override
137 public void setLine(int line) {
138 this.line = line;
139 }
140
141 @Override
142 public void setColumn(int col) {
143 this.col = col;
144 }
145
146 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.located;
55
56 import org.jdom.Element;
57 import org.jdom.IllegalNameException;
58 import org.jdom.Namespace;
59
60 /**
61 * This Element specialization contains the location information as parsed.
62 *
63 * @author Rolf Lear
64 *
65 */
66 public class LocatedElement extends Element implements Located {
67
68 /**
69 * Creates a new element with the supplied (local) name and namespace. If
70 * the provided namespace is null, the element will have no namespace.
71 *
72 * @param name local name of the element
73 * @param namespace namespace for the element
74 * @throws IllegalNameException if the given name is illegal as an element
75 * name
76 */
77 public LocatedElement(final String name, final Namespace namespace) {
78 super(name, namespace);
79 }
80
81 /**
82 * Create a new element with the supplied (local) name and no namespace.
83 *
84 * @param name local name of the element
85 * @throws IllegalNameException if the given name is illegal as an element
86 * name.
87 */
88 public LocatedElement(final String name) {
89 super(name);
90 }
91
92 /**
93 * Creates a new element with the supplied (local) name and a namespace
94 * given by a URI. The element will be put into the unprefixed (default)
95 * namespace.
96 *
97 * @param name name of the element
98 * @param uri namespace URI for the element
99 * @throws IllegalNameException if the given name is illegal as an element
100 * name or the given URI is illegal as a
101 * namespace URI
102 */
103 public LocatedElement(final String name, final String uri) {
104 super(name, uri);
105 }
106
107 /**
108 * Creates a new element with the supplied (local) name and a namespace
109 * given by the supplied prefix and URI combination.
110 *
111 * @param name local name of the element
112 * @param prefix namespace prefix
113 * @param uri namespace URI for the element
114 * @throws IllegalNameException if the given name is illegal as an element
115 * name, the given prefix is illegal as a
116 * namespace prefix, or the given URI is
117 * illegal as a namespace URI
118 */
119 public LocatedElement(final String name, final String prefix, final String uri) {
120 super(name, prefix, uri);
121 }
122
123 /**
124 * JDOM2 Serialization. In this case, DocType is simple.
125 */
126 private static final long serialVersionUID = 200L;
127
128 private int line, col;
129
130 @Override
131 public int getLine() {
132 return line;
133 }
134
135 @Override
136 public int getColumn() {
137 return col;
138 }
139
140 @Override
141 public void setLine(int line) {
142 this.line = line;
143 }
144
145 @Override
146 public void setColumn(int col) {
147 this.col = col;
148 }
149
150
151 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.located;
55
56 import org.jdom.EntityRef;
57 import org.jdom.IllegalDataException;
58 import org.jdom.IllegalNameException;
59
60 /**
61 * An XML entity reference. Methods allow the user to manage its name, public
62 * id, and system id.
63 *
64 * @author Rolf Lear
65 */
66 public class LocatedEntityRef extends EntityRef implements Located {
67
68 /**
69 * This will create a new <code>EntityRef</code> with the supplied name.
70 *
71 * @param name <code>String</code> name of element.
72 * @throws IllegalNameException if the given name is not a legal
73 * XML name.
74 */
75 public LocatedEntityRef(String name) {
76 super(name);
77 }
78
79 /**
80 * This will create a new <code>EntityRef</code>
81 * with the supplied name and system id.
82 *
83 * @param name <code>String</code> name of element.
84 * @param systemID system id of the entity reference being constructed
85 * @throws IllegalNameException if the given name is not a legal
86 * XML name.
87 * @throws IllegalDataException if the given system ID is not a legal
88 * system literal.
89 */
90 public LocatedEntityRef(String name, String systemID) {
91 super(name, systemID);
92 }
93
94 /**
95 * This will create a new <code>EntityRef</code>
96 * with the supplied name, public id, and system id.
97 *
98 * @param name <code>String</code> name of element.
99 * @param publicID public id of the entity reference being constructed
100 * @param systemID system id of the entity reference being constructed
101 * @throws IllegalDataException if the given system ID is not a legal
102 * system literal or the the given public ID is not a
103 * legal public ID
104 * @throws IllegalNameException if the given name is not a legal
105 * XML name.
106 */
107 public LocatedEntityRef(String name, String publicID, String systemID) {
108 super(name, publicID, systemID);
109 }
110
111 /**
112 * JDOM2 Serialization. In this case, DocType is simple.
113 */
114 private static final long serialVersionUID = 200L;
115
116 private int line, col;
117
118 @Override
119 public int getLine() {
120 return line;
121 }
122
123 @Override
124 public int getColumn() {
125 return col;
126 }
127
128 @Override
129 public void setLine(int line) {
130 this.line = line;
131 }
132
133 @Override
134 public void setColumn(int col) {
135 this.col = col;
136 }
137
138 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.located;
55
56 import java.util.Map;
57
58 import org.jdom.CDATA;
59 import org.jdom.Comment;
60 import org.jdom.DefaultJDOMFactory;
61 import org.jdom.DocType;
62 import org.jdom.Element;
63 import org.jdom.EntityRef;
64 import org.jdom.Namespace;
65 import org.jdom.ProcessingInstruction;
66 import org.jdom.Text;
67
68 /**
69 * All Content instances (Element, Comment, CDATA, DocType, Text, EntityRef,
70 * and ProcessingInstruction) will implement {@link Located}, and will
71 * have the values set appropriately.
72 * <p>
73 * You can set an instance of this LocatedJDOMFactory as the factory for a
74 * SAXBuilder, and the JDOM document produced will have the SAX Location data
75 * embedded. Note though, that SAX Location data indicates the position of the
76 * <strong>end</strong> of the SAX Event.
77 *
78 * @author Rolf Lear
79 *
80 */
81 public class LocatedJDOMFactory extends DefaultJDOMFactory {
82
83 @Override
84 public CDATA cdata(int line, int col, String text) {
85 final LocatedCDATA ret = new LocatedCDATA(text);
86 ret.setLine(line);
87 ret.setColumn(col);
88 return ret;
89 }
90
91 @Override
92 public Text text(int line, int col, String text) {
93 final LocatedText ret = new LocatedText(text);
94 ret.setLine(line);
95 ret.setColumn(col);
96 return ret;
97 }
98
99 @Override
100 public Comment comment(int line, int col, String text) {
101 final LocatedComment ret = new LocatedComment(text);
102 ret.setLine(line);
103 ret.setColumn(col);
104 return ret;
105 }
106
107 @Override
108 public DocType docType(int line, int col, String elementName,
109 String publicID, String systemID) {
110 final LocatedDocType ret = new LocatedDocType(elementName, publicID, systemID);
111 ret.setLine(line);
112 ret.setColumn(col);
113 return ret;
114 }
115
116 @Override
117 public DocType docType(int line, int col, String elementName,
118 String systemID) {
119 final LocatedDocType ret = new LocatedDocType(elementName, systemID);
120 ret.setLine(line);
121 ret.setColumn(col);
122 return ret;
123 }
124
125 @Override
126 public DocType docType(int line, int col, String elementName) {
127 final LocatedDocType ret = new LocatedDocType(elementName);
128 ret.setLine(line);
129 ret.setColumn(col);
130 return ret;
131 }
132
133 @Override
134 public Element element(int line, int col, String name, Namespace namespace) {
135 final LocatedElement ret = new LocatedElement(name, namespace);
136 ret.setLine(line);
137 ret.setColumn(col);
138 return ret;
139 }
140
141 @Override
142 public Element element(int line, int col, String name) {
143 final LocatedElement ret = new LocatedElement(name);
144 ret.setLine(line);
145 ret.setColumn(col);
146 return ret;
147 }
148
149 @Override
150 public Element element(int line, int col, String name, String uri) {
151 final LocatedElement ret = new LocatedElement(name, uri);
152 ret.setLine(line);
153 ret.setColumn(col);
154 return ret;
155 }
156
157 @Override
158 public Element element(int line, int col, String name, String prefix,
159 String uri) {
160 final LocatedElement ret = new LocatedElement(name, prefix, uri);
161 ret.setLine(line);
162 ret.setColumn(col);
163 return ret;
164 }
165
166 @Override
167 public ProcessingInstruction processingInstruction(int line, int col,
168 String target) {
169 final LocatedProcessingInstruction ret = new LocatedProcessingInstruction(target);
170 ret.setLine(line);
171 ret.setColumn(col);
172 return ret;
173 }
174
175 @Override
176 public ProcessingInstruction processingInstruction(int line, int col,
177 String target, Map<String, String> data) {
178 final LocatedProcessingInstruction ret = new LocatedProcessingInstruction(target, data);
179 ret.setLine(line);
180 ret.setColumn(col);
181 return ret;
182 }
183
184 @Override
185 public ProcessingInstruction processingInstruction(int line, int col,
186 String target, String data) {
187 final LocatedProcessingInstruction ret = new LocatedProcessingInstruction(target, data);
188 ret.setLine(line);
189 ret.setColumn(col);
190 return ret;
191 }
192
193 @Override
194 public EntityRef entityRef(int line, int col, String name) {
195 final LocatedEntityRef ret = new LocatedEntityRef(name);
196 ret.setLine(line);
197 ret.setColumn(col);
198 return ret;
199 }
200
201 @Override
202 public EntityRef entityRef(int line, int col, String name, String publicID,
203 String systemID) {
204 final LocatedEntityRef ret = new LocatedEntityRef(name, publicID, systemID);
205 ret.setLine(line);
206 ret.setColumn(col);
207 return ret;
208 }
209
210 @Override
211 public EntityRef entityRef(int line, int col, String name, String systemID) {
212 final LocatedEntityRef ret = new LocatedEntityRef(name, systemID);
213 ret.setLine(line);
214 ret.setColumn(col);
215 return ret;
216 }
217
218
219 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.located;
55
56 import java.util.Map;
57
58 import org.jdom.IllegalTargetException;
59 import org.jdom.ProcessingInstruction;
60
61 /**
62 * An XML processing instruction. Methods allow the user to obtain the target of
63 * the PI as well as its data. The data can always be accessed as a String or,
64 * if the data appears akin to an attribute list, can be retrieved as name/value
65 * pairs.
66 *
67 * @author Rolf Lear
68 */
69 public class LocatedProcessingInstruction extends ProcessingInstruction implements
70 Located {
71
72 /**
73 * This will create a new <code>ProcessingInstruction</code>
74 * with the specified target.
75 *
76 * @param target <code>String</code> target of PI.
77 * @throws IllegalTargetException if the given target is illegal
78 * as a processing instruction name.
79 */
80 public LocatedProcessingInstruction(String target) {
81 super(target);
82 }
83
84 /**
85 * This will create a new <code>ProcessingInstruction</code>
86 * with the specified target and data.
87 *
88 * @param target <code>String</code> target of PI.
89 * @param data <code>Map</code> data for PI, in
90 * name/value pairs
91 * @throws IllegalTargetException if the given target is illegal
92 * as a processing instruction name.
93 */
94 public LocatedProcessingInstruction(String target, Map<String,String> data) {
95 super(target, data);
96 }
97
98 /**
99 * This will create a new <code>ProcessingInstruction</code>
100 * with the specified target and data.
101 *
102 * @param target <code>String</code> target of PI.
103 * @param data <code>String</code> data for PI.
104 * @throws IllegalTargetException if the given target is illegal
105 * as a processing instruction name.
106 */
107 public LocatedProcessingInstruction(String target, String data) {
108 super(target, data);
109 }
110
111
112 /**
113 * JDOM2 Serialization. In this case, DocType is simple.
114 */
115 private static final long serialVersionUID = 200L;
116
117 private int line, col;
118
119 @Override
120 public int getLine() {
121 return line;
122 }
123
124 @Override
125 public int getColumn() {
126 return col;
127 }
128
129 @Override
130 public void setLine(int line) {
131 this.line = line;
132 }
133
134 @Override
135 public void setColumn(int col) {
136 this.col = col;
137 }
138
139 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.located;
55
56 import org.jdom.IllegalDataException;
57 import org.jdom.Text;
58
59 /**
60 * An XML character sequence. Provides a modular, parentable method of
61 * representing text. Text makes no guarantees about the underlying textual
62 * representation of character data, but does expose that data as a Java String.
63 *
64 * @author Rolf Lear
65 */
66 public class LocatedText extends Text implements Located {
67
68 /**
69 * This constructor creates a new <code>Text</code> node, with the
70 * supplied string value as it's character content.
71 *
72 * @param str the node's character content.
73 * @throws IllegalDataException if <code>str</code> contains an
74 * illegal character such as a vertical tab (as determined
75 * by {@link org.jdom.Verifier#checkCharacterData})
76 */
77 public LocatedText(String str) {
78 super(str);
79 }
80
81 /**
82 * JDOM2 Serialization. In this case, DocType is simple.
83 */
84 private static final long serialVersionUID = 200L;
85
86 private int line, col;
87
88 @Override
89 public int getLine() {
90 return line;
91 }
92
93 @Override
94 public int getColumn() {
95 return col;
96 }
97
98 @Override
99 public void setLine(int line) {
100 this.line = line;
101 }
102
103 @Override
104 public void setColumn(int col) {
105 this.col = col;
106 }
107
108
109 }
0 <body>
1
2 Extended JDOM Content Classes that contain location coordinates. The coordinates
3 are accessible using the <code>Located</code> interface which has getters and
4 setters for the line and column details.
5 <p>
6 In addition, there is the <code>LocatedJDOMFactory</code> which can be used to
7 create the <code>Located</code>-aware Content. The
8 <code>LocatedJDOMFactory</code> can be used by a <code>SAXBuilder</code> to
9 preserve the location data on the Content.
10
11 </body>
0 /*--
1
2 Copyright (C) 2000-2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output;
55
56 import java.util.List;
57
58 import org.jdom.Attribute;
59 import org.jdom.CDATA;
60 import org.jdom.Comment;
61 import org.jdom.Content;
62 import org.jdom.DocType;
63 import org.jdom.Document;
64 import org.jdom.Element;
65 import org.jdom.EntityRef;
66 import org.jdom.JDOMException;
67 import org.jdom.ProcessingInstruction;
68 import org.jdom.Text;
69 import org.jdom.adapters.DOMAdapter;
70 import org.jdom.adapters.JAXPDOMAdapter;
71 import org.jdom.internal.ReflectionConstructor;
72 import org.jdom.output.support.AbstractDOMOutputProcessor;
73 import org.jdom.output.support.DOMOutputProcessor;
74
75 /**
76 * Outputs a JDOM {@link org.jdom.Document org.jdom.Document} as a DOM
77 * {@link org.w3c.dom.Document org.w3c.dom.Document}. Also provides methods to
78 * output other types of JDOM Content in the equivalent DOM nodes.
79 * <p>
80 * There are two versions of most functions, one that creates an independent DOM
81 * node using the DOMAdapter to create a new org.w3c.dom.Document. The other
82 * version creates the new DOM Nodes using the supplied org.w3c.dom.Document
83 * instance.
84 *
85 * @author Brett McLaughlin
86 * @author Jason Hunter
87 * @author Matthew Merlo
88 * @author Dan Schaffer
89 * @author Yusuf Goolamabbas
90 * @author Bradley S. Huffman
91 * @author Rolf lear
92 */
93 public class DOMOutputter {
94
95 /**
96 * Create a final/concrete instance of the AbstractDOMOutputProcessor.
97 * Making it final improves performance.
98 *
99 * @author Rolf Lear
100 */
101 private static final class DefaultDOMOutputProcessor extends
102 AbstractDOMOutputProcessor {
103 // add nothing except make it final.
104 }
105
106 /** Default adapter class */
107 private static final DOMAdapter DEFAULT_ADAPTER = new JAXPDOMAdapter();
108
109 private static final DOMOutputProcessor DEFAULT_PROCESSOR = new DefaultDOMOutputProcessor();
110
111 /** Adapter to use for interfacing with the DOM implementation */
112 private DOMAdapter adapter;
113
114 private Format format;
115
116 private DOMOutputProcessor processor;
117
118 /**
119 * This creates a new DOMOutputter which will attempt to first locate a DOM
120 * implementation to use via JAXP, and if JAXP does not exist or there's a
121 * problem, will fall back to the default parser.
122 */
123 public DOMOutputter() {
124 this(null, null, null);
125 }
126
127 /**
128 * This creates a new DOMOutputter which uses the defalt (JAXP) DOM
129 * implementation but with a custom processor.
130 *
131 * @param processor
132 * the custom processor to use.
133 * @since JDOM2
134 */
135 public DOMOutputter(DOMOutputProcessor processor) {
136 this(null, null, processor);
137 }
138
139 /**
140 * The complete constructor for specifying a custom DOMAdaptor, Format, and
141 * DOMOutputProcessor.
142 *
143 * @param adapter
144 * The adapter to use to create the base Document instance (null
145 * implies the default).
146 * @param format
147 * The output Format to use (null implies the default).
148 * @param processor
149 * The custom mechanism for doing the output (null implies the
150 * default).
151 * @since JDOM2
152 */
153 public DOMOutputter(DOMAdapter adapter, Format format,
154 DOMOutputProcessor processor) {
155 this.adapter = adapter == null ? DEFAULT_ADAPTER : adapter;
156 this.format = format == null ? Format.getRawFormat() : format;
157 this.processor = processor == null ? DEFAULT_PROCESSOR : processor;
158 }
159
160 /**
161 * This creates a new DOMOutputter using the specified DOMAdapter
162 * implementation as a way to choose the underlying parser.
163 *
164 * @param adapterClass
165 * <code>String</code> name of class to use for DOM output
166 * @throws IllegalArgumentException
167 * if the adapter could not be instantiated. (it should be
168 * JDOMException, but that would require a change to this deprecated
169 * method's signature...
170 * @deprecated use {@link DOMOutputter#DOMOutputter(DOMAdapter)} instead.
171 */
172 @Deprecated
173 public DOMOutputter(String adapterClass) {
174 if (adapterClass == null) {
175 adapter = DEFAULT_ADAPTER;
176 } else {
177 adapter = ReflectionConstructor.construct(adapterClass,
178 DOMAdapter.class);
179 }
180 }
181
182 /**
183 * This creates a new DOMOutputter using the specified DOMAdapter
184 * implementation as a way to choose the underlying parser.
185 * <p>
186 * If the specified adapter is not thread-safe then the user should ensure
187 * that the adapter instance is never shared between multiple DOMOutputters.
188 * The default DOMAdapter {@link JAXPDOMAdapter} is thread-safe.
189 *
190 * @param adapter
191 * the DOMAdapter instance to use for creating the base
192 * org.w3c.dom.Document Specify the null value to get the default
193 * adapter.
194 * @since JDOM2
195 */
196 public DOMOutputter(DOMAdapter adapter) {
197 this.adapter = adapter == null ? DEFAULT_ADAPTER : adapter;
198 }
199
200 /**
201 * Get the DOMAdapter currently set for this DOMOutputter.
202 *
203 * @return the current DOMAdapter.
204 * @since JDOM2
205 */
206 public DOMAdapter getDOMAdapter() {
207 return adapter;
208 }
209
210 /**
211 * Set the DOMAdapter currently set for this DOMOutputter.
212 *
213 * @param adapter
214 * the new DOMAdapter to use (null implies the default).
215 * @since JDOM2
216 */
217 public void setDOMAdapter(DOMAdapter adapter) {
218 this.adapter = adapter == null ? DEFAULT_ADAPTER : adapter;
219 }
220
221 /**
222 * Get the Format instance currently used by this DOMOutputter.
223 *
224 * @return the current Format instance
225 * @since JDOM2
226 */
227 public Format getFormat() {
228 return format;
229 }
230
231 /**
232 * Set a new Format instance for this DOMOutputter
233 *
234 * @param format
235 * the new Format instance to use (null implies the default)
236 * @since JDOM2
237 */
238 public void setFormat(Format format) {
239 this.format = format == null ? Format.getRawFormat() : format;
240 }
241
242 /**
243 * Get the current DOMOutputProcessor
244 *
245 * @return the current DOMOutputProcessor
246 * @since JDOM2
247 */
248 public DOMOutputProcessor getDOMOutputProcessor() {
249 return processor;
250 }
251
252 /**
253 * Set a new DOMOutputProcessor for this DOMOutputter.
254 *
255 * @param processor
256 * the new processor to set (null implies the default)
257 * @since JDOM2
258 */
259 public void setDOMOutputProcessor(DOMOutputProcessor processor) {
260 this.processor = processor == null ? DEFAULT_PROCESSOR : processor;
261 }
262
263 /**
264 * Controls how NO_NAMESPACE nodes are handled. If true the outputter always
265 * creates a namespace aware DOM.
266 *
267 * @param flag
268 * true to force NamespaceAware
269 * @deprecated All DOMOutputters are now always NamespaceAware.
270 */
271 @Deprecated
272 public void setForceNamespaceAware(boolean flag) {
273 // do nothing
274 }
275
276 /**
277 * Returns whether DOMs will be constructed with namespaces even when the
278 * source document has elements all in the empty namespace.
279 *
280 * @return the forceNamespaceAware flag value
281 * @deprecated All DOMOutputters are always NamesapceAware. Always true.
282 */
283 @Deprecated
284 public boolean getForceNamespaceAware() {
285 return true;
286 }
287
288 /**
289 * This converts the JDOM <code>Document</code> parameter to a DOM Document,
290 * returning the DOM version. The DOM implementation is the one supplied by
291 * the current DOMAdapter.
292 *
293 * @param document
294 * <code>Document</code> to output.
295 * @return an <code>org.w3c.dom.Document</code> version
296 * @throws JDOMException
297 * if output failed.
298 */
299 public org.w3c.dom.Document output(Document document) throws JDOMException {
300 return processor.process(adapter.createDocument(document.getDocType()),
301 format, document);
302 }
303
304 /**
305 * This converts the JDOM <code>DocType</code> parameter to a DOM DocumentType,
306 * returning the DOM version. The DOM implementation is the one supplied by
307 * the current DOMAdapter.
308 * <p>
309 * Unlike the other DOM Nodes, you cannot use a DOM Document to simply create a DOM DocumentType Node,
310 * it has to be created at the same time as the DOM Document instance. As a result, there is no
311 * version of this method that takes a DOM Document instance.
312 *
313 * @param doctype
314 * <code>DocType</code> to output.
315 * @return an <code>org.w3c.dom.DocumentType</code> version
316 * @throws JDOMException
317 * if output failed.
318 * @since JDOM2
319 */
320 public org.w3c.dom.DocumentType output(DocType doctype) throws JDOMException {
321 return adapter.createDocument(doctype).getDoctype();
322 }
323
324 /**
325 * This converts the JDOM <code>Element</code> parameter to a DOM Element,
326 * returning the DOM version. The DOM Node will be linked to an independent
327 * DOM Document instance supplied by the current DOMAdapter
328 *
329 * @param element
330 * <code>Element</code> to output.
331 * @return an <code>org.w3c.dom.Element</code> version
332 * @throws JDOMException
333 * if output failed.
334 */
335 public org.w3c.dom.Element output(Element element) throws JDOMException {
336 return processor.process(adapter.createDocument(), format, element);
337 }
338
339 /**
340 * This converts the JDOM <code>Text</code> parameter to a DOM Text Node,
341 * returning the DOM version. The DOM Node will be linked to an independent
342 * DOM Document instance supplied by the current DOMAdapter
343 *
344 * @param text
345 * <code>Text</code> to output.
346 * @return an <code>org.w3c.dom.Text</code> version
347 * @throws JDOMException
348 * if output failed.
349 * @since JDOM2
350 */
351 public org.w3c.dom.Text output(Text text) throws JDOMException {
352 return processor.process(adapter.createDocument(), format, text);
353 }
354
355 /**
356 * This converts the JDOM <code>CDATA</code> parameter to a DOM CDATASection
357 * Node, returning the DOM version. The DOM Node will be linked to an
358 * independent DOM Document instance supplied by the current DOMAdapter
359 *
360 * @param cdata
361 * <code>CDATA</code> to output.
362 * @return an <code>org.w3c.dom.CDATASection</code> version
363 * @throws JDOMException
364 * if output failed.
365 * @since JDOM2
366 */
367 public org.w3c.dom.CDATASection output(CDATA cdata) throws JDOMException {
368 return processor.process(adapter.createDocument(), format, cdata);
369 }
370
371 /**
372 * This converts the JDOM <code>ProcessingInstruction</code> parameter to a
373 * DOM ProcessingInstruction, returning the DOM version. The DOM Node will
374 * be linked to an independent DOM Document instance supplied by the current
375 * DOMAdapter
376 *
377 * @param pi
378 * <code>ProcessingInstruction</code> to output.
379 * @return an <code>org.w3c.dom.Element</code> version
380 * @throws JDOMException
381 * if output failed.
382 * @since JDOM2
383 */
384 public org.w3c.dom.ProcessingInstruction output(ProcessingInstruction pi)
385 throws JDOMException {
386 return processor.process(adapter.createDocument(), format, pi);
387 }
388
389 /**
390 * This converts the JDOM <code>ProcessingInstruction</code> parameter to a
391 * DOM ProcessingInstruction, returning the DOM version. The DOM Node will
392 * be linked to an independent DOM Document instance supplied by the current
393 * DOMAdapter
394 *
395 * @param comment
396 * <code>Comment</code> to output.
397 * @return an <code>org.w3c.dom.Comment</code> version
398 * @throws JDOMException
399 * if output failed.
400 * @since JDOM2
401 */
402 public org.w3c.dom.Comment output(Comment comment) throws JDOMException {
403 return processor.process(adapter.createDocument(), format, comment);
404 }
405
406 /**
407 * This converts the JDOM <code>EntityRef</code> parameter to a DOM
408 * EntityReference Node, returning the DOM version. The DOM Node will be
409 * linked to an independent DOM Document instance supplied by the current
410 * DOMAdapter
411 *
412 * @param entity
413 * <code>EntityRef</code> to output.
414 * @return an <code>org.w3c.dom.EntityReference</code> version
415 * @throws JDOMException
416 * if output failed.
417 * @since JDOM2
418 */
419 public org.w3c.dom.EntityReference output(EntityRef entity)
420 throws JDOMException {
421 return processor.process(adapter.createDocument(), format, entity);
422 }
423
424 /**
425 * This converts the JDOM <code>Attribute</code> parameter to a DOM Attr
426 * Node, returning the DOM version. The DOM Node will be linked to an
427 * independent DOM Document instance supplied by the current DOMAdapter
428 *
429 * @param attribute
430 * <code>Attribute</code> to output.
431 * @return an <code>org.w3c.dom.Attr</code> version
432 * @throws JDOMException
433 * if output failed.
434 * @since JDOM2
435 */
436 public org.w3c.dom.Attr output(Attribute attribute) throws JDOMException {
437 return processor.process(adapter.createDocument(), format, attribute);
438 }
439
440 /**
441 * This converts the JDOM <code>Attribute</code> parameter to a DOM Attr
442 * Node, returning the DOM version. The DOM Node will be linked to an
443 * independent DOM Document instance supplied by the current DOMAdapter
444 *
445 * @param list
446 * <code>Attribute</code> to output.
447 * @return an <code>org.w3c.dom.Attr</code> version
448 * @throws JDOMException
449 * if output failed.
450 * @since JDOM2
451 */
452 public List<org.w3c.dom.Node> output(List<? extends Content> list)
453 throws JDOMException {
454 return processor.process(adapter.createDocument(), format, list);
455 }
456
457 /**
458 * This converts the JDOM <code>Element</code> parameter to a DOM Element,
459 * returning the DOM version. The DOM Node will be linked to an independent
460 * DOM Document instance supplied by the current DOMAdapter
461 *
462 * @param basedoc
463 * The DOM Document to use for creating DOM Nodes.
464 * @param element
465 * <code>Element</code> to output.
466 * @return an <code>org.w3c.dom.Element</code> version
467 * @throws JDOMException
468 * if output failed.
469 * @since JDOM2
470 */
471 public org.w3c.dom.Element output(org.w3c.dom.Document basedoc,
472 Element element) throws JDOMException {
473 return processor.process(basedoc, format, element);
474 }
475
476 /**
477 * This converts the JDOM <code>Text</code> parameter to a DOM Text Node,
478 * returning the DOM version. The DOM Node will be linked to an independent
479 * DOM Document instance supplied by the current DOMAdapter
480 *
481 * @param basedoc
482 * The DOM Document to use for creating DOM Nodes.
483 * @param text
484 * <code>Text</code> to output.
485 * @return an <code>org.w3c.dom.Text</code> version
486 * @throws JDOMException
487 * if output failed.
488 * @since JDOM2
489 */
490 public org.w3c.dom.Text output(org.w3c.dom.Document basedoc, Text text)
491 throws JDOMException {
492 return processor.process(basedoc, format, text);
493 }
494
495 /**
496 * This converts the JDOM <code>CDATA</code> parameter to a DOM CDATASection
497 * Node, returning the DOM version. The DOM Node will be linked to an
498 * independent DOM Document instance supplied by the current DOMAdapter
499 *
500 * @param basedoc
501 * The DOM Document to use for creating DOM Nodes.
502 * @param cdata
503 * <code>CDATA</code> to output.
504 * @return an <code>org.w3c.dom.CDATASection</code> version
505 * @throws JDOMException
506 * if output failed.
507 * @since JDOM2
508 */
509 public org.w3c.dom.CDATASection output(org.w3c.dom.Document basedoc,
510 CDATA cdata) throws JDOMException {
511 return processor.process(basedoc, format, cdata);
512 }
513
514 /**
515 * This converts the JDOM <code>ProcessingInstruction</code> parameter to a
516 * DOM ProcessingInstruction, returning the DOM version. The DOM Node will
517 * be linked to an independent DOM Document instance supplied by the current
518 * DOMAdapter
519 *
520 * @param basedoc
521 * The DOM Document to use for creating DOM Nodes.
522 * @param pi
523 * <code>ProcessingInstruction</code> to output.
524 * @return an <code>org.w3c.dom.Element</code> version
525 * @throws JDOMException
526 * if output failed.
527 * @since JDOM2
528 */
529 public org.w3c.dom.ProcessingInstruction output(
530 org.w3c.dom.Document basedoc, ProcessingInstruction pi)
531 throws JDOMException {
532 return processor.process(basedoc, format, pi);
533 }
534
535 /**
536 * This converts the JDOM <code>ProcessingInstruction</code> parameter to a
537 * DOM ProcessingInstruction, returning the DOM version. The DOM Node will
538 * be linked to an independent DOM Document instance supplied by the current
539 * DOMAdapter
540 *
541 * @param basedoc
542 * The DOM Document to use for creating DOM Nodes.
543 * @param comment
544 * <code>Comment</code> to output.
545 * @return an <code>org.w3c.dom.Comment</code> version
546 * @throws JDOMException
547 * if output failed.
548 * @since JDOM2
549 */
550 public org.w3c.dom.Comment output(org.w3c.dom.Document basedoc,
551 Comment comment) throws JDOMException {
552 return processor.process(basedoc, format, comment);
553 }
554
555 /**
556 * This converts the JDOM <code>EntityRef</code> parameter to a DOM
557 * EntityReference Node, returning the DOM version. The DOM Node will be
558 * linked to an independent DOM Document instance supplied by the current
559 * DOMAdapter
560 *
561 * @param basedoc
562 * The DOM Document to use for creating DOM Nodes.
563 * @param entity
564 * <code>EntityRef</code> to output.
565 * @return an <code>org.w3c.dom.EntityReference</code> version
566 * @throws JDOMException
567 * if output failed.
568 * @since JDOM2
569 */
570 public org.w3c.dom.EntityReference output(org.w3c.dom.Document basedoc,
571 EntityRef entity) throws JDOMException {
572 return processor.process(basedoc, format, entity);
573 }
574
575 /**
576 * This converts the JDOM <code>Attribute</code> parameter to a DOM Attr
577 * Node, returning the DOM version. The DOM Node will be linked to an
578 * independent DOM Document instance supplied by the current DOMAdapter
579 *
580 * @param basedoc
581 * The DOM Document to use for creating DOM Nodes.
582 * @param attribute
583 * <code>Attribute</code> to output.
584 * @return an <code>org.w3c.dom.Attr</code> version
585 * @throws JDOMException
586 * if output failed.
587 * @since JDOM2
588 */
589 public org.w3c.dom.Attr output(org.w3c.dom.Document basedoc,
590 Attribute attribute) throws JDOMException {
591 return processor.process(basedoc, format, attribute);
592 }
593
594 /**
595 * This converts the list of JDOM <code>Content</code> in to a list of DOM
596 * Nodes, returning the DOM version. The DOM Node will be linked to an
597 * independent DOM Document instance supplied by the current DOMAdapter
598 *
599 * @param basedoc
600 * The DOM Document to use for creating DOM Nodes.
601 * @param list
602 * of JDOM Content to output.
603 * @return a List of <code>org.w3c.dom.Node</code>
604 * @throws JDOMException
605 * if output failed.
606 * @since JDOM2
607 */
608 public List<org.w3c.dom.Node> output(org.w3c.dom.Document basedoc,
609 List<? extends Content> list) throws JDOMException {
610 return processor.process(basedoc, format, list);
611 }
612
613 }
0 /*--
1
2 Copyright (C) 2000-2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output;
55
56 /**
57 * Logic to determine which characters should be formatted as character
58 * entities.
59 *
60 * @author Alex Rosen
61 * @author Bradley S. Huffman
62 * @author Jason Hunter
63 */
64 public interface EscapeStrategy {
65
66 /**
67 * Test whether the supplied character should be formatted literally
68 * or as a character entity.
69 * @param ch The char to test to determine whether it should be escaped.
70 * @return true if ch should be escaped.
71 */
72 public boolean shouldEscape(char ch);
73 }
74
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output;
55
56 import java.nio.charset.Charset;
57 import java.nio.charset.CharsetEncoder;
58 import java.util.Locale;
59
60 import org.jdom.IllegalDataException;
61 import org.jdom.Verifier;
62
63 /**
64 * Class to encapsulate XMLOutputter format options.
65 * Typically users adapt the standard format configurations obtained by
66 * {@link #getRawFormat} (no whitespace changes),
67 * {@link #getPrettyFormat} (whitespace beautification), and
68 * {@link #getCompactFormat} (whitespace normalization).
69 * <p>
70 * Several modes are available to effect the way textual content is printed.
71 * See the documentation for {@link TextMode} for details.
72 * <p>
73 * <b>Note about Line Separator:</b>
74 * <p>
75 * By default JDOM will always use the CRNL sequence "\r\n" for output. This
76 * can be changed in a number of different ways. See the {@link LineSeparator}
77 * enumeration for more information.
78 * <p>
79 * <b>Note about XML Character Escaping:</b>
80 * <p>
81 * JDOM will escape characters in the output based on the EscapeStrategy that
82 * is specified by this Format. The Format will by default use a sensible
83 * EscapeStrategy that is based on the character encoding of the output. If
84 * the default escape mechanism is not producing the correct results you can
85 * change the EscapeStrategy on the format to suit your own needs.
86 *
87 *
88 * @see LineSeparator
89 *
90 * @author Jason Hunter
91 * @author Rolf Lear
92 */
93 public class Format implements Cloneable {
94
95 /**
96 * An EscapeStrategy suitable for UTF-8 an UTF-16. We want the class to
97 * have its own name.
98 */
99 private static final class EscapeStrategyUTF implements EscapeStrategy {
100 @Override
101 public final boolean shouldEscape(char ch) {
102 return Verifier.isHighSurrogate(ch);
103 }
104 }
105
106 /**
107 * An EscapeStrategy suitable for UTF-8 an UTF-16
108 */
109 private static final EscapeStrategy UTFEscapeStrategy = new EscapeStrategyUTF();
110
111 /**
112 * An EscapeStrategy suitable for 8-bit charsets. We want the class to have
113 * its own name.
114 */
115 private static final class EscapeStrategy8Bits implements EscapeStrategy {
116 @Override
117 public boolean shouldEscape(final char ch) {
118 return (ch >>> 8) != 0;
119 }
120 }
121
122 /**
123 * An EscapeStrategy suitable for 8-bit charsets
124 */
125 private static final EscapeStrategy Bits8EscapeStrategy = new EscapeStrategy8Bits();
126
127 /**
128 * An EscapeStrategy suitable for 7-bit charsets. We want the class to
129 * have its own name.
130 */
131 private static final class EscapeStrategy7Bits implements EscapeStrategy {
132 @Override
133 public boolean shouldEscape(final char ch) {
134 return (ch >>> 7) != 0;
135 }
136 }
137
138 /**
139 * An EscapeStrategy suitable for 7-bit charsets
140 */
141 private static final EscapeStrategy Bits7EscapeStrategy =
142 new EscapeStrategy7Bits();
143
144 /**
145 * An EscapeStrategy suitable for 'unknown' charsets
146 */
147 private static final EscapeStrategy DefaultEscapeStrategy = new EscapeStrategy() {
148 @Override
149 public boolean shouldEscape(char ch) {
150 if (Verifier.isHighSurrogate(ch)) {
151 return true; // Safer this way per http://unicode.org/faq/utf_bom.html#utf8-4
152 }
153
154 return false;
155 }
156 };
157
158 /**
159 * Handles Charsets.
160 */
161 private final static class DefaultCharsetEscapeStrategy implements EscapeStrategy {
162
163 private final CharsetEncoder encoder;
164
165 public DefaultCharsetEscapeStrategy(CharsetEncoder cse) {
166 encoder = cse;
167 }
168
169 @Override
170 public boolean shouldEscape(final char ch) {
171
172 if (Verifier.isHighSurrogate(ch)) {
173 return true; // Safer this way per http://unicode.org/faq/utf_bom.html#utf8-4
174 }
175
176 return !encoder.canEncode(ch);
177 }
178
179 }
180
181 /**
182 * Returns a new Format object that performs no whitespace changes, uses
183 * the UTF-8 encoding, doesn't expand empty elements, includes the
184 * declaration and encoding, and uses the default entity escape strategy.
185 * Tweaks can be made to the returned Format instance without affecting
186 * other instances.
187
188 * @return a Format with no whitespace changes
189 */
190 public static Format getRawFormat() {
191 return new Format();
192 }
193
194 /**
195 * Returns a new Format object that performs whitespace beautification with
196 * 2-space indents, uses the UTF-8 encoding, doesn't expand empty elements,
197 * includes the declaration and encoding, and uses the default entity
198 * escape strategy.
199 * Tweaks can be made to the returned Format instance without affecting
200 * other instances.
201 *
202 * @return a Format with whitespace beautification
203 */
204 public static Format getPrettyFormat() {
205 Format f = new Format();
206 f.setIndent(STANDARD_INDENT);
207 f.setTextMode(TextMode.TRIM);
208 return f;
209 }
210
211 /**
212 * Returns a new Format object that performs whitespace normalization, uses
213 * the UTF-8 encoding, doesn't expand empty elements, includes the
214 * declaration and encoding, and uses the default entity escape strategy.
215 * Tweaks can be made to the returned Format instance without affecting
216 * other instances.
217 *
218 * @return a Format with whitespace normalization
219 */
220 public static Format getCompactFormat() {
221 Format f = new Format();
222 f.setTextMode(TextMode.NORMALIZE);
223 return f;
224 }
225
226 /**
227 * Use the XML Specification definition of whitespace to compact the
228 * input value. The value is trimmed, and any internal XML whitespace
229 * is replaced with a single ' ' space.
230 * @param str The value to compact.
231 * @return The compacted value
232 * @since JDOM2
233 */
234 public static final String compact(String str) {
235 int right = str.length() - 1;
236 int left = 0;
237 while (left <= right &&
238 Verifier.isXMLWhitespace(str.charAt(left))) {
239 left++;
240 }
241 while (right > left &&
242 Verifier.isXMLWhitespace(str.charAt(right))) {
243 right--;
244 }
245
246 if (left > right) {
247 return "";
248 }
249
250 boolean space = true;
251 final StringBuilder buffer = new StringBuilder(right - left + 1);
252 while (left <= right) {
253 final char c = str.charAt(left);
254 if (Verifier.isXMLWhitespace(c)) {
255 if (space) {
256 buffer.append(' ');
257 space = false;
258 }
259 } else {
260 buffer.append(c);
261 space = true;
262 }
263 left++;
264 }
265 return buffer.toString();
266 }
267
268 /**
269 * Use the XML Specification definition of whitespace to Right-trim the
270 * input value.
271 * @param str The value to trim.
272 * @return The value right-trimmed
273 * @since JDOM2
274 */
275 public static final String trimRight(String str) {
276 int right = str.length() - 1;
277 while (right >= 0 && Verifier.isXMLWhitespace(str.charAt(right))) {
278 right--;
279 }
280 if (right < 0) {
281 return "";
282 }
283 return str.substring(0, right + 1);
284 }
285
286 /**
287 * Use the XML Specification definition of whitespace to Left-trim the
288 * input value.
289 * @param str The value to trim.
290 * @return The value left-trimmed
291 * @since JDOM2
292 */
293 public static final String trimLeft(final String str) {
294 final int right = str.length();
295 int left = 0;
296 while (left < right && Verifier.isXMLWhitespace(str.charAt(left))) {
297 left++;
298 }
299 if (left >= right) {
300 return "";
301 }
302
303 return str.substring(left);
304 }
305
306 /**
307 * Use the XML Specification definition of whitespace to trim the
308 * input value.
309 * @param str The value to trim.
310 * @return The value trimmed
311 * @since JDOM2
312 */
313 public static final String trimBoth(final String str) {
314 int right = str.length() - 1;
315 while (right > 0 && Verifier.isXMLWhitespace(str.charAt(right))) {
316 right--;
317 }
318 int left = 0;
319 while (left <= right && Verifier.isXMLWhitespace(str.charAt(left))) {
320 left++;
321 }
322 if (left > right) {
323 return "";
324 }
325 return str.substring(left, right + 1);
326 }
327
328
329 /**
330 * This will take the three pre-defined entities in XML 1.0 ('&lt;', '&gt;',
331 * and '&amp;' - used specifically in XML elements) as well as CR/NL, tabs,
332 * and Quote characters which require escaping inside Attribute values and
333 * converts their character representation to the appropriate entity
334 * reference suitable for XML attribute content. Further, some special
335 * characters (e.g. characters that are not valid in the current encoding)
336 * are converted to escaped representations.
337 * <p>
338 * @param strategy
339 * The EscapeStrategy to query.
340 * @param value
341 * <code>String</code> Attribute value to escape.
342 * @return The value appropriately escaped.
343 * @throws IllegalDataException
344 * if an entity can not be escaped
345 */
346 public static final String escapeAttribute(final EscapeStrategy strategy,
347 final String value) {
348 final int len = value.length();
349 int idx = 0;
350
351 checkloop: while (idx < len) {
352 final char ch = value.charAt(idx);
353 if (ch == '<' || ch == '>' || ch == '&' || ch == '\r' || ch == '\n'
354 || ch == '"' || ch == '\t' || strategy.shouldEscape(ch)) {
355 break checkloop;
356 }
357 idx++;
358 }
359
360 if (idx == len) {
361 return value;
362 }
363
364 char highsurrogate = 0;
365 final StringBuilder sb = new StringBuilder(len + 5);
366 sb.append(value, 0, idx);
367 while (idx < len) {
368 final char ch = value.charAt(idx++);
369 if (highsurrogate > 0) {
370 if (!Verifier.isLowSurrogate(ch)) {
371 throw new IllegalDataException(
372 "Could not decode surrogate pair 0x" +
373 Integer.toHexString(highsurrogate) + " / 0x"
374 + Integer.toHexString(ch));
375 }
376 int chp = Verifier.decodeSurrogatePair(highsurrogate, ch);
377 sb.append("&#x");
378 sb.append(Integer.toHexString(chp));
379 sb.append(';');
380 highsurrogate = 0;
381 continue;
382 }
383 switch (ch) {
384 case '<':
385 sb.append("&lt;");
386 break;
387 case '>':
388 sb.append("&gt;");
389 break;
390 case '&':
391 sb.append("&amp;");
392 break;
393 case '\r':
394 sb.append("&#xD;");
395 break;
396 case '"':
397 sb.append("&quot;");
398 break;
399 case '\t':
400 sb.append("&#x9;");
401 break;
402 case '\n':
403 sb.append("&#xA;");
404 break;
405 default:
406
407 if (strategy.shouldEscape(ch)) {
408 // make sure what we are escaping is not the
409 // beginning of a multi-byte character.
410 if (Verifier.isHighSurrogate(ch)) {
411 // this is a the high of a surrogate pair
412 highsurrogate = ch;
413 } else {
414 sb.append("&#x");
415 sb.append(Integer.toHexString(ch));
416 sb.append(';');
417 }
418 } else {
419 sb.append(ch);
420 }
421 break;
422 }
423 }
424 if (highsurrogate > 0) {
425 throw new IllegalDataException("Surrogate pair 0x" +
426 Integer.toHexString(highsurrogate) + "truncated");
427 }
428
429 return sb.toString();
430 }
431
432
433
434
435 /**
436 * This will take the three pre-defined entities in XML 1.0 ('&lt;', '&gt;',
437 * and '&amp;' - used specifically in XML elements) and convert their
438 * character representation to the appropriate entity reference, suitable
439 * for XML element content. Further, some special characters (e.g.
440 * characters that are not valid in the current encoding) are converted to
441 * escaped representations. If the eol parameter is not null, then any
442 * internal newlines will be replaced with the specified eol sequence.
443 *
444 * @param strategy
445 * The EscapeStrategy
446 * @param eol
447 * The End-Of-Line sequence to be used (may be null).
448 * @param value
449 * The String to escape
450 * @return The input value escaped.
451 * @throws IllegalDataException
452 * if an entity can not be escaped
453 * @since JDOM2
454 */
455 public static final String escapeText(final EscapeStrategy strategy,
456 final String eol, final String value) {
457 final int right = value.length();
458 int idx = 0;
459 checkloop: while (idx < right) {
460 final char ch = value.charAt(idx);
461 if (ch == '<' || ch == '>' || ch == '&' || ch == '\r' || ch == '\n'
462 || strategy.shouldEscape(ch)) {
463 break checkloop;
464 }
465 idx++;
466 }
467
468 if (idx == right) {
469 // no escape needed.
470 return value;
471 }
472
473 StringBuilder sb = new StringBuilder();
474 if (idx > 0) {
475 sb.append(value, 0, idx);
476 }
477 char highsurrogate = 0;
478 while (idx < right) {
479 final char ch = value.charAt(idx++);
480 if (highsurrogate > 0) {
481 if (!Verifier.isLowSurrogate(ch)) {
482 throw new IllegalDataException(
483 "Could not decode surrogate pair 0x" +
484 Integer.toHexString(highsurrogate) + " / 0x"
485 + Integer.toHexString(ch));
486 }
487 int chp = Verifier.decodeSurrogatePair(highsurrogate, ch);
488 sb.append("&#x" + Integer.toHexString(chp) + ";");
489 highsurrogate = 0;
490 continue;
491 }
492 switch (ch) {
493 case '<':
494 sb.append("&lt;");
495 break;
496 case '>':
497 sb.append("&gt;");
498 break;
499 case '&':
500 sb.append("&amp;");
501 break;
502 case '\r':
503 sb.append("&#xD;");
504 break;
505 case '\n':
506 if (eol != null) {
507 sb.append(eol);
508 } else {
509 sb.append('\n');
510 }
511 break;
512 default:
513
514 if (strategy.shouldEscape(ch)) {
515 // make sure what we are escaping is not the
516 // beginning of a multi-byte character.
517 if (Verifier.isHighSurrogate(ch)) {
518 // this is a the high of a surrogate pair
519 highsurrogate = ch;
520 } else {
521 sb.append("&#x" + Integer.toHexString(ch) + ";");
522 }
523 } else {
524 sb.append(ch);
525 }
526 break;
527 }
528 }
529 if (highsurrogate > 0) {
530 throw new IllegalDataException("Surrogate pair 0x" +
531 Integer.toHexString(highsurrogate) + "truncated");
532 }
533
534 return sb.toString();
535
536 }
537
538 private static final EscapeStrategy chooseStrategy(String encoding) {
539 if ("UTF-8".equalsIgnoreCase(encoding) ||
540 "UTF-16".equalsIgnoreCase(encoding)) {
541 return UTFEscapeStrategy;
542 }
543
544 // Note issue #149: https://github.com/hunterhacker/jdom/issues/149
545 // require locale for case conversion to avoid potential security issue.
546 if (encoding.toUpperCase(Locale.ENGLISH).startsWith("ISO-8859-") ||
547 "Latin1".equalsIgnoreCase(encoding)) {
548 return Bits8EscapeStrategy;
549 }
550
551 if ("US-ASCII".equalsIgnoreCase(encoding) ||
552 "ASCII".equalsIgnoreCase(encoding)) {
553 return Bits7EscapeStrategy;
554 }
555
556 try {
557 final CharsetEncoder cse = Charset.forName(encoding).newEncoder();
558 return new DefaultCharsetEscapeStrategy(cse);
559 } catch (Exception e) {
560 // swallow that... and assume false.
561 }
562 return DefaultEscapeStrategy;
563 }
564
565
566 /** standard value to indent by, if we are indenting */
567 private static final String STANDARD_INDENT = " ";
568
569 /** standard string with which to end a line */
570 private static final String STANDARD_LINE_SEPARATOR = LineSeparator.DEFAULT.value();
571
572 /** standard encoding */
573 private static final String STANDARD_ENCODING = "UTF-8";
574
575
576 /** The default indent is no spaces (as original document) */
577 String indent = null;
578
579 /** New line separator */
580 String lineSeparator = STANDARD_LINE_SEPARATOR;
581
582 /** The encoding format */
583 String encoding = STANDARD_ENCODING;
584
585 /** Whether or not to output the XML declaration
586 * - default is <code>false</code> */
587 boolean omitDeclaration = false;
588
589 /** Whether or not to output the encoding in the XML declaration
590 * - default is <code>false</code> */
591 boolean omitEncoding = false;
592
593 /** Whether Attributes that are defaulted from the DTD or Schema
594 * are output. */
595 boolean specifiedAttributesOnly = false;
596
597 /** Whether or not to expand empty elements to
598 * &lt;tagName&gt;&lt;/tagName&gt; - default is <code>false</code> */
599 boolean expandEmptyElements = false;
600
601 /** Whether TrAX output escaping disabling/enabling PIs are ignored
602 * or processed - default is <code>false</code> */
603 boolean ignoreTrAXEscapingPIs = false;
604
605 /** text handling mode */
606 TextMode mode = TextMode.PRESERVE;
607
608 /** entity escape logic */
609 EscapeStrategy escapeStrategy = DefaultEscapeStrategy;
610
611 /**
612 * Creates a new Format instance with default (raw) behavior.
613 */
614 private Format() {
615 setEncoding(STANDARD_ENCODING);
616 }
617
618 /**
619 * Sets the {@link EscapeStrategy} to use for character escaping.
620 *
621 * @param strategy the EscapeStrategy to use
622 * @return a pointer to this Format for chaining
623 */
624 public Format setEscapeStrategy(EscapeStrategy strategy) {
625 escapeStrategy = strategy;
626 return this;
627 }
628
629 /**
630 * Returns the current escape strategy
631 *
632 * @return the current escape strategy
633 */
634 public EscapeStrategy getEscapeStrategy() {
635 return escapeStrategy;
636 }
637
638 /**
639 * This will set the newline separator (<code>LineSeparator</code>).
640 * The default is <code>\r\n</code>.
641 * <p>
642 * Use the {@link #setLineSeparator(LineSeparator)} method to set
643 * standard separators in an easier way.
644 * <p>
645 * To make it output the system default line ending string, call
646 * <code>setLineSeparator(System.getProperty("line.separator"))</code>.
647 *
648 * <p>
649 * To output "UNIX-style" documents, call
650 * <code>setLineSeparator("\n")</code>. To output "Mac-style"
651 * documents, call <code>setLineSeparator("\r")</code>. DOS-style
652 * documents use CR-LF ("\r\n"), which is the default.
653 * </p>
654 *
655 * <p>
656 * Note that this only applies to newlines generated by the
657 * outputter. All XML parsers are required to 'normalize' all the
658 * combinations of line seperators to just '\n'. As a result, if any JDOM
659 * component has an end-of-line-like value (e.g. '\r') in it then that value
660 * must be the result of an escaped value in the XML source document
661 * <code>&amp;#xD;</code> or a value explicitly set with one of the Text
662 * value setters. Values in JDOM content that were explicitly set to be
663 * '\r' will always be escaped on XML Output.
664 * <p>
665 * The actual newline separator itself though can be set with this method.
666 * Any internal newlines in Text output will be represented by this
667 * end-of-line sequence. For example, the following code:
668 * <p>
669 * <pre>
670 * Text txt = new Text("\r\n");
671 * XMLOutputter xout = new XMLOutputter();
672 * String result = xout.outputString(txt);
673 * </pre>
674 * will produce the literal String sequence "&amp;#xD;\r\n" because the
675 * original \r is escaped to be <code>&amp;#xD;</code> and the original \n
676 * is replaced with the JDOM default Line Separator "\r\n".
677 *
678 * <p>
679 * If the format's "indent" property is null (as is the default
680 * for the Raw and Compact formats), then this value only effects the
681 * newlines written after the declaration and doctype, as well as any
682 * newlines embedded within existing text content.
683 * </p>
684 * Setting the indent to be null will disable end-of-line processing
685 * for any formatting, but will not affect substitution of embedded \n.
686 * Setting this value to null or the empty string will disable all
687 * end-of-line modifications.
688 *
689 * @see #setTextMode
690 * @see #setLineSeparator(LineSeparator)
691 *
692 * @param separator <code>String</code> line separator to use.
693 * @return a pointer to this Format for chaining
694 */
695 public Format setLineSeparator(String separator) {
696 this.lineSeparator = "".equals(separator) ? null : separator;
697 return this;
698 }
699
700 /**
701 * This will set the newline separator sequence.
702 * <p>
703 * This method differes from {@link #setLineSeparator(String)} slightly in
704 * that, to disable end-of-line processing you should call:
705 * <pre>
706 * Format.setLinewSeparator(LineSeparator.NONE);
707 * </pre>
708 *
709 * @see #setLineSeparator(String) for comprehensive notes.
710 *
711 * @param separator {@link LineSeparator} line separator to us
712 * @return a pointer to this Format for chaining
713 * @since JDOM2
714 */
715 public Format setLineSeparator(LineSeparator separator) {
716 return setLineSeparator(separator == null ?
717 STANDARD_LINE_SEPARATOR :
718 separator.value());
719 }
720
721 /**
722 * Returns the current line separator.
723 *
724 * @return the current line separator
725 */
726 public String getLineSeparator() {
727 return lineSeparator;
728 }
729
730 /**
731 * This will set whether the XML declaration
732 * (<code>&lt;&#063;xml version="1&#046;0"
733 * encoding="UTF-8"&#063;&gt;</code>)
734 * includes the encoding of the document. It is common to omit
735 * this in uses such as WML and other wireless device protocols.
736 *
737 * @param omitEncoding <code>boolean</code> indicating whether or not
738 * the XML declaration should indicate the document encoding.
739 * @return a pointer to this Format for chaining
740 */
741 public Format setOmitEncoding(boolean omitEncoding) {
742 this.omitEncoding = omitEncoding;
743 return this;
744 }
745
746 /**
747 * Returns whether the XML declaration encoding will be omitted.
748 *
749 * @return whether the XML declaration encoding will be omitted
750 */
751 public boolean getOmitEncoding() {
752 return omitEncoding;
753 }
754
755 /**
756 * This will set whether the XML declaration
757 * (<code>&lt;&#063;xml version="1&#046;0"&#063;&gt;</code>)
758 * will be omitted or not. It is common to omit this in uses such
759 * as SOAP and XML-RPC calls.
760 *
761 * @param omitDeclaration <code>boolean</code> indicating whether or not
762 * the XML declaration should be omitted.
763 * @return a pointer to this Format for chaining
764 */
765 public Format setOmitDeclaration(boolean omitDeclaration) {
766 this.omitDeclaration = omitDeclaration;
767 return this;
768 }
769
770 /**
771 * Returns whether the XML declaration will be omitted.
772 *
773 * @return whether the XML declaration will be omitted
774 */
775 public boolean getOmitDeclaration() {
776 return omitDeclaration;
777 }
778
779 /**
780 * This will set whether empty elements are expanded from
781 * <code>&lt;tagName/&gt;</code> to
782 * <code>&lt;tagName&gt;&lt;/tagName&gt;</code>.
783 *
784 * @param expandEmptyElements <code>boolean</code> indicating whether or not
785 * empty elements should be expanded.
786 * @return a pointer to this Format for chaining
787 */
788 public Format setExpandEmptyElements(boolean expandEmptyElements) {
789 this.expandEmptyElements = expandEmptyElements;
790 return this;
791 }
792
793 /**
794 * Returns whether empty elements are expanded.
795 *
796 * @return whether empty elements are expanded
797 */
798 public boolean getExpandEmptyElements() {
799 return expandEmptyElements;
800 }
801
802 /**
803 * This will set whether JAXP TrAX processing instructions for
804 * disabling/enabling output escaping are ignored. Disabling
805 * output escaping allows using XML text as element content and
806 * outputing it verbatim, i&#46;e&#46; as element children would be.
807 * <p>
808 * When processed, these processing instructions are removed from
809 * the generated XML text and control whether the element text
810 * content is output verbatim or with escaping of the pre-defined
811 * entities in XML 1.0. The text to be output verbatim shall be
812 * surrounded by the
813 * <code>&lt;?javax.xml.transform.disable-output-escaping ?&gt;</code>
814 * and <code>&lt;?javax.xml.transform.enable-output-escaping ?&gt;</code>
815 * PIs.</p>
816 * <p>
817 * When ignored, the processing instructions are present in the
818 * generated XML text and the pre-defined entities in XML 1.0 are
819 * escaped.
820 * <p>
821 * Default: <code>false</code>.</p>
822 *
823 * @param ignoreTrAXEscapingPIs <code>boolean</code> indicating
824 * whether or not TrAX ouput escaping PIs are ignored.
825 *
826 * @see javax.xml.transform.Result#PI_ENABLE_OUTPUT_ESCAPING
827 * @see javax.xml.transform.Result#PI_DISABLE_OUTPUT_ESCAPING
828 */
829 public void setIgnoreTrAXEscapingPIs(boolean ignoreTrAXEscapingPIs) {
830 this.ignoreTrAXEscapingPIs = ignoreTrAXEscapingPIs;
831 }
832
833 /**
834 * Returns whether JAXP TrAX processing instructions for
835 * disabling/enabling output escaping are ignored.
836 *
837 * @return whether or not TrAX ouput escaping PIs are ignored.
838 */
839 public boolean getIgnoreTrAXEscapingPIs() {
840 return ignoreTrAXEscapingPIs;
841 }
842
843 /**
844 * This sets the text output style. Options are available as static
845 * {@link TextMode} instances. The default is {@link TextMode#PRESERVE}.
846 *
847 * @param mode The TextMode to set.
848 * @return a pointer to this Format for chaining
849 */
850 public Format setTextMode(Format.TextMode mode) {
851 this.mode = mode;
852 return this;
853 }
854
855 /**
856 * Returns the current text output style.
857 *
858 * @return the current text output style
859 */
860 public Format.TextMode getTextMode() {
861 return mode;
862 }
863
864 /**
865 * This will set the indent <code>String</code> to use; this
866 * is usually a <code>String</code> of empty spaces. If you pass
867 * the empty string (""), then no indentation will happen but newlines
868 * will still be generated. Passing null will result in no indentation
869 * and no newlines generated. Default: none (null)
870 *
871 * @param indent <code>String</code> to use for indentation.
872 * @return a pointer to this Format for chaining
873 */
874 public Format setIndent(String indent) {
875 this.indent = indent;
876 return this;
877 }
878
879 /**
880 * Returns the indent string in use.
881 *
882 * @return the indent string in use
883 */
884 public String getIndent() {
885 return indent;
886 }
887
888 /**
889 * Sets the output encoding. The name should be an accepted XML
890 * encoding.
891 *
892 * @param encoding the encoding format. Use XML-style names like
893 * "UTF-8" or "ISO-8859-1" or "US-ASCII"
894 * @return a pointer to this Format for chaining
895 */
896 public Format setEncoding(String encoding) {
897 this.encoding = encoding;
898 escapeStrategy = chooseStrategy(encoding);
899 return this;
900 }
901
902 /**
903 * Returns the configured output encoding.
904 *
905 * @return the output encoding
906 */
907 public String getEncoding() {
908 return encoding;
909 }
910
911
912 /**
913 * Will Attributes defaulted from the DTD or XMLSchema
914 * be output
915 * @return true if the defaulted Attributes will be output
916 */
917 public boolean isSpecifiedAttributesOnly() {
918 return specifiedAttributesOnly;
919 }
920
921 /**
922 * Set whether only those Attributes specified in the input XML should
923 * be output. Other Attributes (those defaulted or 'fixed' in the DTD
924 * or XMLSchema) should be ignored.
925 * @param specifiedAttributesOnly true if the defaulted
926 * Attributes should be ignored, false if they should be output
927 */
928 public void setSpecifiedAttributesOnly(boolean specifiedAttributesOnly) {
929 this.specifiedAttributesOnly = specifiedAttributesOnly;
930 }
931
932 @Override
933 public Format clone() {
934 Format format = null;
935
936 try {
937 format = (Format) super.clone();
938 }
939 catch (CloneNotSupportedException ce) {
940 // swallow.
941 }
942
943 return format;
944 }
945
946 /**
947 * Class to signify how text should be handled on output. The following
948 * table provides details.
949 *
950 * <table>
951 * <tr>
952 * <th align="left">
953 * Text Mode
954 * </th>
955 * <th>
956 * Resulting behavior.
957 * </th>
958 * </tr>
959 *
960 * <tr valign="top">
961 * <td>
962 * <i>PRESERVE (Default)</i>
963 * </td>
964 * <td>
965 * All content is printed in the format it was created, no whitespace
966 * or line separators are are added or removed.
967 * </td>
968 * </tr>
969 *
970 * <tr valign="top">
971 * <td>
972 * TRIM_FULL_WHITE
973 * </td>
974 * <td>
975 * Content between tags consisting of all whitespace is not printed.
976 * If the content contains even one non-whitespace character, it is
977 * all printed verbatim, whitespace and all.
978 * </td>
979 * </tr>
980 *
981 * <tr valign="top">
982 * <td>
983 * TRIM
984 * </td>
985 * <td>
986 * All leading and trailing whitespace is trimmed.
987 * </td>
988 * </tr>
989 *
990 * <tr valign="top">
991 * <td>
992 * NORMALIZE
993 * </td>
994 * <td>
995 * Leading and trailing whitespace is trimmed, and any 'internal'
996 * whitespace is compressed to a single space.
997 * </td>
998 * </tr>
999 * </table>
1000 *
1001 * In most cases textual content is aligned with the surrounding tags
1002 * (after the appropriate text mode is applied). In the case where the only
1003 * content between the start and end tags is textual, the start tag, text,
1004 * and end tag are all printed on the same line. If the document being
1005 * output already has whitespace, it's wise to turn on TRIM mode so the
1006 * pre-existing whitespace can be trimmed before adding new whitespace.
1007 * <p>
1008 * When an element has a xml:space attribute with the value of "preserve",
1009 * all formating is turned off (actually, the TextMode is set to
1010 * {@link #PRESERVE} until the element and its contents have been printed.
1011 * If a nested element contains another xml:space with the value "default"
1012 * formatting is turned back on for the child element and then off for the
1013 * remainder of the parent element.
1014 *
1015 * @since JDOM2
1016 */
1017 public static enum TextMode {
1018 /**
1019 * Mode for literal text preservation.
1020 */
1021 PRESERVE,
1022
1023 /**
1024 * Mode for text trimming (left and right trim).
1025 */
1026 TRIM,
1027
1028 /**
1029 * Mode for text normalization (left and right trim plus internal
1030 * whitespace is normalized to a single space.
1031 * @see org.jdom.Element#getTextNormalize
1032 */
1033 NORMALIZE,
1034
1035 /**
1036 * Mode for text trimming of content consisting of nothing but
1037 * whitespace but otherwise not changing output.
1038 */
1039 TRIM_FULL_WHITE;
1040
1041 }
1042 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output;
55
56 import org.xml.sax.Locator;
57
58 /**
59 * An implementation of the SAX {@link Locator} interface that
60 * exposes the JDOM node being processed by SAXOutputter.
61 * <p>
62 * In JDOM2 this class is demoted to an interface. The information was never
63 * accurate anyway, and as an interface a specific Outputter instance can
64 * instead do 'the right thing' with the locator, if needed.
65 * <p>
66 * This change breaks a possible compatibility with anyone who happened to treat
67 * the JDOMLocator to be 'settable'. This used to extend LocatorImpl class which
68 * had setter methods for the ColumnNumber, Line, PublicID, SystemID
69 *
70 * @author Laurent Bihanic
71 * @author Rolf Lear
72 *
73 */
74 public interface JDOMLocator extends Locator {
75
76 /**
77 * Returns the JDOM node being processed by SAXOutputter.
78 *
79 * @return the JDOM node being processed by SAXOutputter.
80 */
81 public Object getNode();
82
83 }
84
0 /*--
1
2 Copyright (C) 2011 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output;
55
56 import org.jdom.JDOMConstants;
57 import org.jdom.internal.SystemProperty;
58
59 /**
60 * An enumeration of common separators that are used for JDOM output.
61 * <p>
62 * These enumerated values can be used as input to the
63 * {@link Format#setLineSeparator(LineSeparator)} method. Additionally, the
64 * names of these constants can be also be used in the System Property
65 * {@link JDOMConstants#JDOM2_PROPERTY_LINE_SEPARATOR} which is used to
66 * define the default Line Separator sequence for JDOM output. See
67 * {@link #DEFAULT} Javadoc.
68 *
69 * <p>
70 * JDOM has historically used the CR/NL sequence '\r\n' as a line-terminator.
71 * This sequence has the advantage that the output is easily opened in the
72 * 'Notepad' editor on Windows. Other editors on other platforms are typically
73 * smart enough to automatically adjust to whatever termination sequence is
74 * used in the document. The XML specification requires that the CR/NL sequence
75 * should be 'normalized' to a single newline '\n' when the document is parsed
76 * (<a href="http://www.w3.org/TR/xml11/#sec-line-ends">XML 1.1 End-Of-Line
77 * Handling</a>). As a result there is no XML issue with the JDOM default CR/NL
78 * end-of-line sequence.
79 * <p>
80 * It should be noted that because JDOM internally stores just a '\n' as a line
81 * separator that any other output separator requires additional processing to
82 * output. There is a distinct performance benefit for using the UNIX, or NL
83 * LineSeparator for output.
84 * <p>
85 * JDOM has always allowed the line-terminating sequence to be customised (or
86 * even disabled) for each {@link XMLOutputter2} operation by using this Format
87 * class.
88 * <p>
89 * JDOM2 introduces two new features in relation to the end-of-line sequence.
90 * Firstly, it introduces this new {@link LineSeparator} enumeration which
91 * formalises the common line separators that can be used. In addition to the
92 * simple String-based {@link Format#setLineSeparator(String)} method you can
93 * now also call {@link Format#setLineSeparator(LineSeparator)} with one of the
94 * common enumerations.
95 * <p>
96 * The second new JDOM2 feature is the ability to set a global default
97 * end-of-line sequence. JDOM 1.x forced the default sequence to be the CRLF
98 * sequence, but JDOM2 allows you to set the system property
99 * {@link JDOMConstants#JDOM2_PROPERTY_LINE_SEPARATOR} which will be used as the
100 * default sequence for Format. You can set the property to be the name of one
101 * of these LineSeparator enumerations too. For example, the following will
102 * cause all default Format instances to use the System-dependent end-of-line
103 * sequence instead of always CRLF:
104 * <p>
105 * <pre>
106 * java -Dorg.jdom.output.LineSeparator=SYSTEM ...
107 * </pre>
108 *
109 * @since JDOM2
110 * @author Rolf Lear
111 *
112 */
113 public enum LineSeparator {
114 /**
115 * The Separator sequence CRNL which is '\r\n'.
116 * This is the default sequence.
117 */
118 CRNL("\r\n"),
119
120 /**
121 * The Separator sequence NL which is '\n'.
122 */
123 NL("\n"),
124 /**
125 * The Separator sequence CR which is '\r'.
126 */
127 CR("\r"),
128
129 /** The 'DOS' Separator sequence CRLF (CRNL) which is '\r\n'. */
130 DOS("\r\n"),
131
132 /** The 'UNIX' Separator sequence NL which is '\n'. */
133 UNIX("\n"),
134
135
136 /**
137 * The system-dependent Separator sequence NL which is obtained from
138 * <code>System.getProperty("line.separator")</code>. This should be
139 * the equivalent of {@link #DOS} on windows platforms, and
140 * of {@link #UNIX} on UNIX and Apple systems (after Mac OSX).
141 */
142 SYSTEM(SystemProperty.get("line.separator", "\r\n")),
143
144 /** Perform no end-of-line processing. */
145 NONE(null),
146
147 /**
148 * Use the sequence '\r\n' unless the System property
149 * {@link JDOMConstants#JDOM2_PROPERTY_LINE_SEPARATOR} is defined, in which
150 * case use the value specified in that property. If the value in that
151 * property matches one of the Enumeration names (e.g. SYSTEM) then use the
152 * sequence specified in that enumeration.
153 */
154 // DEFAULT must be declared last so that you can specify enum names
155 // in the system property.
156 DEFAULT(getDefaultLineSeparator());
157
158
159
160 private static String getDefaultLineSeparator() {
161 // Android has some unique ordering requirements in this bootstrap process.
162 // also, Android will not have the system property set, so we can exit with the null.
163 final String prop = SystemProperty.get(JDOMConstants.JDOM2_PROPERTY_LINE_SEPARATOR, "DEFAULT");
164 if ("DEFAULT".equals(prop)) {
165 // need to do this to catch the normal process where the property is not set
166 // which will cause the value 'DEFAULT' to be returned by the getProperty(),
167 // or in an unlikely instance when someone sets
168 // -Dorg.jdom.output.LineSeparator=DEFAULT
169 // which would create some sort of loop to happen....
170 return "\r\n";
171 } else if ("SYSTEM".equals(prop)) {
172 return System.getProperty("line.separator");
173 } else if ("CRNL".equals(prop)) {
174 return "\r\n";
175 } else if ("NL".equals(prop)) {
176 return "\n";
177 } else if ("CR".equals(prop)) {
178 return "\r";
179 } else if ("DOS".equals(prop)) {
180 return "\r\n";
181 } else if ("UNIX".equals(prop)) {
182 return "\n";
183 } else if ("NONE".equals(prop)) {
184 return null;
185 }
186 return prop;
187 }
188
189
190
191 private final String value;
192
193 LineSeparator(String value) {
194 this.value = value;
195 }
196
197 /**
198 * The String sequence used for this Separator
199 * @return an End-Of-Line String
200 */
201 public String value() {
202 return value;
203 }
204
205 }
0 /*--
1
2 $Id: NamespaceStack.java,v 1.14 2007/11/10 05:29:01 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55 package org.jdom.output;
56
57 import java.util.*;
58
59 import org.jdom.Namespace;
60
61 /**
62 * A non-public utility class used by both <code>{@link XMLOutputter}</code> and
63 * <code>{@link SAXOutputter}</code> to manage namespaces in a JDOM Document
64 * during output.
65 *
66 * @version $Revision: 1.14 $, $Date: 2007/11/10 05:29:01 $
67 * @author Elliotte Rusty Harolde
68 * @author Fred Trimble
69 * @author Brett McLaughlin
70 */
71 class NamespaceStack {
72
73 private static final String CVS_ID =
74 "@(#) $RCSfile: NamespaceStack.java,v $ $Revision: 1.14 $ $Date: 2007/11/10 05:29:01 $ $Name: $";
75
76 /** The prefixes available */
77 private Stack prefixes;
78
79 /** The URIs available */
80 private Stack uris;
81
82 /**
83 * This creates the needed storage.
84 */
85 NamespaceStack() {
86 prefixes = new Stack();
87 uris = new Stack();
88 }
89
90 /**
91 * This will add a new <code>{@link Namespace}</code>
92 * to those currently available.
93 *
94 * @param ns <code>Namespace</code> to add.
95 */
96 public void push(Namespace ns) {
97 prefixes.push(ns.getPrefix());
98 uris.push(ns.getURI());
99 }
100
101 /**
102 * This will remove the topmost (most recently added)
103 * <code>{@link Namespace}</code>, and return its prefix.
104 *
105 * @return <code>String</code> - the popped namespace prefix.
106 */
107 public String pop() {
108 String prefix = (String)prefixes.pop();
109 uris.pop();
110
111 return prefix;
112 }
113
114 /**
115 * This returns the number of available namespaces.
116 *
117 * @return <code>int</code> - size of the namespace stack.
118 */
119 public int size() {
120 return prefixes.size();
121 }
122
123 /**
124 * Given a prefix, this will return the namespace URI most
125 * rencently (topmost) associated with that prefix.
126 *
127 * @param prefix <code>String</code> namespace prefix.
128 * @return <code>String</code> - the namespace URI for that prefix.
129 */
130 public String getURI(String prefix) {
131 int index = prefixes.lastIndexOf(prefix);
132 if (index == -1) {
133 return null;
134 }
135 String uri = (String)uris.elementAt(index);
136 return uri;
137 }
138
139 /**
140 * This will print out the size and current stack, from the
141 * most recently added <code>{@link Namespace}</code> to
142 * the "oldest," all to <code>System.out</code>.
143 */
144 public String toString() {
145 StringBuffer buf = new StringBuffer();
146 String sep = System.getProperty("line.separator");
147 buf.append("Stack: " + prefixes.size() + sep);
148 for (int i = 0; i < prefixes.size(); i++) {
149 buf.append(prefixes.elementAt(i) + "&" + uris.elementAt(i) + sep);
150 }
151 return buf.toString();
152 }
153 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output;
55
56 import static org.jdom.JDOMConstants.*;
57
58 import java.util.List;
59
60 import org.xml.sax.ContentHandler;
61 import org.xml.sax.DTDHandler;
62 import org.xml.sax.EntityResolver;
63 import org.xml.sax.ErrorHandler;
64 import org.xml.sax.SAXException;
65 import org.xml.sax.SAXNotRecognizedException;
66 import org.xml.sax.SAXNotSupportedException;
67 import org.xml.sax.SAXParseException;
68 import org.xml.sax.ext.DeclHandler;
69 import org.xml.sax.ext.LexicalHandler;
70
71 import org.jdom.CDATA;
72 import org.jdom.Comment;
73 import org.jdom.Content;
74 import org.jdom.DocType;
75 import org.jdom.Document;
76 import org.jdom.Element;
77 import org.jdom.EntityRef;
78 import org.jdom.JDOMException;
79 import org.jdom.ProcessingInstruction;
80 import org.jdom.Text;
81 import org.jdom.output.support.AbstractSAXOutputProcessor;
82 import org.jdom.output.support.SAXOutputProcessor;
83 import org.jdom.output.support.SAXTarget;
84
85 /**
86 * Outputs a JDOM document as a stream of SAX2 events.
87 * <p>
88 * Most ContentHandler callbacks are supported. BOTH
89 * <code>ignorableWhitespace()</code> and <code>skippedEntity()</code> have not
90 * been implemented. The <code>{@link JDOMLocator}</code> class returned by
91 * <code>{@link #getLocator}</code> exposes the current node being operated
92 * upon.
93 * <p>
94 * At this time, it is not possible to access notations and unparsed entity
95 * references in a DTD from JDOM. Therefore, <code>DTDHandler</code> callbacks
96 * have not been implemented yet.
97 * <p>
98 * The <code>ErrorHandler</code> callbacks have not been implemented, since
99 * these are supposed to be invoked when the document is parsed and at this
100 * point the document exists in memory and is known to have no errors.
101 * </p>
102 *
103 * @author Brett McLaughlin
104 * @author Jason Hunter
105 * @author Fred Trimble
106 * @author Bradley S. Huffman
107 */
108 public class SAXOutputter {
109
110 private static final class DefaultSAXOutputProcessor extends
111 AbstractSAXOutputProcessor {
112 // nothing.
113 }
114
115 private static final SAXOutputProcessor DEFAULT_PROCESSOR = new DefaultSAXOutputProcessor();
116
117 /** registered <code>ContentHandler</code> */
118 private ContentHandler contentHandler;
119
120 /** registered <code>ErrorHandler</code> */
121 private ErrorHandler errorHandler;
122
123 /** registered <code>DTDHandler</code> */
124 private DTDHandler dtdHandler;
125
126 /** registered <code>EntityResolver</code> */
127 private EntityResolver entityResolver;
128
129 /** registered <code>LexicalHandler</code> */
130 private LexicalHandler lexicalHandler;
131
132 /** registered <code>DeclHandler</code> */
133 private DeclHandler declHandler;
134
135 /**
136 * Whether to report attribute namespace declarations as xmlns attributes.
137 * Defaults to <code>false</code> as per SAX specifications.
138 *
139 * @see <a href="http://www.megginson.com/SAX/Java/namespaces.html"> SAX
140 * namespace specifications</a>
141 */
142 private boolean declareNamespaces = false;
143
144 /**
145 * Whether to report DTD events to DeclHandlers and LexicalHandlers.
146 * Defaults to <code>true</code>.
147 */
148 private boolean reportDtdEvents = true;
149
150 /**
151 * A SAXOutputProcessor
152 */
153 private SAXOutputProcessor processor = DEFAULT_PROCESSOR;
154
155 /**
156 * The Format to use for output.
157 */
158 private Format format = Format.getRawFormat();
159
160 /**
161 * This will create a <code>SAXOutputter</code> without any registered
162 * handler. The application is then responsible for registering them using
163 * the <code>setXxxHandler()</code> methods.
164 */
165 public SAXOutputter() {
166 }
167
168 /**
169 * This will create a <code>SAXOutputter</code> with the specified
170 * <code>ContentHandler</code>.
171 *
172 * @param contentHandler
173 * contains <code>ContentHandler</code> callback methods
174 */
175 public SAXOutputter(ContentHandler contentHandler) {
176 this(contentHandler, null, null, null, null);
177 }
178
179 /**
180 * This will create a <code>SAXOutputter</code> with the specified SAX2
181 * handlers. At this time, only <code>ContentHandler</code> and
182 * <code>EntityResolver</code> are supported.
183 *
184 * @param contentHandler
185 * contains <code>ContentHandler</code> callback methods
186 * @param errorHandler
187 * contains <code>ErrorHandler</code> callback methods
188 * @param dtdHandler
189 * contains <code>DTDHandler</code> callback methods
190 * @param entityResolver
191 * contains <code>EntityResolver</code> callback methods
192 */
193 public SAXOutputter(ContentHandler contentHandler,
194 ErrorHandler errorHandler, DTDHandler dtdHandler,
195 EntityResolver entityResolver) {
196 this(contentHandler, errorHandler, dtdHandler, entityResolver, null);
197 }
198
199 /**
200 * This will create a <code>SAXOutputter</code> with the specified SAX2
201 * handlers. At this time, only <code>ContentHandler</code> and
202 * <code>EntityResolver</code> are supported.
203 *
204 * @param contentHandler
205 * contains <code>ContentHandler</code> callback methods
206 * @param errorHandler
207 * contains <code>ErrorHandler</code> callback methods
208 * @param dtdHandler
209 * contains <code>DTDHandler</code> callback methods
210 * @param entityResolver
211 * contains <code>EntityResolver</code> callback methods
212 * @param lexicalHandler
213 * contains <code>LexicalHandler</code> callbacks.
214 */
215 public SAXOutputter(ContentHandler contentHandler,
216 ErrorHandler errorHandler, DTDHandler dtdHandler,
217 EntityResolver entityResolver, LexicalHandler lexicalHandler) {
218 this.contentHandler = contentHandler;
219 this.errorHandler = errorHandler;
220 this.dtdHandler = dtdHandler;
221 this.entityResolver = entityResolver;
222 this.lexicalHandler = lexicalHandler;
223 }
224
225 /**
226 * This will create a <code>SAXOutputter</code> with the specified SAX2
227 * handlers. At this time, only <code>ContentHandler</code> and
228 * <code>EntityResolver</code> are supported.
229 *
230 * @param processor
231 * the {@link SAXOutputProcessor} to use for output.
232 * @param format
233 * the {@link Format} to use for output.
234 * @param contentHandler
235 * contains <code>ContentHandler</code> callback methods
236 * @param errorHandler
237 * contains <code>ErrorHandler</code> callback methods
238 * @param dtdHandler
239 * contains <code>DTDHandler</code> callback methods
240 * @param entityResolver
241 * contains <code>EntityResolver</code> callback methods
242 * @param lexicalHandler
243 * contains <code>LexicalHandler</code> callbacks.
244 */
245 public SAXOutputter(SAXOutputProcessor processor, Format format,
246 ContentHandler contentHandler, ErrorHandler errorHandler,
247 DTDHandler dtdHandler, EntityResolver entityResolver,
248 LexicalHandler lexicalHandler) {
249 this.processor = processor == null ? DEFAULT_PROCESSOR : processor;
250 this.format = format == null ? Format.getRawFormat() : format;
251 this.contentHandler = contentHandler;
252 this.errorHandler = errorHandler;
253 this.dtdHandler = dtdHandler;
254 this.entityResolver = entityResolver;
255 this.lexicalHandler = lexicalHandler;
256 }
257
258 /**
259 * This will set the <code>ContentHandler</code>.
260 *
261 * @param contentHandler
262 * contains <code>ContentHandler</code> callback methods.
263 */
264 public void setContentHandler(ContentHandler contentHandler) {
265 this.contentHandler = contentHandler;
266 }
267
268 /**
269 * Returns the registered <code>ContentHandler</code>.
270 *
271 * @return the current <code>ContentHandler</code> or <code>null</code> if
272 * none was registered.
273 */
274 public ContentHandler getContentHandler() {
275 return this.contentHandler;
276 }
277
278 /**
279 * This will set the <code>ErrorHandler</code>.
280 *
281 * @param errorHandler
282 * contains <code>ErrorHandler</code> callback methods.
283 */
284 public void setErrorHandler(ErrorHandler errorHandler) {
285 this.errorHandler = errorHandler;
286 }
287
288 /**
289 * Return the registered <code>ErrorHandler</code>.
290 *
291 * @return the current <code>ErrorHandler</code> or <code>null</code> if
292 * none was registered.
293 */
294 public ErrorHandler getErrorHandler() {
295 return this.errorHandler;
296 }
297
298 /**
299 * This will set the <code>DTDHandler</code>.
300 *
301 * @param dtdHandler
302 * contains <code>DTDHandler</code> callback methods.
303 */
304 public void setDTDHandler(DTDHandler dtdHandler) {
305 this.dtdHandler = dtdHandler;
306 }
307
308 /**
309 * Return the registered <code>DTDHandler</code>.
310 *
311 * @return the current <code>DTDHandler</code> or <code>null</code> if none
312 * was registered.
313 */
314 public DTDHandler getDTDHandler() {
315 return this.dtdHandler;
316 }
317
318 /**
319 * This will set the <code>EntityResolver</code>.
320 *
321 * @param entityResolver
322 * contains EntityResolver callback methods.
323 */
324 public void setEntityResolver(EntityResolver entityResolver) {
325 this.entityResolver = entityResolver;
326 }
327
328 /**
329 * Return the registered <code>EntityResolver</code>.
330 *
331 * @return the current <code>EntityResolver</code> or <code>null</code> if
332 * none was registered.
333 */
334 public EntityResolver getEntityResolver() {
335 return this.entityResolver;
336 }
337
338 /**
339 * This will set the <code>LexicalHandler</code>.
340 *
341 * @param lexicalHandler
342 * contains lexical callback methods.
343 */
344 public void setLexicalHandler(LexicalHandler lexicalHandler) {
345 this.lexicalHandler = lexicalHandler;
346 }
347
348 /**
349 * Return the registered <code>LexicalHandler</code>.
350 *
351 * @return the current <code>LexicalHandler</code> or <code>null</code> if
352 * none was registered.
353 */
354 public LexicalHandler getLexicalHandler() {
355 return this.lexicalHandler;
356 }
357
358 /**
359 * This will set the <code>DeclHandler</code>.
360 *
361 * @param declHandler
362 * contains declaration callback methods.
363 */
364 public void setDeclHandler(DeclHandler declHandler) {
365 this.declHandler = declHandler;
366 }
367
368 /**
369 * Return the registered <code>DeclHandler</code>.
370 *
371 * @return the current <code>DeclHandler</code> or <code>null</code> if none
372 * was registered.
373 */
374 public DeclHandler getDeclHandler() {
375 return this.declHandler;
376 }
377
378 /**
379 * Returns whether attribute namespace declarations shall be reported as
380 * "xmlns" attributes.
381 *
382 * @return whether attribute namespace declarations shall be reported as
383 * "xmlns" attributes.
384 */
385 public boolean getReportNamespaceDeclarations() {
386 return declareNamespaces;
387 }
388
389 /**
390 * This will define whether attribute namespace declarations shall be
391 * reported as "xmlns" attributes. This flag defaults to <code>false</code>
392 * and behaves as the "namespace-prefixes" SAX core feature.
393 *
394 * @param declareNamespaces
395 * whether attribute namespace declarations shall be reported as
396 * "xmlns" attributes.
397 */
398 public void setReportNamespaceDeclarations(boolean declareNamespaces) {
399 this.declareNamespaces = declareNamespaces;
400 }
401
402 /**
403 * Returns whether DTD events will be reported.
404 *
405 * @return whether DTD events will be reported
406 */
407 public boolean getReportDTDEvents() {
408 return reportDtdEvents;
409 }
410
411 /**
412 * This will define whether to report DTD events to SAX DeclHandlers and
413 * LexicalHandlers if these handlers are registered and the document to
414 * output includes a DocType declaration.
415 *
416 * @param reportDtdEvents
417 * whether to notify DTD events.
418 */
419 public void setReportDTDEvents(boolean reportDtdEvents) {
420 this.reportDtdEvents = reportDtdEvents;
421 }
422
423 /**
424 * This will set the state of a SAX feature.
425 * <p>
426 * All XMLReaders are required to support setting to true and to false.
427 * </p>
428 * <p>
429 * SAXOutputter currently supports the following SAX core features:
430 * <dl>
431 * <dt><code>http://xml.org/sax/features/namespaces</code></dt>
432 * <dd><strong>description:</strong> <code>true</code> indicates namespace
433 * URIs and unprefixed local names for element and attribute names will be
434 * available</dd>
435 * <dd><strong>access:</strong> read/write, but always <code>true</code>!</dd>
436 * <dt><code>http://xml.org/sax/features/namespace-prefixes</code></dt>
437 * <dd><strong>description:</strong> <code>true</code> indicates XML 1.0
438 * names (with prefixes) and attributes (including xmlns* attributes) will
439 * be available</dd>
440 * <dd><strong>access:</strong> read/write</dd>
441 * <dt><code>http://xml.org/sax/features/validation</code></dt>
442 * <dd><strong>description:</strong> controls whether SAXOutputter is
443 * reporting DTD-related events; if <code>true</code>, the DocType internal
444 * subset will be parsed to fire DTD events</dd>
445 * <dd><strong>access:</strong> read/write, defaults to <code>true</code></dd>
446 * </dl>
447 * </p>
448 *
449 * @param name
450 * <code>String</code> the feature name, which is a fully-qualified
451 * URI.
452 * @param value
453 * <code>boolean</code> the requested state of the feature (true or
454 * false).
455 * @throws SAXNotRecognizedException
456 * when SAXOutputter does not recognize the feature name.
457 * @throws SAXNotSupportedException
458 * when SAXOutputter recognizes the feature name but cannot set the
459 * requested value.
460 */
461 public void setFeature(String name, boolean value)
462 throws SAXNotRecognizedException, SAXNotSupportedException {
463 if (SAX_FEATURE_NAMESPACE_PREFIXES.equals(name)) {
464 // Namespace prefix declarations.
465 this.setReportNamespaceDeclarations(value);
466 } else {
467 if (SAX_FEATURE_NAMESPACES.equals(name)) {
468 if (value != true) {
469 // Namespaces feature always supported by SAXOutputter.
470 throw new SAXNotSupportedException(name);
471 }
472 // Else: true is OK!
473 } else {
474 if (SAX_FEATURE_VALIDATION.equals(name)) {
475 // Report DTD events.
476 this.setReportDTDEvents(value);
477 } else {
478 // Not a supported feature.
479 throw new SAXNotRecognizedException(name);
480 }
481 }
482 }
483 }
484
485 /**
486 * This will look up the value of a SAX feature.
487 *
488 * @param name
489 * <code>String</code> the feature name, which is a fully-qualified
490 * URI.
491 * @return <code>boolean</code> the current state of the feature (true or
492 * false).
493 * @throws SAXNotRecognizedException
494 * when SAXOutputter does not recognize the feature name.
495 * @throws SAXNotSupportedException
496 * when SAXOutputter recognizes the feature name but determine its
497 * value at this time.
498 */
499 public boolean getFeature(String name) throws SAXNotRecognizedException,
500 SAXNotSupportedException {
501 if (SAX_FEATURE_NAMESPACE_PREFIXES.equals(name)) {
502 // Namespace prefix declarations.
503 return (this.declareNamespaces);
504 }
505 if (SAX_FEATURE_NAMESPACES.equals(name)) {
506 // Namespaces feature always supported by SAXOutputter.
507 return (true);
508 }
509 if (SAX_FEATURE_VALIDATION.equals(name)) {
510 // Report DTD events.
511 return (this.reportDtdEvents);
512 }
513 // Not a supported feature.
514 throw new SAXNotRecognizedException(name);
515 }
516
517 /**
518 * This will set the value of a SAX property. This method is also the
519 * standard mechanism for setting extended handlers.
520 * <p>
521 * SAXOutputter currently supports the following SAX properties:
522 * <dl>
523 * <dt><code>http://xml.org/sax/properties/lexical-handler</code></dt>
524 * <dd><strong>data type:</strong>
525 * <code>org.xml.sax.ext.LexicalHandler</code></dd>
526 * <dd><strong>description:</strong> An optional extension handler for
527 * lexical events like comments.</dd>
528 * <dd><strong>access:</strong> read/write</dd>
529 * <dt><code>http://xml.org/sax/properties/declaration-handler</code></dt>
530 * <dd><strong>data type:</strong> <code>org.xml.sax.ext.DeclHandler</code></dd>
531 * <dd><strong>description:</strong> An optional extension handler for
532 * DTD-related events other than notations and unparsed entities.</dd>
533 * <dd><strong>access:</strong> read/write</dd>
534 * </dl>
535 * </p>
536 *
537 * @param name
538 * <code>String</code> the property name, which is a fully-qualified
539 * URI.
540 * @param value
541 * <code>Object</code> the requested value for the property.
542 * @throws SAXNotRecognizedException
543 * when SAXOutputter does not recognize the property name.
544 * @throws SAXNotSupportedException
545 * when SAXOutputter recognizes the property name but cannot set the
546 * requested value.
547 */
548 public void setProperty(String name, Object value)
549 throws SAXNotRecognizedException, SAXNotSupportedException {
550 if ((SAX_PROPERTY_LEXICAL_HANDLER.equals(name))
551 || (SAX_PROPERTY_LEXICAL_HANDLER_ALT.equals(name))) {
552 this.setLexicalHandler((LexicalHandler) value);
553 } else {
554 if ((SAX_PROPERTY_DECLARATION_HANDLER.equals(name))
555 || (SAX_PROPERTY_DECLARATION_HANDLER_ALT.equals(name))) {
556 this.setDeclHandler((DeclHandler) value);
557 } else {
558 throw new SAXNotRecognizedException(name);
559 }
560 }
561 }
562
563 /**
564 * This will look up the value of a SAX property.
565 *
566 * @param name
567 * <code>String</code> the property name, which is a fully-qualified
568 * URI.
569 * @return <code>Object</code> the current value of the property.
570 * @throws SAXNotRecognizedException
571 * when SAXOutputter does not recognize the property name.
572 * @throws SAXNotSupportedException
573 * when SAXOutputter recognizes the property name but cannot
574 * determine its value at this time.
575 */
576 public Object getProperty(String name) throws SAXNotRecognizedException,
577 SAXNotSupportedException {
578 if ((SAX_PROPERTY_LEXICAL_HANDLER.equals(name))
579 || (SAX_PROPERTY_LEXICAL_HANDLER_ALT.equals(name))) {
580 return this.getLexicalHandler();
581 }
582 if ((SAX_PROPERTY_DECLARATION_HANDLER.equals(name))
583 || (SAX_PROPERTY_DECLARATION_HANDLER_ALT.equals(name))) {
584 return this.getDeclHandler();
585 }
586 throw new SAXNotRecognizedException(name);
587 }
588
589 /**
590 * Get the current {@link SAXOutputProcessor} being used for output.
591 *
592 * @return The current SAXOutputProcessor
593 */
594 public SAXOutputProcessor getSAXOutputProcessor() {
595 return processor;
596 }
597
598 /**
599 * Set the current {@link SAXOutputProcessor} to be used for output.
600 *
601 * @param processor
602 * the new SAXOutputProcessor
603 */
604 public void setSAXOutputProcessor(SAXOutputProcessor processor) {
605 this.processor = processor == null ? DEFAULT_PROCESSOR : processor;
606 }
607
608 /**
609 * Get the current {@link Format} being used for output
610 *
611 * @return the current Format
612 */
613 public Format getFormat() {
614 return format;
615 }
616
617 /**
618 * Set the current {@link Format} to be used for output.
619 *
620 * @param format
621 * the new Format
622 */
623 public void setFormat(Format format) {
624 this.format = format == null ? Format.getRawFormat() : format;
625 }
626
627 private final SAXTarget buildTarget(Document doc) {
628 String publicID = null;
629 String systemID = null;
630 if (doc != null) {
631 DocType dt = doc.getDocType();
632 if (dt != null) {
633 publicID = dt.getPublicID();
634 systemID = dt.getSystemID();
635 }
636 }
637 return new SAXTarget(contentHandler, errorHandler, dtdHandler,
638 entityResolver, lexicalHandler, declHandler, declareNamespaces,
639 reportDtdEvents, publicID, systemID);
640 }
641
642 /**
643 * This will output the <code>JDOM Document</code>, firing off the SAX
644 * events that have been registered.
645 *
646 * @param document
647 * <code>JDOM Document</code> to output.
648 * @throws JDOMException
649 * if any error occurred.
650 */
651 public void output(Document document) throws JDOMException {
652 processor.process(buildTarget(document), format, document);
653 }
654
655 /**
656 * This will output a list of JDOM nodes as a document, firing off the SAX
657 * events that have been registered.
658 * <p>
659 * <strong>Warning</strong>: This method may output ill-formed XML documents
660 * if the list contains top-level objects that are not legal at the document
661 * level (e.g. Text or CDATA nodes, multiple Element nodes, etc.). Thus, it
662 * should only be used to output document portions towards ContentHandlers
663 * capable of accepting such ill-formed documents (such as XSLT processors).
664 * </p>
665 *
666 * @param nodes
667 * <code>List</code> of JDOM nodes to output.
668 * @throws JDOMException
669 * if any error occurred.
670 * @see #output(org.jdom.Document)
671 */
672 public void output(List<? extends Content> nodes) throws JDOMException {
673 processor.processAsDocument(buildTarget(null), format, nodes);
674 }
675
676 /**
677 * This will output a single JDOM element as a document, firing off the SAX
678 * events that have been registered.
679 *
680 * @param node
681 * the <code>Element</code> node to output.
682 * @throws JDOMException
683 * if any error occurred.
684 */
685 public void output(Element node) throws JDOMException {
686 processor.processAsDocument(buildTarget(null), format, node);
687 }
688
689 /**
690 * This will output a list of JDOM nodes as a fragment of an XML document,
691 * firing off the SAX events that have been registered.
692 * <p>
693 * <strong>Warning</strong>: This method does not call the
694 * {@link ContentHandler#setDocumentLocator},
695 * {@link ContentHandler#startDocument} and
696 * {@link ContentHandler#endDocument} callbacks on the
697 * {@link #setContentHandler ContentHandler}. The user shall invoke these
698 * methods directly prior/after outputting the document fragments.
699 * </p>
700 *
701 * @param nodes
702 * <code>List</code> of JDOM nodes to output.
703 * @throws JDOMException
704 * if any error occurred.
705 * @see #outputFragment(org.jdom.Content)
706 */
707 public void outputFragment(List<? extends Content> nodes)
708 throws JDOMException {
709 if (nodes == null) {
710 return;
711 }
712 processor.process(buildTarget(null), format, nodes);
713 }
714
715 /**
716 * This will output a single JDOM nodes as a fragment of an XML document,
717 * firing off the SAX events that have been registered.
718 * <p>
719 * <strong>Warning</strong>: This method does not call the
720 * {@link ContentHandler#setDocumentLocator},
721 * {@link ContentHandler#startDocument} and
722 * {@link ContentHandler#endDocument} callbacks on the
723 * {@link #setContentHandler ContentHandler}. The user shall invoke these
724 * methods directly prior/after outputting the document fragments.
725 * </p>
726 *
727 * @param node
728 * the <code>Content</code> node to output.
729 * @throws JDOMException
730 * if any error occurred.
731 * @see #outputFragment(java.util.List)
732 */
733 public void outputFragment(Content node) throws JDOMException {
734 if (node == null) {
735 return;
736 }
737
738 SAXTarget out = buildTarget(null);
739
740 switch (node.getCType()) {
741 case CDATA:
742 processor.process(out, format, (CDATA) node);
743 break;
744 case Comment:
745 processor.process(out, format, (Comment) node);
746 break;
747 case Element:
748 processor.process(out, format, (Element) node);
749 break;
750 case EntityRef:
751 processor.process(out, format, (EntityRef) node);
752 break;
753 case ProcessingInstruction:
754 processor.process(out, format, (ProcessingInstruction) node);
755 break;
756 case Text:
757 processor.process(out, format, (Text) node);
758 break;
759 default:
760 handleError(new JDOMException("Invalid element content: " + node));
761 }
762
763 }
764
765 /**
766 * <p>
767 * Notifies the registered {@link ErrorHandler SAX error handler}
768 * (if any) of an input processing error. The error handler can
769 * choose to absorb the error and let the processing continue.
770 * </p>
771 *
772 * @param exception <code>JDOMException</code> containing the
773 * error information; will be wrapped in a
774 * {@link SAXParseException} when reported to
775 * the SAX error handler.
776 *
777 * @throws JDOMException if no error handler has been registered
778 * or if the error handler fired a
779 * {@link SAXException}.
780 */
781 private void handleError(JDOMException exception) throws JDOMException {
782 if (errorHandler != null) {
783 try {
784 errorHandler.error(new SAXParseException(
785 exception.getMessage(), null, exception));
786 }
787 catch (SAXException se) {
788 if (se.getException() instanceof JDOMException) {
789 throw (JDOMException)(se.getException());
790 }
791 throw new JDOMException(se.getMessage(), se);
792 }
793 }
794 else {
795 throw exception;
796 }
797 }
798
799
800 /**
801 * Returns null.
802 *
803 * @return null
804 * @deprecated there is no way to get a meaningful document Locator outside
805 * of an active output process, and the contents of the locator
806 * are meaningless outside of an active output process anyway.
807 */
808 @Deprecated
809 public JDOMLocator getLocator() {
810 return null;
811 }
812 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output;
55
56 import java.util.List;
57
58 import javax.xml.stream.XMLEventFactory;
59 import javax.xml.stream.XMLStreamException;
60 import javax.xml.stream.util.XMLEventConsumer;
61
62 import org.jdom.Attribute;
63 import org.jdom.CDATA;
64 import org.jdom.Comment;
65 import org.jdom.Content;
66 import org.jdom.DocType;
67 import org.jdom.Document;
68 import org.jdom.Element;
69 import org.jdom.EntityRef;
70 import org.jdom.ProcessingInstruction;
71 import org.jdom.Text;
72 import org.jdom.output.support.AbstractStAXEventProcessor;
73 import org.jdom.output.support.StAXEventProcessor;
74 import org.jdom.output.support.XMLOutputProcessor;
75
76 /**
77 * Outputs a JDOM document as a StAX XMLEventConsumer of bytes.
78 * <p>
79 * The StAXStreamOutputter can manage many styles of document formatting, from
80 * untouched to 'pretty' printed. The default is to output the document content
81 * exactly as created, but this can be changed by setting a new Format object:
82 * <ul>
83 * <li>For pretty-print output, use
84 * <code>{@link Format#getPrettyFormat()}</code>.
85 * <li>For whitespace-normalised output, use
86 * <code>{@link Format#getCompactFormat()}</code>.
87 * <li>For unmodified-format output, use
88 * <code>{@link Format#getRawFormat()}</code>.
89 * </ul>
90 * <p>
91 * <b>All</b> of the <code>output*(...)</code> methods will flush the
92 * destination XMLEventConsumer before returning, and <b>none</b> of them
93 * will <code>close()</code> the destination.
94 * <p>
95 * To omit output of the declaration use
96 * <code>{@link Format#setOmitDeclaration}</code>. To omit printing of the
97 * encoding in the declaration use <code>{@link Format#setOmitEncoding}</code>.
98 * <p>
99 * If changing the {@link Format} settings are insufficient for your output
100 * needs you can customise this StAXStreamOutputter further by setting a different
101 * {@link StAXEventProcessor} with the
102 * {@link #setStAXEventProcessor(StAXEventProcessor)} method or an appropriate
103 * constructor. A fully-enabled Abstract class
104 * {@link AbstractStAXEventProcessor} is available to be further extended to
105 * your needs if all you want to do is tweak some details.
106 *
107 * @since JDOM2
108 * @author Rolf Lear
109 */
110
111 public final class StAXEventOutputter implements Cloneable {
112
113 /*
114 * =====================================================================
115 * Static content.
116 * =====================================================================
117 */
118
119 /**
120 * Create a final and static instance of the AbstractStAXEventProcessor The
121 * final part is important because it improves performance.
122 * <p>
123 * The JDOM user can change the actual XMLOutputProcessor with the
124 * {@link StAXEventOutputter#setStAXEventProcessor(StAXEventProcessor)} method.
125 *
126 * @author rolf
127 */
128 private static final class DefaultStAXEventProcessor
129 extends AbstractStAXEventProcessor {
130 // nothing
131 }
132
133 /**
134 * This constant StAXEventProcessor is used for all non-customised
135 * StAXStreamOutputters
136 */
137 private static final DefaultStAXEventProcessor DEFAULTPROCESSOR =
138 new DefaultStAXEventProcessor();
139
140 /**
141 * This constant StAXEventProcessor is used for all non-customised
142 * StAXStreamOutputters
143 */
144 private static final XMLEventFactory DEFAULTEVENTFACTORY =
145 XMLEventFactory.newInstance();
146
147 /*
148 * =====================================================================
149 * Instance content.
150 * =====================================================================
151 */
152
153 // For normal output
154 private Format myFormat = null;
155
156 // The actual StAXEventProcessor to delegate to.
157 private StAXEventProcessor myProcessor = null;
158
159 private XMLEventFactory myEventFactory = null;
160
161 /*
162 * =====================================================================
163 * Constructors
164 * =====================================================================
165 */
166
167 /**
168 * This will create an <code>StAXStreamOutputter</code> with the specified format
169 * characteristics.
170 * <p>
171 * <b>Note:</b> the format object is cloned internally before use. If you
172 * want to modify the Format after constructing the StAXStreamOutputter you can
173 * modify the Format instance {@link #getFormat()} returns.
174 *
175 * @param format
176 * The Format instance to use. This instance will be cloned() and as
177 * a consequence, changes made to the specified format instance
178 * <b>will not</b> be reflected in this StAXStreamOutputter. A null input
179 * format indicates that StAXStreamOutputter should use the default
180 * {@link Format#getRawFormat()}
181 * @param processor
182 * The XMLOutputProcessor to delegate output to. If null the
183 * StAXStreamOutputter will use the default XMLOutputProcessor.
184 * @param eventfactory
185 * The factory to use to create XMLEvent instances.
186 */
187 public StAXEventOutputter(Format format, StAXEventProcessor processor, XMLEventFactory eventfactory) {
188 myFormat = format == null ? Format.getRawFormat() : format.clone();
189 myProcessor = processor == null ? DEFAULTPROCESSOR : processor;
190 myEventFactory = eventfactory == null ? DEFAULTEVENTFACTORY : eventfactory;
191 }
192
193 /**
194 * This will create an <code>StAXStreamOutputter</code> with a default
195 * {@link Format} and {@link XMLOutputProcessor}.
196 */
197 public StAXEventOutputter() {
198 this(null, null, null);
199 }
200
201 /**
202 * This will create an <code>StAXStreamOutputter</code> with the specified format
203 * characteristics.
204 * <p>
205 * <b>Note:</b> the format object is cloned internally before use.
206 *
207 * @param format
208 * The Format instance to use. This instance will be cloned() and as
209 * a consequence, changes made to the specified format instance
210 * <b>will not</b> be reflected in this StAXStreamOutputter. A null input
211 * format indicates that StAXStreamOutputter should use the default
212 * {@link Format#getRawFormat()}
213 */
214 public StAXEventOutputter(Format format) {
215 this(format, null, null);
216 }
217
218 /**
219 * This will create an <code>StAXStreamOutputter</code> with the specified
220 * XMLOutputProcessor.
221 *
222 * @param processor
223 * The XMLOutputProcessor to delegate output to. If null the
224 * StAXStreamOutputter will use the default XMLOutputProcessor.
225 */
226 public StAXEventOutputter(StAXEventProcessor processor) {
227 this(null, processor, null);
228 }
229
230 /**
231 * This will create an <code>StAXStreamOutputter</code> with the specified
232 * XMLOutputProcessor.
233 *
234 * @param eventfactory
235 * The XMLEventFactory to use to create XMLEvent instances.
236 */
237 public StAXEventOutputter(XMLEventFactory eventfactory) {
238 this(null, null, eventfactory);
239 }
240
241 /*
242 * =======================================================================
243 * API - Settings...
244 * =======================================================================
245 */
246
247 /**
248 * Sets the new format logic for the StAXStreamOutputter. Note the Format object is
249 * cloned internally before use.
250 *
251 * @see #getFormat()
252 * @param newFormat
253 * the format to use for subsequent output
254 */
255 public void setFormat(Format newFormat) {
256 this.myFormat = newFormat.clone();
257 }
258
259 /**
260 * Returns the current format in use by the StAXStreamOutputter. Note the Format
261 * object returned is <b>not</b> a clone of the one used internally, thus,
262 * an StAXStreamOutputter instance is able to have it's Format changed by changing
263 * the settings on the Format instance returned by this method.
264 *
265 * @return the current Format instance used by this StAXStreamOutputter.
266 */
267 public Format getFormat() {
268 return myFormat;
269 }
270
271 /**
272 * Returns the current XMLOutputProcessor instance in use by the
273 * StAXStreamOutputter.
274 *
275 * @return the current XMLOutputProcessor instance.
276 */
277 public StAXEventProcessor getStAXStream() {
278 return myProcessor;
279 }
280
281 /**
282 * Sets a new XMLOutputProcessor instance for this StAXStreamOutputter. Note the
283 * processor object is expected to be thread-safe.
284 *
285 * @param processor
286 * the new XMLOutputProcesor to use for output
287 */
288 public void setStAXEventProcessor(StAXEventProcessor processor) {
289 this.myProcessor = processor;
290 }
291
292
293
294 /**
295 * @return the current XMLEventFactory used by this StAXEventOutputter
296 */
297 public XMLEventFactory getEventFactory() {
298 return myEventFactory;
299 }
300
301 /**
302 * @param myEventFactory the XMLEventFactory to use for subsequent output.
303 */
304 public void setEventFactory(XMLEventFactory myEventFactory) {
305 this.myEventFactory = myEventFactory;
306 }
307
308 /*
309 * ========================================================================
310 * API - Output to XMLEventConsumer Methods ... These are the core methods that the
311 * Stream and String output methods call. On the other hand, these methods
312 * defer to the protected/override methods. These methods flush the writer.
313 * ========================================================================
314 */
315
316 /**
317 * This will print the <code>Document</code> to the given Writer.
318 * <p>
319 * Warning: using your own Writer may cause the outputter's preferred
320 * character encoding to be ignored. If you use encodings other than UTF-8,
321 * we recommend using the method that takes an OutputStream instead.
322 * </p>
323 *
324 * @param doc
325 * <code>Document</code> to format.
326 * @param out
327 * <code>XMLEventConsumer</code> to use.
328 * @throws XMLStreamException
329 * - if there's any problem writing.
330 * @throws NullPointerException
331 * if the specified content is null.
332 */
333 public final void output(Document doc, XMLEventConsumer out) throws XMLStreamException {
334 myProcessor.process(out, myFormat, myEventFactory, doc);
335 //out.flush();
336 }
337
338 /**
339 * Print out the <code>{@link DocType}</code>.
340 *
341 * @param doctype
342 * <code>DocType</code> to output.
343 * @param out
344 * <code>XMLEventConsumer</code> to use.
345 * @throws XMLStreamException
346 * - if there's any problem writing.
347 * @throws NullPointerException
348 * if the specified content is null.
349 */
350 public final void output(DocType doctype, XMLEventConsumer out) throws XMLStreamException {
351 myProcessor.process(out, myFormat, myEventFactory, doctype);
352 //out.flush();
353 }
354
355 /**
356 * Print out an <code>{@link Element}</code>, including its
357 * <code>{@link Attribute}</code>s, and all contained (child) elements, etc.
358 *
359 * @param element
360 * <code>Element</code> to output.
361 * @param out
362 * <code>XMLEventConsumer</code> to use.
363 * @throws XMLStreamException
364 * - if there's any problem writing.
365 * @throws NullPointerException
366 * if the specified content is null.
367 */
368 public final void output(Element element, XMLEventConsumer out) throws XMLStreamException {
369 // If this is the root element we could pre-initialize the
370 // namespace stack with the namespaces
371 myProcessor.process(out, myFormat, myEventFactory, element);
372 //out.flush();
373 }
374
375 /**
376 * This will handle printing out an <code>{@link
377 * Element}</code>'s content only, not including its tag, and attributes.
378 * This can be useful for printing the content of an element that contains
379 * HTML, like "&lt;description&gt;JDOM is
380 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
381 *
382 * @param element
383 * <code>Element</code> to output.
384 * @param out
385 * <code>XMLEventConsumer</code> to use.
386 * @throws XMLStreamException
387 * - if there's any problem writing.
388 * @throws NullPointerException
389 * if the specified content is null.
390 */
391 public final void outputElementContent(Element element, XMLEventConsumer out)
392 throws XMLStreamException {
393 myProcessor.process(out, myFormat, myEventFactory, element.getContent());
394 //out.flush();
395 }
396
397 /**
398 * This will handle printing out a list of nodes. This can be useful for
399 * printing the content of an element that contains HTML, like
400 * "&lt;description&gt;JDOM is &lt;b&gt;fun&gt;!&lt;/description&gt;".
401 *
402 * @param list
403 * <code>List</code> of nodes.
404 * @param out
405 * <code>XMLEventConsumer</code> to use.
406 * @throws XMLStreamException
407 * - if there's any problem writing.
408 * @throws NullPointerException
409 * if the specified content is null.
410 */
411 public final void output(List<? extends Content> list, XMLEventConsumer out)
412 throws XMLStreamException {
413 myProcessor.process(out, myFormat, myEventFactory, list);
414 //out.flush();
415 }
416
417 /**
418 * Print out a <code>{@link CDATA}</code> node.
419 *
420 * @param cdata
421 * <code>CDATA</code> to output.
422 * @param out
423 * <code>XMLEventConsumer</code> to use.
424 * @throws XMLStreamException
425 * - if there's any problem writing.
426 * @throws NullPointerException
427 * if the specified content is null.
428 */
429 public final void output(CDATA cdata, XMLEventConsumer out) throws XMLStreamException {
430 myProcessor.process(out, myFormat, myEventFactory, cdata);
431 //out.flush();
432 }
433
434 /**
435 * Print out a <code>{@link Text}</code> node. Perfoms the necessary entity
436 * escaping and whitespace stripping.
437 *
438 * @param text
439 * <code>Text</code> to output.
440 * @param out
441 * <code>XMLEventConsumer</code> to use.
442 * @throws XMLStreamException
443 * - if there's any problem writing.
444 * @throws NullPointerException
445 * if the specified content is null.
446 */
447 public final void output(Text text, XMLEventConsumer out) throws XMLStreamException {
448 myProcessor.process(out, myFormat, myEventFactory, text);
449 //out.flush();
450 }
451
452 /**
453 * Print out a <code>{@link Comment}</code>.
454 *
455 * @param comment
456 * <code>Comment</code> to output.
457 * @param out
458 * <code>XMLEventConsumer</code> to use.
459 * @throws XMLStreamException
460 * - if there's any problem writing.
461 * @throws NullPointerException
462 * if the specified content is null.
463 */
464 public final void output(Comment comment, XMLEventConsumer out) throws XMLStreamException {
465 myProcessor.process(out, myFormat, myEventFactory, comment);
466 //out.flush();
467 }
468
469 /**
470 * Print out a <code>{@link ProcessingInstruction}</code>.
471 *
472 * @param pi
473 * <code>ProcessingInstruction</code> to output.
474 * @param out
475 * <code>XMLEventConsumer</code> to use.
476 * @throws XMLStreamException
477 * - if there's any problem writing.
478 * @throws NullPointerException
479 * if the specified content is null.
480 */
481 public final void output(ProcessingInstruction pi, XMLEventConsumer out)
482 throws XMLStreamException {
483 myProcessor.process(out, myFormat, myEventFactory, pi);
484 //out.flush();
485 }
486
487 /**
488 * Print out an <code>{@link EntityRef}</code>.
489 *
490 * @param entity
491 * <code>EntityRef</code> to output.
492 * @param out
493 * <code>XMLEventConsumer</code> to use.
494 * @throws XMLStreamException
495 * - if there's any problem writing.
496 * @throws NullPointerException
497 * if the specified content is null.
498 */
499 public final void output(EntityRef entity, XMLEventConsumer out) throws XMLStreamException {
500 myProcessor.process(out, myFormat, myEventFactory, entity);
501 //out.flush();
502 }
503
504 /*
505 * ========================================================================
506 * Basic Support methods.
507 * ========================================================================
508 */
509
510 /**
511 * Returns a cloned copy of this StAXStreamOutputter.
512 */
513 @Override
514 public StAXEventOutputter clone() {
515 // Implementation notes: Since all state of an StAXStreamOutputter is
516 // embodied in simple private instance variables, Object.clone
517 // can be used. Note that since Object.clone is totally
518 // broken, we must catch an exception that will never be
519 // thrown.
520 try {
521 return (StAXEventOutputter) super.clone();
522 } catch (java.lang.CloneNotSupportedException e) {
523 // even though this should never ever happen, it's still
524 // possible to fool Java into throwing a
525 // CloneNotSupportedException. If that happens, we
526 // shouldn't swallow it.
527 throw new RuntimeException(e.toString());
528 }
529 }
530
531 /**
532 * Return a string listing of the settings for this StAXStreamOutputter instance.
533 *
534 * @return a string listing the settings for this StAXStreamOutputter instance
535 */
536 @Override
537 public String toString() {
538 StringBuilder buffer = new StringBuilder();
539 buffer.append("StAXStreamOutputter[omitDeclaration = ");
540 buffer.append(myFormat.omitDeclaration);
541 buffer.append(", ");
542 buffer.append("encoding = ");
543 buffer.append(myFormat.encoding);
544 buffer.append(", ");
545 buffer.append("omitEncoding = ");
546 buffer.append(myFormat.omitEncoding);
547 buffer.append(", ");
548 buffer.append("indent = '");
549 buffer.append(myFormat.indent);
550 buffer.append("'");
551 buffer.append(", ");
552 buffer.append("expandEmptyElements = ");
553 buffer.append(myFormat.expandEmptyElements);
554 buffer.append(", ");
555 buffer.append("lineSeparator = '");
556 for (char ch : myFormat.lineSeparator.toCharArray()) {
557 switch (ch) {
558 case '\r':
559 buffer.append("\\r");
560 break;
561 case '\n':
562 buffer.append("\\n");
563 break;
564 case '\t':
565 buffer.append("\\t");
566 break;
567 default:
568 buffer.append("[" + ((int) ch) + "]");
569 break;
570 }
571 }
572 buffer.append("', ");
573 buffer.append("textMode = ");
574 buffer.append(myFormat.mode + "]");
575 return buffer.toString();
576 }
577
578 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output;
55
56 import java.util.List;
57
58 import javax.xml.stream.XMLStreamException;
59 import javax.xml.stream.XMLStreamWriter;
60
61 import org.jdom.Attribute;
62 import org.jdom.CDATA;
63 import org.jdom.Comment;
64 import org.jdom.Content;
65 import org.jdom.DocType;
66 import org.jdom.Document;
67 import org.jdom.Element;
68 import org.jdom.EntityRef;
69 import org.jdom.ProcessingInstruction;
70 import org.jdom.Text;
71 import org.jdom.output.support.AbstractStAXStreamProcessor;
72 import org.jdom.output.support.StAXStreamProcessor;
73 import org.jdom.output.support.XMLOutputProcessor;
74
75 /**
76 * Outputs a JDOM document as a StAX XMLStreamWriter of bytes.
77 * <p>
78 * The StAXStreamOutputter can manage many styles of document formatting, from
79 * untouched to 'pretty' printed. The default is to output the document content
80 * exactly as created, but this can be changed by setting a new Format object:
81 * <ul>
82 * <li>For pretty-print output, use
83 * <code>{@link Format#getPrettyFormat()}</code>.
84 * <li>For whitespace-normalised output, use
85 * <code>{@link Format#getCompactFormat()}</code>.
86 * <li>For unmodified-format output, use
87 * <code>{@link Format#getRawFormat()}</code>.
88 * </ul>
89 * <p>
90 * <b>All</b> of the <code>output*(...)</code> methods will flush the
91 * destination XMLStreamWriter before returning, and <b>none</b> of them
92 * will <code>close()</code> the destination.
93 * <p>
94 * To omit output of the declaration use
95 * <code>{@link Format#setOmitDeclaration}</code>. To omit printing of the
96 * encoding in the declaration use <code>{@link Format#setOmitEncoding}</code>.
97 * <p>
98 * If changing the {@link Format} settings are insufficient for your output
99 * needs you can customise this StAXStreamOutputter further by setting a different
100 * {@link StAXStreamProcessor} with the
101 * {@link #setStAXStreamProcessor(StAXStreamProcessor)} method or an appropriate
102 * constructor. A fully-enabled Abstract class
103 * {@link AbstractStAXStreamProcessor} is available to be further extended to
104 * your needs if all you want to do is tweak some details.
105 *
106 * @since JDOM2
107 * @author Rolf Lear
108 */
109
110 public final class StAXStreamOutputter implements Cloneable {
111
112 /*
113 * =====================================================================
114 * Static content.
115 * =====================================================================
116 */
117
118 /**
119 * Create a final and static instance of the AbstractStAXStreamProcessor The
120 * final part is important because it improves performance.
121 * <p>
122 * The JDOM user can change the actual XMLOutputProcessor with the
123 * {@link StAXStreamOutputter#setStAXStreamProcessor(StAXStreamProcessor)} method.
124 *
125 * @author rolf
126 */
127 private static final class DefaultStAXStreamProcessor
128 extends AbstractStAXStreamProcessor {
129 // nothing
130 }
131
132 /**
133 * This constant StAXStreamProcessor is used for all non-customised
134 * StAXStreamOutputters
135 */
136 private static final DefaultStAXStreamProcessor DEFAULTPROCESSOR =
137 new DefaultStAXStreamProcessor();
138
139 /*
140 * =====================================================================
141 * Instance content.
142 * =====================================================================
143 */
144
145 // For normal output
146 private Format myFormat = null;
147
148 // The actual StAXStreamProcessor to delegate to.
149 private StAXStreamProcessor myProcessor = null;
150
151 /*
152 * =====================================================================
153 * Constructors
154 * =====================================================================
155 */
156
157 /**
158 * This will create an <code>StAXStreamOutputter</code> with the specified format
159 * characteristics.
160 * <p>
161 * <b>Note:</b> the format object is cloned internally before use. If you
162 * want to modify the Format after constructing the StAXStreamOutputter you can
163 * modify the Format instance {@link #getFormat()} returns.
164 *
165 * @param format
166 * The Format instance to use. This instance will be cloned() and as
167 * a consequence, changes made to the specified format instance
168 * <b>will not</b> be reflected in this StAXStreamOutputter. A null input
169 * format indicates that StAXStreamOutputter should use the default
170 * {@link Format#getRawFormat()}
171 * @param processor
172 * The XMLOutputProcessor to delegate output to. If null the
173 * StAXStreamOutputter will use the default XMLOutputProcessor.
174 */
175 public StAXStreamOutputter(Format format, StAXStreamProcessor processor) {
176 myFormat = format == null ? Format.getRawFormat() : format.clone();
177 myProcessor = processor == null ? DEFAULTPROCESSOR : processor;
178 }
179
180 /**
181 * This will create an <code>StAXStreamOutputter</code> with a default
182 * {@link Format} and {@link XMLOutputProcessor}.
183 */
184 public StAXStreamOutputter() {
185 this(null, null);
186 }
187
188 /**
189 * This will create an <code>StAXStreamOutputter</code> with the specified format
190 * characteristics.
191 * <p>
192 * <b>Note:</b> the format object is cloned internally before use.
193 *
194 * @param format
195 * The Format instance to use. This instance will be cloned() and as
196 * a consequence, changes made to the specified format instance
197 * <b>will not</b> be reflected in this StAXStreamOutputter. A null input
198 * format indicates that StAXStreamOutputter should use the default
199 * {@link Format#getRawFormat()}
200 */
201 public StAXStreamOutputter(Format format) {
202 this(format, null);
203 }
204
205 /**
206 * This will create an <code>StAXStreamOutputter</code> with the specified
207 * XMLOutputProcessor.
208 *
209 * @param processor
210 * The XMLOutputProcessor to delegate output to. If null the
211 * StAXStreamOutputter will use the default XMLOutputProcessor.
212 */
213 public StAXStreamOutputter(StAXStreamProcessor processor) {
214 this(null, processor);
215 }
216
217 /*
218 * =======================================================================
219 * API - Settings...
220 * =======================================================================
221 */
222
223 /**
224 * Sets the new format logic for the StAXStreamOutputter. Note the Format object is
225 * cloned internally before use.
226 *
227 * @see #getFormat()
228 * @param newFormat
229 * the format to use for subsequent output
230 */
231 public void setFormat(Format newFormat) {
232 this.myFormat = newFormat.clone();
233 }
234
235 /**
236 * Returns the current format in use by the StAXStreamOutputter. Note the Format
237 * object returned is <b>not</b> a clone of the one used internally, thus,
238 * an StAXStreamOutputter instance is able to have it's Format changed by changing
239 * the settings on the Format instance returned by this method.
240 *
241 * @return the current Format instance used by this StAXStreamOutputter.
242 */
243 public Format getFormat() {
244 return myFormat;
245 }
246
247 /**
248 * Returns the current XMLOutputProcessor instance in use by the
249 * StAXStreamOutputter.
250 *
251 * @return the current XMLOutputProcessor instance.
252 */
253 public StAXStreamProcessor getStAXStream() {
254 return myProcessor;
255 }
256
257 /**
258 * Sets a new XMLOutputProcessor instance for this StAXStreamOutputter. Note the
259 * processor object is expected to be thread-safe.
260 *
261 * @param processor
262 * the new XMLOutputProcesor to use for output
263 */
264 public void setStAXStreamProcessor(StAXStreamProcessor processor) {
265 this.myProcessor = processor;
266 }
267
268 /*
269 * ========================================================================
270 * API - Output to XMLStreamWriter Methods ... These are the core methods that the
271 * Stream and String output methods call. On the other hand, these methods
272 * defer to the protected/override methods. These methods flush the writer.
273 * ========================================================================
274 */
275
276 /**
277 * This will print the <code>Document</code> to the given Writer.
278 * <p>
279 * Warning: using your own Writer may cause the outputter's preferred
280 * character encoding to be ignored. If you use encodings other than UTF-8,
281 * we recommend using the method that takes an OutputStream instead.
282 * </p>
283 *
284 * @param doc
285 * <code>Document</code> to format.
286 * @param out
287 * <code>XMLStreamWriter</code> to use.
288 * @throws XMLStreamException
289 * - if there's any problem writing.
290 * @throws NullPointerException
291 * if the specified content is null.
292 */
293 public final void output(Document doc, XMLStreamWriter out) throws XMLStreamException {
294 myProcessor.process(out, myFormat, doc);
295 out.flush();
296 }
297
298 /**
299 * Print out the <code>{@link DocType}</code>.
300 *
301 * @param doctype
302 * <code>DocType</code> to output.
303 * @param out
304 * <code>XMLStreamWriter</code> to use.
305 * @throws XMLStreamException
306 * - if there's any problem writing.
307 * @throws NullPointerException
308 * if the specified content is null.
309 */
310 public final void output(DocType doctype, XMLStreamWriter out) throws XMLStreamException {
311 myProcessor.process(out, myFormat, doctype);
312 out.flush();
313 }
314
315 /**
316 * Print out an <code>{@link Element}</code>, including its
317 * <code>{@link Attribute}</code>s, and all contained (child) elements, etc.
318 *
319 * @param element
320 * <code>Element</code> to output.
321 * @param out
322 * <code>XMLStreamWriter</code> to use.
323 * @throws XMLStreamException
324 * - if there's any problem writing.
325 * @throws NullPointerException
326 * if the specified content is null.
327 */
328 public final void output(Element element, XMLStreamWriter out) throws XMLStreamException {
329 // If this is the root element we could pre-initialize the
330 // namespace stack with the namespaces
331 myProcessor.process(out, myFormat, element);
332 out.flush();
333 }
334
335 /**
336 * This will handle printing out an <code>{@link
337 * Element}</code>'s content only, not including its tag, and attributes.
338 * This can be useful for printing the content of an element that contains
339 * HTML, like "&lt;description&gt;JDOM is
340 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
341 *
342 * @param element
343 * <code>Element</code> to output.
344 * @param out
345 * <code>XMLStreamWriter</code> to use.
346 * @throws XMLStreamException
347 * - if there's any problem writing.
348 * @throws NullPointerException
349 * if the specified content is null.
350 */
351 public final void outputElementContent(Element element, XMLStreamWriter out)
352 throws XMLStreamException {
353 myProcessor.process(out, myFormat, element.getContent());
354 out.flush();
355 }
356
357 /**
358 * This will handle printing out a list of nodes. This can be useful for
359 * printing the content of an element that contains HTML, like
360 * "&lt;description&gt;JDOM is &lt;b&gt;fun&gt;!&lt;/description&gt;".
361 *
362 * @param list
363 * <code>List</code> of nodes.
364 * @param out
365 * <code>XMLStreamWriter</code> to use.
366 * @throws XMLStreamException
367 * - if there's any problem writing.
368 * @throws NullPointerException
369 * if the specified content is null.
370 */
371 public final void output(List<? extends Content> list, XMLStreamWriter out)
372 throws XMLStreamException {
373 myProcessor.process(out, myFormat, list);
374 out.flush();
375 }
376
377 /**
378 * Print out a <code>{@link CDATA}</code> node.
379 *
380 * @param cdata
381 * <code>CDATA</code> to output.
382 * @param out
383 * <code>XMLStreamWriter</code> to use.
384 * @throws XMLStreamException
385 * - if there's any problem writing.
386 * @throws NullPointerException
387 * if the specified content is null.
388 */
389 public final void output(CDATA cdata, XMLStreamWriter out) throws XMLStreamException {
390 myProcessor.process(out, myFormat, cdata);
391 out.flush();
392 }
393
394 /**
395 * Print out a <code>{@link Text}</code> node. Perfoms the necessary entity
396 * escaping and whitespace stripping.
397 *
398 * @param text
399 * <code>Text</code> to output.
400 * @param out
401 * <code>XMLStreamWriter</code> to use.
402 * @throws XMLStreamException
403 * - if there's any problem writing.
404 * @throws NullPointerException
405 * if the specified content is null.
406 */
407 public final void output(Text text, XMLStreamWriter out) throws XMLStreamException {
408 myProcessor.process(out, myFormat, text);
409 out.flush();
410 }
411
412 /**
413 * Print out a <code>{@link Comment}</code>.
414 *
415 * @param comment
416 * <code>Comment</code> to output.
417 * @param out
418 * <code>XMLStreamWriter</code> to use.
419 * @throws XMLStreamException
420 * - if there's any problem writing.
421 * @throws NullPointerException
422 * if the specified content is null.
423 */
424 public final void output(Comment comment, XMLStreamWriter out) throws XMLStreamException {
425 myProcessor.process(out, myFormat, comment);
426 out.flush();
427 }
428
429 /**
430 * Print out a <code>{@link ProcessingInstruction}</code>.
431 *
432 * @param pi
433 * <code>ProcessingInstruction</code> to output.
434 * @param out
435 * <code>XMLStreamWriter</code> to use.
436 * @throws XMLStreamException
437 * - if there's any problem writing.
438 * @throws NullPointerException
439 * if the specified content is null.
440 */
441 public final void output(ProcessingInstruction pi, XMLStreamWriter out)
442 throws XMLStreamException {
443 myProcessor.process(out, myFormat, pi);
444 out.flush();
445 }
446
447 /**
448 * Print out an <code>{@link EntityRef}</code>.
449 *
450 * @param entity
451 * <code>EntityRef</code> to output.
452 * @param out
453 * <code>XMLStreamWriter</code> to use.
454 * @throws XMLStreamException
455 * - if there's any problem writing.
456 * @throws NullPointerException
457 * if the specified content is null.
458 */
459 public final void output(EntityRef entity, XMLStreamWriter out) throws XMLStreamException {
460 myProcessor.process(out, myFormat, entity);
461 out.flush();
462 }
463
464 /*
465 * ========================================================================
466 * Basic Support methods.
467 * ========================================================================
468 */
469
470 /**
471 * Returns a cloned copy of this StAXStreamOutputter.
472 */
473 @Override
474 public StAXStreamOutputter clone() {
475 // Implementation notes: Since all state of an StAXStreamOutputter is
476 // embodied in simple private instance variables, Object.clone
477 // can be used. Note that since Object.clone is totally
478 // broken, we must catch an exception that will never be
479 // thrown.
480 try {
481 return (StAXStreamOutputter) super.clone();
482 } catch (java.lang.CloneNotSupportedException e) {
483 // even though this should never ever happen, it's still
484 // possible to fool Java into throwing a
485 // CloneNotSupportedException. If that happens, we
486 // shouldn't swallow it.
487 throw new RuntimeException(e.toString());
488 }
489 }
490
491 /**
492 * Return a string listing of the settings for this StAXStreamOutputter instance.
493 *
494 * @return a string listing the settings for this StAXStreamOutputter instance
495 */
496 @Override
497 public String toString() {
498 StringBuilder buffer = new StringBuilder();
499 buffer.append("StAXStreamOutputter[omitDeclaration = ");
500 buffer.append(myFormat.omitDeclaration);
501 buffer.append(", ");
502 buffer.append("encoding = ");
503 buffer.append(myFormat.encoding);
504 buffer.append(", ");
505 buffer.append("omitEncoding = ");
506 buffer.append(myFormat.omitEncoding);
507 buffer.append(", ");
508 buffer.append("indent = '");
509 buffer.append(myFormat.indent);
510 buffer.append("'");
511 buffer.append(", ");
512 buffer.append("expandEmptyElements = ");
513 buffer.append(myFormat.expandEmptyElements);
514 buffer.append(", ");
515 buffer.append("lineSeparator = '");
516 for (char ch : myFormat.lineSeparator.toCharArray()) {
517 switch (ch) {
518 case '\r':
519 buffer.append("\\r");
520 break;
521 case '\n':
522 buffer.append("\\n");
523 break;
524 case '\t':
525 buffer.append("\\t");
526 break;
527 default:
528 buffer.append("[" + ((int) ch) + "]");
529 break;
530 }
531 }
532 buffer.append("', ");
533 buffer.append("textMode = ");
534 buffer.append(myFormat.mode + "]");
535 return buffer.toString();
536 }
537
538 }
0 /*--
1
2 $Id: XMLOutputter.java,v 1.117 2009/07/23 05:54:23 jhunter Exp $
3
4 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact <request_AT_jdom_DOT_org>.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management <request_AT_jdom_DOT_org>.
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
51 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
52 on the JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 package org.jdom.output;
57
58 import java.io.*;
59 import java.util.*;
60
61 import javax.xml.transform.Result;
62
63 import org.jdom.*;
64
65 /**
66 * Outputs a JDOM document as a stream of bytes. The outputter can manage many
67 * styles of document formatting, from untouched to pretty printed. The default
68 * is to output the document content exactly as created, but this can be changed
69 * by setting a new Format object. For pretty-print output, use
70 * <code>{@link Format#getPrettyFormat()}</code>. For whitespace-normalized
71 * output, use <code>{@link Format#getCompactFormat()}</code>.
72 * <p>
73 * There are <code>{@link #output output(...)}</code> methods to print any of
74 * the standard JDOM classes, including Document and Element, to either a Writer
75 * or an OutputStream. <b>Warning</b>: When outputting to a Writer, make sure
76 * the writer's encoding matches the encoding setting in the Format object. This
77 * ensures the encoding in which the content is written (controlled by the
78 * Writer configuration) matches the encoding placed in the document's XML
79 * declaration (controlled by the XMLOutputter). Because a Writer cannot be
80 * queried for its encoding, the information must be passed to the Format
81 * manually in its constructor or via the
82 * <code>{@link Format#setEncoding}</code> method. The default encoding is
83 * UTF-8.
84 * <p>
85 * The methods <code>{@link #outputString outputString(...)}</code> are for
86 * convenience only; for top performance you should call one of the <code>{@link
87 * #output output(...)}</code> methods and pass in your own Writer or
88 * OutputStream if possible.
89 * <p>
90 * XML declarations are always printed on their own line followed by a line
91 * seperator (this doesn't change the semantics of the document). To omit
92 * printing of the declaration use
93 * <code>{@link Format#setOmitDeclaration}</code>. To omit printing of the
94 * encoding in the declaration use <code>{@link Format#setOmitEncoding}</code>.
95 * Unfortunatly there is currently no way to know the original encoding of the
96 * document.
97 * <p>
98 * Empty elements are by default printed as &lt;empty/&gt;, but this can be
99 * configured with <code>{@link Format#setExpandEmptyElements}</code> to cause
100 * them to be expanded to &lt;empty&gt;&lt;/empty&gt;.
101 *
102 * @version $Revision: 1.117 $, $Date: 2009/07/23 05:54:23 $
103 * @author Brett McLaughlin
104 * @author Jason Hunter
105 * @author Jason Reid
106 * @author Wolfgang Werner
107 * @author Elliotte Rusty Harold
108 * @author David &amp; Will (from Post Tool Design)
109 * @author Dan Schaffer
110 * @author Alex Chaffee
111 * @author Bradley S. Huffman
112 */
113
114 public class XMLOutputter implements Cloneable {
115
116 private static final String CVS_ID =
117 "@(#) $RCSfile: XMLOutputter.java,v $ $Revision: 1.117 $ $Date: 2009/07/23 05:54:23 $ $Name: $";
118
119 // For normal output
120 private Format userFormat = Format.getRawFormat();
121
122 // For xml:space="preserve"
123 protected static final Format preserveFormat = Format.getRawFormat();
124
125 // What's currently in use
126 protected Format currentFormat = userFormat;
127
128 /** Whether output escaping is enabled for the being processed
129 * Element - default is <code>true</code> */
130 private boolean escapeOutput = true;
131
132 // * * * * * * * * * * Constructors * * * * * * * * * *
133 // * * * * * * * * * * Constructors * * * * * * * * * *
134
135 /**
136 * This will create an <code>XMLOutputter</code> with the default
137 * {@link Format} matching {@link Format#getRawFormat}.
138 */
139 public XMLOutputter() {
140 }
141
142 /**
143 * This will create an <code>XMLOutputter</code> with the specified
144 * format characteristics. Note the format object is cloned internally
145 * before use.
146 */
147 public XMLOutputter(Format format) {
148 userFormat = (Format) format.clone();
149 currentFormat = userFormat;
150 }
151
152 /**
153 * This will create an <code>XMLOutputter</code> with all the
154 * options as set in the given <code>XMLOutputter</code>. Note
155 * that <code>XMLOutputter two = (XMLOutputter)one.clone();</code>
156 * would work equally well.
157 *
158 * @param that the XMLOutputter to clone
159 */
160 public XMLOutputter(XMLOutputter that) {
161 this.userFormat = (Format) that.userFormat.clone();
162 currentFormat = userFormat;
163 }
164
165 // * * * * * * * * * * Set parameters methods * * * * * * * * * *
166 // * * * * * * * * * * Set parameters methods * * * * * * * * * *
167
168 /**
169 * Sets the new format logic for the outputter. Note the Format
170 * object is cloned internally before use.
171 *
172 * @param newFormat the format to use for output
173 */
174 public void setFormat(Format newFormat) {
175 this.userFormat = (Format) newFormat.clone();
176 this.currentFormat = userFormat;
177 }
178
179 /**
180 * Returns the current format in use by the outputter. Note the
181 * Format object returned is a clone of the one used internally.
182 */
183 public Format getFormat() {
184 return (Format) userFormat.clone();
185 }
186
187 // * * * * * * * * * * Output to a OutputStream * * * * * * * * * *
188 // * * * * * * * * * * Output to a OutputStream * * * * * * * * * *
189
190 /**
191 * This will print the <code>Document</code> to the given output stream.
192 * The characters are printed using the encoding specified in the
193 * constructor, or a default of UTF-8.
194 *
195 * @param doc <code>Document</code> to format.
196 * @param out <code>OutputStream</code> to use.
197 * @throws IOException - if there's any problem writing.
198 */
199 public void output(Document doc, OutputStream out)
200 throws IOException {
201 Writer writer = makeWriter(out);
202 output(doc, writer); // output() flushes
203 }
204
205 /**
206 * Print out the <code>{@link DocType}</code>.
207 *
208 * @param doctype <code>DocType</code> to output.
209 * @param out <code>OutputStream</code> to use.
210 */
211 public void output(DocType doctype, OutputStream out) throws IOException {
212 Writer writer = makeWriter(out);
213 output(doctype, writer); // output() flushes
214 }
215
216 /**
217 * Print out an <code>{@link Element}</code>, including
218 * its <code>{@link Attribute}</code>s, and all
219 * contained (child) elements, etc.
220 *
221 * @param element <code>Element</code> to output.
222 * @param out <code>Writer</code> to use.
223 */
224 public void output(Element element, OutputStream out) throws IOException {
225 Writer writer = makeWriter(out);
226 output(element, writer); // output() flushes
227 }
228
229 /**
230 * This will handle printing out an <code>{@link
231 * Element}</code>'s content only, not including its tag, and
232 * attributes. This can be useful for printing the content of an
233 * element that contains HTML, like "&lt;description&gt;JDOM is
234 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
235 *
236 * @param element <code>Element</code> to output.
237 * @param out <code>OutputStream</code> to use.
238 */
239 public void outputElementContent(Element element, OutputStream out)
240 throws IOException {
241 Writer writer = makeWriter(out);
242 outputElementContent(element, writer); // output() flushes
243 }
244
245 /**
246 * This will handle printing out a list of nodes.
247 * This can be useful for printing the content of an element that
248 * contains HTML, like "&lt;description&gt;JDOM is
249 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
250 *
251 * @param list <code>List</code> of nodes.
252 * @param out <code>OutputStream</code> to use.
253 */
254 public void output(List list, OutputStream out)
255 throws IOException {
256 Writer writer = makeWriter(out);
257 output(list, writer); // output() flushes
258 }
259
260 /**
261 * Print out a <code>{@link CDATA}</code> node.
262 *
263 * @param cdata <code>CDATA</code> to output.
264 * @param out <code>OutputStream</code> to use.
265 */
266 public void output(CDATA cdata, OutputStream out) throws IOException {
267 Writer writer = makeWriter(out);
268 output(cdata, writer); // output() flushes
269 }
270
271 /**
272 * Print out a <code>{@link Text}</code> node. Perfoms
273 * the necessary entity escaping and whitespace stripping.
274 *
275 * @param text <code>Text</code> to output.
276 * @param out <code>OutputStream</code> to use.
277 */
278 public void output(Text text, OutputStream out) throws IOException {
279 Writer writer = makeWriter(out);
280 output(text, writer); // output() flushes
281 }
282
283 /**
284 * Print out a <code>{@link Comment}</code>.
285 *
286 * @param comment <code>Comment</code> to output.
287 * @param out <code>OutputStream</code> to use.
288 */
289 public void output(Comment comment, OutputStream out) throws IOException {
290 Writer writer = makeWriter(out);
291 output(comment, writer); // output() flushes
292 }
293
294 /**
295 * Print out a <code>{@link ProcessingInstruction}</code>.
296 *
297 * @param pi <code>ProcessingInstruction</code> to output.
298 * @param out <code>OutputStream</code> to use.
299 */
300 public void output(ProcessingInstruction pi, OutputStream out)
301 throws IOException {
302 Writer writer = makeWriter(out);
303 output(pi, writer); // output() flushes
304 }
305
306 /**
307 * Print out a <code>{@link EntityRef}</code>.
308 *
309 * @param entity <code>EntityRef</code> to output.
310 * @param out <code>OutputStream</code> to use.
311 */
312 public void output(EntityRef entity, OutputStream out) throws IOException {
313 Writer writer = makeWriter(out);
314 output(entity, writer); // output() flushes
315 }
316
317 /**
318 * Get an OutputStreamWriter, using prefered encoding
319 * (see {@link Format#setEncoding}).
320 */
321 private Writer makeWriter(OutputStream out)
322 throws java.io.UnsupportedEncodingException {
323 return makeWriter(out, userFormat.encoding);
324 }
325
326 /**
327 * Get an OutputStreamWriter, use specified encoding.
328 */
329 private static Writer makeWriter(OutputStream out, String enc)
330 throws java.io.UnsupportedEncodingException {
331 // "UTF-8" is not recognized before JDK 1.1.6, so we'll translate
332 // into "UTF8" which works with all JDKs.
333 if ("UTF-8".equals(enc)) {
334 enc = "UTF8";
335 }
336
337 Writer writer = new BufferedWriter(
338 (new OutputStreamWriter(
339 new BufferedOutputStream(out), enc)
340 ));
341 return writer;
342 }
343
344 // * * * * * * * * * * Output to a Writer * * * * * * * * * *
345 // * * * * * * * * * * Output to a Writer * * * * * * * * * *
346
347 /**
348 * This will print the <code>Document</code> to the given Writer.
349 *
350 * <p>
351 * Warning: using your own Writer may cause the outputter's
352 * preferred character encoding to be ignored. If you use
353 * encodings other than UTF-8, we recommend using the method that
354 * takes an OutputStream instead.
355 * </p>
356 *
357 * @param doc <code>Document</code> to format.
358 * @param out <code>Writer</code> to use.
359 * @throws IOException - if there's any problem writing.
360 */
361 public void output(Document doc, Writer out) throws IOException {
362
363 printDeclaration(out, doc, userFormat.encoding);
364
365 // Print out root element, as well as any root level
366 // comments and processing instructions,
367 // starting with no indentation
368 List content = doc.getContent();
369 int size = content.size();
370 for (int i = 0; i < size; i++) {
371 Object obj = content.get(i);
372
373 if (obj instanceof Element) {
374 printElement(out, doc.getRootElement(), 0,
375 createNamespaceStack());
376 }
377 else if (obj instanceof Comment) {
378 printComment(out, (Comment) obj);
379 }
380 else if (obj instanceof ProcessingInstruction) {
381 printProcessingInstruction(out, (ProcessingInstruction) obj);
382 }
383 else if (obj instanceof DocType) {
384 printDocType(out, doc.getDocType());
385 // Always print line separator after declaration, helps the
386 // output look better and is semantically inconsequential
387 writeLineSeparator(out);
388 }
389 else {
390 // XXX if we get here then we have a illegal content, for
391 // now we'll just ignore it
392 }
393
394 newline(out);
395 indent(out, 0);
396 }
397
398 // Output final line separator
399 // We output this no matter what the newline flags say
400 writeLineSeparator(out);
401
402 out.flush();
403 }
404
405 private void writeLineSeparator(Writer out) throws IOException {
406 if (currentFormat.lineSeparator != null) {
407 out.write(currentFormat.lineSeparator);
408 }
409 }
410
411 /**
412 * Print out the <code>{@link DocType}</code>.
413 *
414 * @param doctype <code>DocType</code> to output.
415 * @param out <code>Writer</code> to use.
416 */
417 public void output(DocType doctype, Writer out) throws IOException {
418 printDocType(out, doctype);
419 out.flush();
420 }
421
422 /**
423 * Print out an <code>{@link Element}</code>, including
424 * its <code>{@link Attribute}</code>s, and all
425 * contained (child) elements, etc.
426 *
427 * @param element <code>Element</code> to output.
428 * @param out <code>Writer</code> to use.
429 */
430 public void output(Element element, Writer out) throws IOException {
431 // If this is the root element we could pre-initialize the
432 // namespace stack with the namespaces
433 printElement(out, element, 0, createNamespaceStack());
434 out.flush();
435 }
436
437 /**
438 * This will handle printing out an <code>{@link
439 * Element}</code>'s content only, not including its tag, and
440 * attributes. This can be useful for printing the content of an
441 * element that contains HTML, like "&lt;description&gt;JDOM is
442 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
443 *
444 * @param element <code>Element</code> to output.
445 * @param out <code>Writer</code> to use.
446 */
447 public void outputElementContent(Element element, Writer out)
448 throws IOException {
449 List content = element.getContent();
450 printContentRange(out, content, 0, content.size(),
451 0, createNamespaceStack());
452 out.flush();
453 }
454
455 /**
456 * This will handle printing out a list of nodes.
457 * This can be useful for printing the content of an element that
458 * contains HTML, like "&lt;description&gt;JDOM is
459 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
460 *
461 * @param list <code>List</code> of nodes.
462 * @param out <code>Writer</code> to use.
463 */
464 public void output(List list, Writer out)
465 throws IOException {
466 printContentRange(out, list, 0, list.size(),
467 0, createNamespaceStack());
468 out.flush();
469 }
470
471 /**
472 * Print out a <code>{@link CDATA}</code> node.
473 *
474 * @param cdata <code>CDATA</code> to output.
475 * @param out <code>Writer</code> to use.
476 */
477 public void output(CDATA cdata, Writer out) throws IOException {
478 printCDATA(out, cdata);
479 out.flush();
480 }
481
482 /**
483 * Print out a <code>{@link Text}</code> node. Perfoms
484 * the necessary entity escaping and whitespace stripping.
485 *
486 * @param text <code>Text</code> to output.
487 * @param out <code>Writer</code> to use.
488 */
489 public void output(Text text, Writer out) throws IOException {
490 printText(out, text);
491 out.flush();
492 }
493
494 /**
495 * Print out a <code>{@link Comment}</code>.
496 *
497 * @param comment <code>Comment</code> to output.
498 * @param out <code>Writer</code> to use.
499 */
500 public void output(Comment comment, Writer out) throws IOException {
501 printComment(out, comment);
502 out.flush();
503 }
504
505 /**
506 * Print out a <code>{@link ProcessingInstruction}</code>.
507 *
508 * @param pi <code>ProcessingInstruction</code> to output.
509 * @param out <code>Writer</code> to use.
510 */
511 public void output(ProcessingInstruction pi, Writer out)
512 throws IOException {
513 boolean currentEscapingPolicy = currentFormat.ignoreTrAXEscapingPIs;
514
515 // Output PI verbatim, disregarding TrAX escaping PIs.
516 currentFormat.setIgnoreTrAXEscapingPIs(true);
517 printProcessingInstruction(out, pi);
518 currentFormat.setIgnoreTrAXEscapingPIs(currentEscapingPolicy);
519
520 out.flush();
521 }
522
523 /**
524 * Print out a <code>{@link EntityRef}</code>.
525 *
526 * @param entity <code>EntityRef</code> to output.
527 * @param out <code>Writer</code> to use.
528 */
529 public void output(EntityRef entity, Writer out) throws IOException {
530 printEntityRef(out, entity);
531 out.flush();
532 }
533
534 // * * * * * * * * * * Output to a String * * * * * * * * * *
535 // * * * * * * * * * * Output to a String * * * * * * * * * *
536
537 /**
538 * Return a string representing a document. Uses an internal
539 * StringWriter. Warning: a String is Unicode, which may not match
540 * the outputter's specified encoding.
541 *
542 * @param doc <code>Document</code> to format.
543 */
544 public String outputString(Document doc) {
545 StringWriter out = new StringWriter();
546 try {
547 output(doc, out); // output() flushes
548 } catch (IOException e) { }
549 return out.toString();
550 }
551
552 /**
553 * Return a string representing a DocType. Warning: a String is
554 * Unicode, which may not match the outputter's specified
555 * encoding.
556 *
557 * @param doctype <code>DocType</code> to format.
558 */
559 public String outputString(DocType doctype) {
560 StringWriter out = new StringWriter();
561 try {
562 output(doctype, out); // output() flushes
563 } catch (IOException e) { }
564 return out.toString();
565 }
566
567 /**
568 * Return a string representing an element. Warning: a String is
569 * Unicode, which may not match the outputter's specified
570 * encoding.
571 *
572 * @param element <code>Element</code> to format.
573 */
574 public String outputString(Element element) {
575 StringWriter out = new StringWriter();
576 try {
577 output(element, out); // output() flushes
578 } catch (IOException e) { }
579 return out.toString();
580 }
581
582 /**
583 * Return a string representing a list of nodes. The list is
584 * assumed to contain legal JDOM nodes.
585 *
586 * @param list <code>List</code> to format.
587 */
588 public String outputString(List list) {
589 StringWriter out = new StringWriter();
590 try {
591 output(list, out); // output() flushes
592 } catch (IOException e) { }
593 return out.toString();
594 }
595
596 /**
597 * Return a string representing a CDATA node. Warning: a String is
598 * Unicode, which may not match the outputter's specified
599 * encoding.
600 *
601 * @param cdata <code>CDATA</code> to format.
602 */
603 public String outputString(CDATA cdata) {
604 StringWriter out = new StringWriter();
605 try {
606 output(cdata, out); // output() flushes
607 } catch (IOException e) { }
608 return out.toString();
609 }
610
611 /**
612 * Return a string representing a Text node. Warning: a String is
613 * Unicode, which may not match the outputter's specified
614 * encoding.
615 *
616 * @param text <code>Text</code> to format.
617 */
618 public String outputString(Text text) {
619 StringWriter out = new StringWriter();
620 try {
621 output(text, out); // output() flushes
622 } catch (IOException e) { }
623 return out.toString();
624 }
625
626
627 /**
628 * Return a string representing a comment. Warning: a String is
629 * Unicode, which may not match the outputter's specified
630 * encoding.
631 *
632 * @param comment <code>Comment</code> to format.
633 */
634 public String outputString(Comment comment) {
635 StringWriter out = new StringWriter();
636 try {
637 output(comment, out); // output() flushes
638 } catch (IOException e) { }
639 return out.toString();
640 }
641
642 /**
643 * Return a string representing a PI. Warning: a String is
644 * Unicode, which may not match the outputter's specified
645 * encoding.
646 *
647 * @param pi <code>ProcessingInstruction</code> to format.
648 */
649 public String outputString(ProcessingInstruction pi) {
650 StringWriter out = new StringWriter();
651 try {
652 output(pi, out); // output() flushes
653 } catch (IOException e) { }
654 return out.toString();
655 }
656
657 /**
658 * Return a string representing an entity. Warning: a String is
659 * Unicode, which may not match the outputter's specified
660 * encoding.
661 *
662 * @param entity <code>EntityRef</code> to format.
663 */
664 public String outputString(EntityRef entity) {
665 StringWriter out = new StringWriter();
666 try {
667 output(entity, out); // output() flushes
668 } catch (IOException e) { }
669 return out.toString();
670 }
671
672 // * * * * * * * * * * Internal printing methods * * * * * * * * * *
673 // * * * * * * * * * * Internal printing methods * * * * * * * * * *
674
675 /**
676 * This will handle printing of the declaration.
677 * Assumes XML version 1.0 since we don't directly know.
678 *
679 * @param doc <code>Document</code> whose declaration to write.
680 * @param out <code>Writer</code> to use.
681 * @param encoding The encoding to add to the declaration
682 */
683 protected void printDeclaration(Writer out, Document doc,
684 String encoding) throws IOException {
685
686 // Only print the declaration if it's not being omitted
687 if (!userFormat.omitDeclaration) {
688 // Assume 1.0 version
689 out.write("<?xml version=\"1.0\"");
690 if (!userFormat.omitEncoding) {
691 out.write(" encoding=\"" + encoding + "\"");
692 }
693 out.write("?>");
694
695 // Print new line after decl always, even if no other new lines
696 // Helps the output look better and is semantically
697 // inconsequential
698 writeLineSeparator(out);
699 }
700 }
701
702 /**
703 * This handle printing the DOCTYPE declaration if one exists.
704 *
705 * @param docType <code>Document</code> whose declaration to write.
706 * @param out <code>Writer</code> to use.
707 */
708 protected void printDocType(Writer out, DocType docType)
709 throws IOException {
710
711 String publicID = docType.getPublicID();
712 String systemID = docType.getSystemID();
713 String internalSubset = docType.getInternalSubset();
714 boolean hasPublic = false;
715
716 out.write("<!DOCTYPE ");
717 out.write(docType.getElementName());
718 if (publicID != null) {
719 out.write(" PUBLIC \"");
720 out.write(publicID);
721 out.write("\"");
722 hasPublic = true;
723 }
724 if (systemID != null) {
725 if (!hasPublic) {
726 out.write(" SYSTEM");
727 }
728 out.write(" \"");
729 out.write(systemID);
730 out.write("\"");
731 }
732 if ((internalSubset != null) && (!internalSubset.equals(""))) {
733 out.write(" [");
734 writeLineSeparator(out);
735 out.write(docType.getInternalSubset());
736 out.write("]");
737 }
738 out.write(">");
739 }
740
741 /**
742 * This will handle printing of comments.
743 *
744 * @param comment <code>Comment</code> to write.
745 * @param out <code>Writer</code> to use.
746 */
747 protected void printComment(Writer out, Comment comment)
748 throws IOException {
749 out.write("<!--");
750 out.write(comment.getText());
751 out.write("-->");
752 }
753
754 /**
755 * This will handle printing of processing instructions.
756 *
757 * @param pi <code>ProcessingInstruction</code> to write.
758 * @param out <code>Writer</code> to use.
759 */
760 protected void printProcessingInstruction(Writer out, ProcessingInstruction pi
761 ) throws IOException {
762 String target = pi.getTarget();
763 boolean piProcessed = false;
764
765 if (currentFormat.ignoreTrAXEscapingPIs == false) {
766 if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING)) {
767 escapeOutput = false;
768 piProcessed = true;
769 }
770 else if (target.equals(Result.PI_ENABLE_OUTPUT_ESCAPING)) {
771 escapeOutput = true;
772 piProcessed = true;
773 }
774 }
775 if (piProcessed == false) {
776 String rawData = pi.getData();
777
778 // Write <?target data?> or if no data then just <?target?>
779 if (!"".equals(rawData)) {
780 out.write("<?");
781 out.write(target);
782 out.write(" ");
783 out.write(rawData);
784 out.write("?>");
785 }
786 else {
787 out.write("<?");
788 out.write(target);
789 out.write("?>");
790 }
791 }
792 }
793
794 /**
795 * This will handle printing a <code>{@link EntityRef}</code>.
796 * Only the entity reference such as <code>&amp;entity;</code>
797 * will be printed. However, subclasses are free to override
798 * this method to print the contents of the entity instead.
799 *
800 * @param entity <code>EntityRef</code> to output.
801 * @param out <code>Writer</code> to use. */
802 protected void printEntityRef(Writer out, EntityRef entity)
803 throws IOException {
804 out.write("&");
805 out.write(entity.getName());
806 out.write(";");
807 }
808
809 /**
810 * This will handle printing of <code>{@link CDATA}</code> text.
811 *
812 * @param cdata <code>CDATA</code> to output.
813 * @param out <code>Writer</code> to use.
814 */
815 protected void printCDATA(Writer out, CDATA cdata) throws IOException {
816 String str = (currentFormat.mode == Format.TextMode.NORMALIZE)
817 ? cdata.getTextNormalize()
818 : ((currentFormat.mode == Format.TextMode.TRIM) ?
819 cdata.getText().trim() : cdata.getText());
820 out.write("<![CDATA[");
821 out.write(str);
822 out.write("]]>");
823 }
824
825 /**
826 * This will handle printing of <code>{@link Text}</code> strings.
827 *
828 * @param text <code>Text</code> to write.
829 * @param out <code>Writer</code> to use.
830 */
831 protected void printText(Writer out, Text text) throws IOException {
832 String str = (currentFormat.mode == Format.TextMode.NORMALIZE)
833 ? text.getTextNormalize()
834 : ((currentFormat.mode == Format.TextMode.TRIM) ?
835 text.getText().trim() : text.getText());
836 out.write(escapeElementEntities(str));
837 }
838
839 /**
840 * This will handle printing a string. Escapes the element entities,
841 * trims interior whitespace, etc. if necessary.
842 */
843 private void printString(Writer out, String str) throws IOException {
844 if (currentFormat.mode == Format.TextMode.NORMALIZE) {
845 str = Text.normalizeString(str);
846 }
847 else if (currentFormat.mode == Format.TextMode.TRIM) {
848 str = str.trim();
849 }
850 out.write(escapeElementEntities(str));
851 }
852
853 /**
854 * This will handle printing of a <code>{@link Element}</code>,
855 * its <code>{@link Attribute}</code>s, and all contained (child)
856 * elements, etc.
857 *
858 * @param element <code>Element</code> to output.
859 * @param out <code>Writer</code> to use.
860 * @param level <code>int</code> level of indention.
861 * @param namespaces <code>List</code> stack of Namespaces in scope.
862 */
863 protected void printElement(Writer out, Element element,
864 int level, NamespaceStack namespaces)
865 throws IOException {
866
867 List attributes = element.getAttributes();
868 List content = element.getContent();
869
870 // Check for xml:space and adjust format settings
871 String space = null;
872 if (attributes != null) {
873 space = element.getAttributeValue("space",
874 Namespace.XML_NAMESPACE);
875 }
876
877 Format previousFormat = currentFormat;
878
879 if ("default".equals(space)) {
880 currentFormat = userFormat;
881 }
882 else if ("preserve".equals(space)) {
883 currentFormat = preserveFormat;
884 }
885
886 // Print the beginning of the tag plus attributes and any
887 // necessary namespace declarations
888 out.write("<");
889 printQualifiedName(out, element);
890
891 // Mark our namespace starting point
892 int previouslyDeclaredNamespaces = namespaces.size();
893
894 // Print the element's namespace, if appropriate
895 printElementNamespace(out, element, namespaces);
896
897 // Print out additional namespace declarations
898 printAdditionalNamespaces(out, element, namespaces);
899
900 // Print out attributes
901 if (attributes != null)
902 printAttributes(out, attributes, element, namespaces);
903
904 // Depending on the settings (newlines, textNormalize, etc), we may
905 // or may not want to print all of the content, so determine the
906 // index of the start of the content we're interested
907 // in based on the current settings.
908
909 int start = skipLeadingWhite(content, 0);
910 int size = content.size();
911 if (start >= size) {
912 // Case content is empty or all insignificant whitespace
913 if (currentFormat.expandEmptyElements) {
914 out.write("></");
915 printQualifiedName(out, element);
916 out.write(">");
917 }
918 else {
919 out.write(" />");
920 }
921 }
922 else {
923 out.write(">");
924
925 // For a special case where the content is only CDATA
926 // or Text we don't want to indent after the start or
927 // before the end tag.
928
929 if (nextNonText(content, start) < size) {
930 // Case Mixed Content - normal indentation
931 newline(out);
932 printContentRange(out, content, start, size,
933 level + 1, namespaces);
934 newline(out);
935 indent(out, level);
936 }
937 else {
938 // Case all CDATA or Text - no indentation
939 printTextRange(out, content, start, size);
940 }
941 out.write("</");
942 printQualifiedName(out, element);
943 out.write(">");
944 }
945
946 // remove declared namespaces from stack
947 while (namespaces.size() > previouslyDeclaredNamespaces) {
948 namespaces.pop();
949 }
950
951 // Restore our format settings
952 currentFormat = previousFormat;
953 }
954
955 /**
956 * This will handle printing of content within a given range.
957 * The range to print is specified in typical Java fashion; the
958 * starting index is inclusive, while the ending index is
959 * exclusive.
960 *
961 * @param content <code>List</code> of content to output
962 * @param start index of first content node (inclusive.
963 * @param end index of last content node (exclusive).
964 * @param out <code>Writer</code> to use.
965 * @param level <code>int</code> level of indentation.
966 * @param namespaces <code>List</code> stack of Namespaces in scope.
967 */
968 private void printContentRange(Writer out, List content,
969 int start, int end, int level,
970 NamespaceStack namespaces)
971 throws IOException {
972 boolean firstNode; // Flag for 1st node in content
973 Object next; // Node we're about to print
974 int first, index; // Indexes into the list of content
975
976 index = start;
977 while (index < end) {
978 firstNode = (index == start) ? true : false;
979 next = content.get(index);
980
981 //
982 // Handle consecutive CDATA, Text, and EntityRef nodes all at once
983 //
984 if ((next instanceof Text) || (next instanceof EntityRef)) {
985 first = skipLeadingWhite(content, index);
986 // Set index to next node for loop
987 index = nextNonText(content, first);
988
989 // If it's not all whitespace - print it!
990 if (first < index) {
991 if (!firstNode)
992 newline(out);
993 indent(out, level);
994 printTextRange(out, content, first, index);
995 }
996 continue;
997 }
998
999 //
1000 // Handle other nodes
1001 //
1002 if (!firstNode) {
1003 newline(out);
1004 }
1005
1006 indent(out, level);
1007
1008 if (next instanceof Comment) {
1009 printComment(out, (Comment)next);
1010 }
1011 else if (next instanceof Element) {
1012 printElement(out, (Element)next, level, namespaces);
1013 }
1014 else if (next instanceof ProcessingInstruction) {
1015 printProcessingInstruction(out, (ProcessingInstruction)next);
1016 }
1017 else {
1018 // XXX if we get here then we have a illegal content, for
1019 // now we'll just ignore it (probably should throw
1020 // a exception)
1021 }
1022
1023 index++;
1024 } /* while */
1025 }
1026
1027 /**
1028 * This will handle printing of a sequence of <code>{@link CDATA}</code>
1029 * or <code>{@link Text}</code> nodes. It is an error to have any other
1030 * pass this method any other type of node.
1031 *
1032 * @param content <code>List</code> of content to output
1033 * @param start index of first content node (inclusive).
1034 * @param end index of last content node (exclusive).
1035 * @param out <code>Writer</code> to use.
1036 */
1037 private void printTextRange(Writer out, List content, int start, int end
1038 ) throws IOException {
1039 String previous; // Previous text printed
1040 Object node; // Next node to print
1041 String next; // Next text to print
1042
1043 previous = null;
1044
1045 // Remove leading whitespace-only nodes
1046 start = skipLeadingWhite(content, start);
1047
1048 int size = content.size();
1049 if (start < size) {
1050 // And remove trialing whitespace-only nodes
1051 end = skipTrailingWhite(content, end);
1052
1053 for (int i = start; i < end; i++) {
1054 node = content.get(i);
1055
1056 // Get the unmangled version of the text
1057 // we are about to print
1058 if (node instanceof Text) {
1059 next = ((Text) node).getText();
1060 }
1061 else if (node instanceof EntityRef) {
1062 next = "&" + ((EntityRef) node).getValue() + ";";
1063 }
1064 else {
1065 throw new IllegalStateException("Should see only " +
1066 "CDATA, Text, or EntityRef");
1067 }
1068
1069 // This may save a little time
1070 if (next == null || "".equals(next)) {
1071 continue;
1072 }
1073
1074 // Determine if we need to pad the output (padding is
1075 // only need in trim or normalizing mode)
1076 if (previous != null) { // Not 1st node
1077 if (currentFormat.mode == Format.TextMode.NORMALIZE ||
1078 currentFormat.mode == Format.TextMode.TRIM) {
1079 if ((endsWithWhite(previous)) ||
1080 (startsWithWhite(next))) {
1081 out.write(" ");
1082 }
1083 }
1084 }
1085
1086 // Print the node
1087 if (node instanceof CDATA) {
1088 printCDATA(out, (CDATA) node);
1089 }
1090 else if (node instanceof EntityRef) {
1091 printEntityRef(out, (EntityRef) node);
1092 }
1093 else {
1094 printString(out, next);
1095 }
1096
1097 previous = next;
1098 }
1099 }
1100 }
1101
1102 /**
1103 * This will handle printing of any needed <code>{@link Namespace}</code>
1104 * declarations.
1105 *
1106 * @param ns <code>Namespace</code> to print definition of
1107 * @param out <code>Writer</code> to use.
1108 */
1109 private void printNamespace(Writer out, Namespace ns,
1110 NamespaceStack namespaces)
1111 throws IOException {
1112 String prefix = ns.getPrefix();
1113 String uri = ns.getURI();
1114
1115 // Already printed namespace decl?
1116 if (uri.equals(namespaces.getURI(prefix))) {
1117 return;
1118 }
1119
1120 out.write(" xmlns");
1121 if (!prefix.equals("")) {
1122 out.write(":");
1123 out.write(prefix);
1124 }
1125 out.write("=\"");
1126 out.write(escapeAttributeEntities(uri));
1127 out.write("\"");
1128 namespaces.push(ns);
1129 }
1130
1131 /**
1132 * This will handle printing of a <code>{@link Attribute}</code> list.
1133 *
1134 * @param attributes <code>List</code> of Attribute objcts
1135 * @param out <code>Writer</code> to use
1136 */
1137 protected void printAttributes(Writer out, List attributes, Element parent,
1138 NamespaceStack namespaces)
1139 throws IOException {
1140
1141 // I do not yet handle the case where the same prefix maps to
1142 // two different URIs. For attributes on the same element
1143 // this is illegal; but as yet we don't throw an exception
1144 // if someone tries to do this
1145 // Set prefixes = new HashSet();
1146 for (int i = 0; i < attributes.size(); i++) {
1147 Attribute attribute = (Attribute) attributes.get(i);
1148 Namespace ns = attribute.getNamespace();
1149 if ((ns != Namespace.NO_NAMESPACE) &&
1150 (ns != Namespace.XML_NAMESPACE)) {
1151 printNamespace(out, ns, namespaces);
1152 }
1153
1154 out.write(" ");
1155 printQualifiedName(out, attribute);
1156 out.write("=");
1157
1158 out.write("\"");
1159 out.write(escapeAttributeEntities(attribute.getValue()));
1160 out.write("\"");
1161 }
1162 }
1163
1164 private void printElementNamespace(Writer out, Element element,
1165 NamespaceStack namespaces)
1166 throws IOException {
1167 // Add namespace decl only if it's not the XML namespace and it's
1168 // not the NO_NAMESPACE with the prefix "" not yet mapped
1169 // (we do output xmlns="" if the "" prefix was already used and we
1170 // need to reclaim it for the NO_NAMESPACE)
1171 Namespace ns = element.getNamespace();
1172 if (ns == Namespace.XML_NAMESPACE) {
1173 return;
1174 }
1175 if ( !((ns == Namespace.NO_NAMESPACE) &&
1176 (namespaces.getURI("") == null))) {
1177 printNamespace(out, ns, namespaces);
1178 }
1179 }
1180
1181 private void printAdditionalNamespaces(Writer out, Element element,
1182 NamespaceStack namespaces)
1183 throws IOException {
1184 List list = element.getAdditionalNamespaces();
1185 if (list != null) {
1186 for (int i = 0; i < list.size(); i++) {
1187 Namespace additional = (Namespace)list.get(i);
1188 printNamespace(out, additional, namespaces);
1189 }
1190 }
1191 }
1192
1193 // * * * * * * * * * * Support methods * * * * * * * * * *
1194 // * * * * * * * * * * Support methods * * * * * * * * * *
1195
1196 /**
1197 * This will print a newline only if indent is not null.
1198 *
1199 * @param out <code>Writer</code> to use
1200 */
1201 private void newline(Writer out) throws IOException {
1202 if (currentFormat.indent != null) {
1203 writeLineSeparator(out);
1204 }
1205 }
1206
1207 /**
1208 * This will print indents only if indent is not null or the empty string.
1209 *
1210 * @param out <code>Writer</code> to use
1211 * @param level current indent level
1212 */
1213 private void indent(Writer out, int level) throws IOException {
1214 if (currentFormat.indent == null ||
1215 currentFormat.indent.equals("")) {
1216 return;
1217 }
1218
1219 for (int i = 0; i < level; i++) {
1220 out.write(currentFormat.indent);
1221 }
1222 }
1223
1224 // Returns the index of the first non-all-whitespace CDATA or Text,
1225 // index = content.size() is returned if content contains
1226 // all whitespace.
1227 // @param start index to begin search (inclusive)
1228 private int skipLeadingWhite(List content, int start) {
1229 if (start < 0) {
1230 start = 0;
1231 }
1232
1233 int index = start;
1234 int size = content.size();
1235 if (currentFormat.mode == Format.TextMode.TRIM_FULL_WHITE
1236 || currentFormat.mode == Format.TextMode.NORMALIZE
1237 || currentFormat.mode == Format.TextMode.TRIM) {
1238 while (index < size) {
1239 if (!isAllWhitespace(content.get(index))) {
1240 return index;
1241 }
1242 index++;
1243 }
1244 }
1245 return index;
1246 }
1247
1248 // Return the index + 1 of the last non-all-whitespace CDATA or
1249 // Text node, index < 0 is returned
1250 // if content contains all whitespace.
1251 // @param start index to begin search (exclusive)
1252 private int skipTrailingWhite(List content, int start) {
1253 int size = content.size();
1254 if (start > size) {
1255 start = size;
1256 }
1257
1258 int index = start;
1259 if (currentFormat.mode == Format.TextMode.TRIM_FULL_WHITE
1260 || currentFormat.mode == Format.TextMode.NORMALIZE
1261 || currentFormat.mode == Format.TextMode.TRIM) {
1262 while (index >= 0) {
1263 if (!isAllWhitespace(content.get(index - 1)))
1264 break;
1265 --index;
1266 }
1267 }
1268 return index;
1269 }
1270
1271 // Return the next non-CDATA, non-Text, or non-EntityRef node,
1272 // index = content.size() is returned if there is no more non-CDATA,
1273 // non-Text, or non-EntiryRef nodes
1274 // @param start index to begin search (inclusive)
1275 private static int nextNonText(List content, int start) {
1276 if (start < 0) {
1277 start = 0;
1278 }
1279
1280 int index = start;
1281 int size = content.size();
1282 while (index < size) {
1283 Object node = content.get(index);
1284 if (!((node instanceof Text) || (node instanceof EntityRef))) {
1285 return index;
1286 }
1287 index++;
1288 }
1289 return size;
1290 }
1291
1292 // Determine if a Object is all whitespace
1293 private boolean isAllWhitespace(Object obj) {
1294 String str = null;
1295
1296 if (obj instanceof String) {
1297 str = (String) obj;
1298 }
1299 else if (obj instanceof Text) {
1300 str = ((Text) obj).getText();
1301 }
1302 else if (obj instanceof EntityRef) {
1303 return false;
1304 }
1305 else {
1306 return false;
1307 }
1308
1309 for (int i = 0; i < str.length(); i++) {
1310 if (!Verifier.isXMLWhitespace(str.charAt(i)))
1311 return false;
1312 }
1313 return true;
1314 }
1315
1316 // Determine if a string starts with a XML whitespace.
1317 private boolean startsWithWhite(String str) {
1318 if ((str != null) &&
1319 (str.length() > 0) &&
1320 Verifier.isXMLWhitespace(str.charAt(0))) {
1321 return true;
1322 }
1323 return false;
1324 }
1325
1326 // Determine if a string ends with a XML whitespace.
1327 private boolean endsWithWhite(String str) {
1328 if ((str != null) &&
1329 (str.length() > 0) &&
1330 Verifier.isXMLWhitespace(str.charAt(str.length() - 1))) {
1331 return true;
1332 }
1333 return false;
1334 }
1335
1336 /**
1337 * This will take the pre-defined entities in XML 1.0 and
1338 * convert their character representation to the appropriate
1339 * entity reference, suitable for XML attributes. It does not convert
1340 * the single quote (') because it's not necessary as the outputter
1341 * writes attributes surrounded by double-quotes.
1342 *
1343 * @param str <code>String</code> input to escape.
1344 * @return <code>String</code> with escaped content.
1345 * @throws IllegalArgumentException if an entity can not be escaped
1346 */
1347 public String escapeAttributeEntities(String str) {
1348 StringBuffer buffer;
1349 int ch, pos;
1350 String entity;
1351 EscapeStrategy strategy = currentFormat.escapeStrategy;
1352
1353 buffer = null;
1354 for (int i = 0; i < str.length(); i++) {
1355 ch = str.charAt(i);
1356 pos = i;
1357 switch(ch) {
1358 case '<' :
1359 entity = "&lt;";
1360 break;
1361 case '>' :
1362 entity = "&gt;";
1363 break;
1364 /*
1365 case '\'' :
1366 entity = "&apos;";
1367 break;
1368 */
1369 case '\"' :
1370 entity = "&quot;";
1371 break;
1372 case '&' :
1373 entity = "&amp;";
1374 break;
1375 case '\r' :
1376 entity = "&#xD;";
1377 break;
1378 case '\t' :
1379 entity = "&#x9;";
1380 break;
1381 case '\n' :
1382 entity = "&#xA;";
1383 break;
1384 default :
1385
1386 if (strategy.shouldEscape((char) ch)) {
1387 // Make sure what we are escaping is not the
1388 // Beginning of a multi-byte character.
1389 if (Verifier.isHighSurrogate((char) ch)) {
1390 // This is a the high of a surrogate pair
1391 i++;
1392 if (i < str.length()) {
1393 char low = str.charAt(i);
1394 if(!Verifier.isLowSurrogate(low)) {
1395 throw new IllegalDataException("Could not decode surrogate pair 0x" +
1396 Integer.toHexString(ch) + " / 0x" + Integer.toHexString(low));
1397 }
1398 ch = Verifier.decodeSurrogatePair((char) ch, low);
1399 } else {
1400 throw new IllegalDataException("Surrogate pair 0x" +
1401 Integer.toHexString(ch) + " truncated");
1402 }
1403 }
1404 entity = "&#x" + Integer.toHexString(ch) + ";";
1405 }
1406 else {
1407 entity = null;
1408 }
1409 break;
1410 }
1411 if (buffer == null) {
1412 if (entity != null) {
1413 // An entity occurred, so we'll have to use StringBuffer
1414 // (allocate room for it plus a few more entities).
1415 buffer = new StringBuffer(str.length() + 20);
1416 // Copy previous skipped characters and fall through
1417 // to pickup current character
1418 buffer.append(str.substring(0, pos));
1419 buffer.append(entity);
1420 }
1421 }
1422 else {
1423 if (entity == null) {
1424 buffer.append((char) ch);
1425 }
1426 else {
1427 buffer.append(entity);
1428 }
1429 }
1430 }
1431
1432 // If there were any entities, return the escaped characters
1433 // that we put in the StringBuffer. Otherwise, just return
1434 // the unmodified input string.
1435 return (buffer == null) ? str : buffer.toString();
1436 }
1437
1438
1439 /**
1440 * This will take the three pre-defined entities in XML 1.0
1441 * (used specifically in XML elements) and convert their character
1442 * representation to the appropriate entity reference, suitable for
1443 * XML element content.
1444 *
1445 * @param str <code>String</code> input to escape.
1446 * @return <code>String</code> with escaped content.
1447 * @throws IllegalArgumentException if an entity can not be escaped
1448 */
1449 public String escapeElementEntities(String str) {
1450 if (escapeOutput == false) return str;
1451
1452 StringBuffer buffer;
1453 int ch, pos;
1454 String entity;
1455 EscapeStrategy strategy = currentFormat.escapeStrategy;
1456
1457 buffer = null;
1458 for (int i = 0; i < str.length(); i++) {
1459 ch = str.charAt(i);
1460 pos = i;
1461 switch(ch) {
1462 case '<' :
1463 entity = "&lt;";
1464 break;
1465 case '>' :
1466 entity = "&gt;";
1467 break;
1468 case '&' :
1469 entity = "&amp;";
1470 break;
1471 case '\r' :
1472 entity = "&#xD;";
1473 break;
1474 case '\n' :
1475 entity = currentFormat.lineSeparator;
1476 break;
1477 default :
1478
1479 if (strategy.shouldEscape((char) ch)) {
1480
1481 //make sure what we are escaping is not the
1482 //beginning of a multi-byte character.
1483 if(Verifier.isHighSurrogate((char) ch)) {
1484 //this is a the high of a surrogate pair
1485 i++;
1486 if (i < str.length()) {
1487 char low = str.charAt(i);
1488 if(!Verifier.isLowSurrogate(low)) {
1489 throw new IllegalDataException("Could not decode surrogate pair 0x" +
1490 Integer.toHexString(ch) + " / 0x" + Integer.toHexString(low));
1491 }
1492 ch = Verifier.decodeSurrogatePair((char) ch, low);
1493 } else {
1494 throw new IllegalDataException("Surrogate pair 0x" +
1495 Integer.toHexString(ch) + " truncated");
1496 }
1497 }
1498 entity = "&#x" + Integer.toHexString(ch) + ";";
1499 }
1500 else {
1501 entity = null;
1502 }
1503 break;
1504 }
1505 if (buffer == null) {
1506 if (entity != null) {
1507 // An entity occurred, so we'll have to use StringBuffer
1508 // (allocate room for it plus a few more entities).
1509 buffer = new StringBuffer(str.length() + 20);
1510 // Copy previous skipped characters and fall through
1511 // to pickup current character
1512 buffer.append(str.substring(0, pos));
1513 buffer.append(entity);
1514 }
1515 }
1516 else {
1517 if (entity == null) {
1518 buffer.append((char) ch);
1519 }
1520 else {
1521 buffer.append(entity);
1522 }
1523 }
1524 }
1525
1526 // If there were any entities, return the escaped characters
1527 // that we put in the StringBuffer. Otherwise, just return
1528 // the unmodified input string.
1529 return (buffer == null) ? str : buffer.toString();
1530 }
1531
1532 /**
1533 * Returns a copy of this XMLOutputter.
1534 */
1535 public Object clone() {
1536 // Implementation notes: Since all state of an XMLOutputter is
1537 // embodied in simple private instance variables, Object.clone
1538 // can be used. Note that since Object.clone is totally
1539 // broken, we must catch an exception that will never be
1540 // thrown.
1541 try {
1542 return super.clone();
1543 }
1544 catch (java.lang.CloneNotSupportedException e) {
1545 // even though this should never ever happen, it's still
1546 // possible to fool Java into throwing a
1547 // CloneNotSupportedException. If that happens, we
1548 // shouldn't swallow it.
1549 throw new RuntimeException(e.toString());
1550 }
1551 }
1552
1553 /**
1554 * Return a string listing of the settings for this
1555 * XMLOutputter instance.
1556 *
1557 * @return a string listing the settings for this XMLOutputter instance
1558 */
1559 public String toString() {
1560 StringBuffer buffer = new StringBuffer();
1561 if (userFormat.lineSeparator != null) {
1562 for (int i = 0; i < userFormat.lineSeparator.length(); i++) {
1563 char ch = userFormat.lineSeparator.charAt(i);
1564 switch (ch) {
1565 case '\r': buffer.append("\\r");
1566 break;
1567 case '\n': buffer.append("\\n");
1568 break;
1569 case '\t': buffer.append("\\t");
1570 break;
1571 default: buffer.append("[" + ((int)ch) + "]");
1572 break;
1573 }
1574 }
1575 }
1576 else {
1577 buffer.append("null");
1578 }
1579
1580 return (
1581 "XMLOutputter[omitDeclaration = " + userFormat.omitDeclaration + ", " +
1582 "encoding = " + userFormat.encoding + ", " +
1583 "omitEncoding = " + userFormat.omitEncoding + ", " +
1584 "indent = '" + userFormat.indent + "'" + ", " +
1585 "expandEmptyElements = " + userFormat.expandEmptyElements + ", " +
1586 "lineSeparator = '" + buffer.toString() + "', " +
1587 "textMode = " + userFormat.mode + "]"
1588 );
1589 }
1590
1591 /**
1592 * Factory for making new NamespaceStack objects. The NamespaceStack
1593 * created is actually an inner class extending the package protected
1594 * NamespaceStack, as a way to make NamespaceStack "friendly" toward
1595 * subclassers.
1596 */
1597 private NamespaceStack createNamespaceStack() {
1598 // actually returns a XMLOutputter.NamespaceStack (see below)
1599 return new NamespaceStack();
1600 }
1601
1602 /**
1603 * Our own null subclass of NamespaceStack. This plays a little
1604 * trick with Java access protection. We want subclasses of
1605 * XMLOutputter to be able to override protected methods that
1606 * declare a NamespaceStack parameter, but we don't want to
1607 * declare the parent NamespaceStack class as public.
1608 */
1609 protected class NamespaceStack
1610 extends org.jdom.output.NamespaceStack
1611 {
1612 }
1613
1614 // Support method to print a name without using elt.getQualifiedName()
1615 // and thus avoiding a StringBuffer creation and memory churn
1616 private void printQualifiedName(Writer out, Element e) throws IOException {
1617 if (e.getNamespace().getPrefix().length() == 0) {
1618 out.write(e.getName());
1619 }
1620 else {
1621 out.write(e.getNamespace().getPrefix());
1622 out.write(':');
1623 out.write(e.getName());
1624 }
1625 }
1626
1627 // Support method to print a name without using att.getQualifiedName()
1628 // and thus avoiding a StringBuffer creation and memory churn
1629 private void printQualifiedName(Writer out, Attribute a) throws IOException {
1630 String prefix = a.getNamespace().getPrefix();
1631 if ((prefix != null) && (!prefix.equals(""))) {
1632 out.write(prefix);
1633 out.write(':');
1634 out.write(a.getName());
1635 }
1636 else {
1637 out.write(a.getName());
1638 }
1639 }
1640
1641 // * * * * * * * * * * Deprecated methods * * * * * * * * * *
1642
1643 /* The methods below here are deprecations of protected methods. We
1644 * don't usually deprecate protected methods, so they're commented out.
1645 * They're left here in case this mass deprecation causes people trouble.
1646 * Since we're getting close to 1.0 it's actually better for people to
1647 * raise issues early though.
1648 */
1649
1650 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output;
55
56 import java.io.BufferedOutputStream;
57 import java.io.BufferedWriter;
58 import java.io.IOException;
59 import java.io.OutputStream;
60 import java.io.OutputStreamWriter;
61 import java.io.StringWriter;
62 import java.io.Writer;
63 import java.util.List;
64
65 import org.jdom.Attribute;
66 import org.jdom.CDATA;
67 import org.jdom.Comment;
68 import org.jdom.Content;
69 import org.jdom.DocType;
70 import org.jdom.Document;
71 import org.jdom.Element;
72 import org.jdom.EntityRef;
73 import org.jdom.ProcessingInstruction;
74 import org.jdom.Text;
75 import org.jdom.output.support.AbstractXMLOutputProcessor;
76 import org.jdom.output.support.FormatStack;
77 import org.jdom.output.support.XMLOutputProcessor;
78
79 /**
80 * Outputs a JDOM document as a stream of bytes.
81 * <p>
82 * The XMLOutputter can manage many styles of document formatting, from
83 * untouched to 'pretty' printed. The default is to output the document content
84 * exactly as created, but this can be changed by setting a new Format object:
85 * <ul>
86 * <li>For pretty-print output, use
87 * <code>{@link Format#getPrettyFormat()}</code>.
88 * <li>For whitespace-normalised output, use
89 * <code>{@link Format#getCompactFormat()}</code>.
90 * <li>For unmodified-format output, use
91 * <code>{@link Format#getRawFormat()}</code>.
92 * </ul>
93 * <p>
94 * There are <code>{@link #output output(...)}</code> methods to print any of
95 * the standard JDOM classes to either a Writer or an OutputStream.
96 * <p>
97 * <b>Warning</b>: When outputting to a Writer, make sure the writer's encoding
98 * matches the encoding setting in the Format object. This ensures the encoding
99 * in which the content is written (controlled by the Writer configuration)
100 * matches the encoding placed in the document's XML declaration (controlled by
101 * the XMLOutputter). Because a Writer cannot be queried for its encoding, the
102 * information must be passed to the Format manually in its constructor or via
103 * the <code>{@link Format#setEncoding}</code> method. The default encoding is
104 * UTF-8.
105 * <p>
106 * The methods <code>{@link #outputString outputString(...)}</code> are for
107 * convenience only; for top performance you should call one of the <code>{@link
108 * #output output(...)}</code> methods and pass in your own Writer or
109 * OutputStream if possible.
110 * <p>
111 * <b>All</b> of the <code>output*(...)</code> methods will flush the
112 * destination Writer or OutputStream before returning, and <b>none</b> of them
113 * will <code>close()</code> the destination.
114 * <p>
115 * XML declarations are always printed on their own line followed by a line
116 * separator (this doesn't change the semantics of the document). To omit
117 * printing of the declaration use
118 * <code>{@link Format#setOmitDeclaration}</code>. To omit printing of the
119 * encoding in the declaration use <code>{@link Format#setOmitEncoding}</code>.
120 * Unfortunately there is currently no way to know the original encoding of the
121 * document.
122 * <p>
123 * Empty elements are by default printed as &lt;empty/&gt;, but this can be
124 * configured with <code>{@link Format#setExpandEmptyElements}</code> to cause
125 * them to be expanded to &lt;empty&gt;&lt;/empty&gt;.
126 * <p>
127 * If changing the {@link Format} settings are insufficient for your output
128 * needs you can customise this XMLOutputter further by setting a different
129 * {@link XMLOutputProcessor} with the
130 * {@link #setXMLOutputProcessor(XMLOutputProcessor)} method or an appropriate
131 * constructor. A fully-enabled Abstract class
132 * {@link AbstractXMLOutputProcessor} is available to be further extended to
133 * your needs if all you want to do is tweak some details.
134 *
135 * @author Brett McLaughlin
136 * @author Jason Hunter
137 * @author Jason Reid
138 * @author Wolfgang Werner
139 * @author Elliotte Rusty Harold
140 * @author David &amp; Will (from Post Tool Design)
141 * @author Dan Schaffer
142 * @author Alex Chaffee
143 * @author Bradley S. Huffman
144 */
145
146 public final class XMLOutputter2 implements Cloneable {
147
148 /*
149 * =====================================================================
150 * Static content.
151 * =====================================================================
152 */
153
154 /**
155 * Get an OutputStreamWriter, use specified encoding.
156 *
157 * @param out
158 * The OutputStream to wrap in the writer
159 * @param format
160 * The format is used to obtain the Character Encoding.
161 * @return An Writer (Buffered) that delegates to the specified output steam
162 * @throws java.io.UnsupportedEncodingException
163 */
164 private static final Writer makeWriter(final OutputStream out,
165 final Format format)
166 throws java.io.UnsupportedEncodingException {
167 return new BufferedWriter(new OutputStreamWriter(
168 new BufferedOutputStream(out), format.getEncoding()));
169 }
170
171 /**
172 * Create a final and static instance of the AbstractXMLOutputProcessor The
173 * final part is important because it improves performance.
174 * <p>
175 * The JDOM user can change the actual XMLOutputProcessor with the
176 * {@link XMLOutputter2#setXMLOutputProcessor(XMLOutputProcessor)} method.
177 *
178 * @author rolf
179 */
180 private static final class DefaultXMLProcessor
181 extends AbstractXMLOutputProcessor {
182
183 /**
184 * A helper method to implement backward-compatibility with JDOM1
185 *
186 * @see XMLOutputter2#escapeAttributeEntities(String)
187 * @param str
188 * The String to output.
189 * @param format
190 * The format details to use.
191 * @return The input String escaped as an attribute value.
192 */
193 public String escapeAttributeEntities(String str, Format format) {
194 StringWriter sw = new StringWriter();
195 try {
196 super.attributeEscapedEntitiesFilter(sw, new FormatStack(format), str);
197 } catch (IOException e) {
198 // no IOException on StringWriter....
199 }
200 return sw.toString();
201 }
202
203 /**
204 * A helper method to implement backward-compatibility with JDOM1
205 *
206 * @see XMLOutputter2#escapeElementEntities(String)
207 * @param str
208 * The String to output.
209 * @param format
210 * The format details to use.
211 * @return The input String escaped as an element text value.
212 */
213 public final String escapeElementEntities(final String str,
214 final Format format) {
215 return Format.escapeText(format.getEscapeStrategy(),
216 format.getLineSeparator(), str);
217 }
218
219 }
220
221 /**
222 * This constant XMLOutputProcessor is used for all non-customised
223 * XMLOutputters
224 */
225 private static final DefaultXMLProcessor DEFAULTPROCESSOR =
226 new DefaultXMLProcessor();
227
228 /*
229 * =====================================================================
230 * Instance content.
231 * =====================================================================
232 */
233
234 // For normal output
235 private Format myFormat = null;
236
237 // The actual XMLOutputProcessor to delegate to.
238 private XMLOutputProcessor myProcessor = null;
239
240 /*
241 * =====================================================================
242 * Constructors
243 * =====================================================================
244 */
245
246 /**
247 * This will create an <code>XMLOutputter</code> with the specified format
248 * characteristics.
249 * <p>
250 * <b>Note:</b> the format object is cloned internally before use. If you
251 * want to modify the Format after constructing the XMLOutputter you can
252 * modify the Format instance {@link #getFormat()} returns.
253 *
254 * @param format
255 * The Format instance to use. This instance will be cloned() and as
256 * a consequence, changes made to the specified format instance
257 * <b>will not</b> be reflected in this XMLOutputter. A null input
258 * format indicates that XMLOutputter should use the default
259 * {@link Format#getRawFormat()}
260 * @param processor
261 * The XMLOutputProcessor to delegate output to. If null the
262 * XMLOutputter will use the default XMLOutputProcessor.
263 */
264 public XMLOutputter2(Format format, XMLOutputProcessor processor) {
265 myFormat = format == null ? Format.getRawFormat() : format.clone();
266 myProcessor = processor == null ? DEFAULTPROCESSOR : processor;
267 }
268
269 /**
270 * This will create an <code>XMLOutputter</code> with a default
271 * {@link Format} and {@link XMLOutputProcessor}.
272 */
273 public XMLOutputter2() {
274 this(null, null);
275 }
276
277 /**
278 * This will create an <code>XMLOutputter</code> with the same
279 * customisations set in the given <code>XMLOutputter</code> instance. Note
280 * that <code>XMLOutputter two = one.clone();</code> would work equally
281 * well.
282 *
283 * @param that
284 * the XMLOutputter to clone
285 */
286 public XMLOutputter2(XMLOutputter2 that) {
287 this(that.myFormat, null);
288 }
289
290 /**
291 * This will create an <code>XMLOutputter</code> with the specified format
292 * characteristics.
293 * <p>
294 * <b>Note:</b> the format object is cloned internally before use.
295 *
296 * @param format
297 * The Format instance to use. This instance will be cloned() and as
298 * a consequence, changes made to the specified format instance
299 * <b>will not</b> be reflected in this XMLOutputter. A null input
300 * format indicates that XMLOutputter should use the default
301 * {@link Format#getRawFormat()}
302 */
303 public XMLOutputter2(Format format) {
304 this(format, null);
305 }
306
307 /**
308 * This will create an <code>XMLOutputter</code> with the specified
309 * XMLOutputProcessor.
310 *
311 * @param processor
312 * The XMLOutputProcessor to delegate output to. If null the
313 * XMLOutputter will use the default XMLOutputProcessor.
314 */
315 public XMLOutputter2(XMLOutputProcessor processor) {
316 this(null, processor);
317 }
318
319 /*
320 * =======================================================================
321 * API - Settings...
322 * =======================================================================
323 */
324
325 /**
326 * Sets the new format logic for the XMLOutputter. Note the Format object is
327 * cloned internally before use.
328 *
329 * @see #getFormat()
330 * @param newFormat
331 * the format to use for subsequent output
332 */
333 public void setFormat(Format newFormat) {
334 this.myFormat = newFormat.clone();
335 }
336
337 /**
338 * Returns the current format in use by the XMLOutputter. Note the Format
339 * object returned is <b>not</b> a clone of the one used internally, thus,
340 * an XMLOutputter instance is able to have it's Format changed by changing
341 * the settings on the Format instance returned by this method.
342 *
343 * @return the current Format instance used by this XMLOutputter.
344 */
345 public Format getFormat() {
346 return myFormat;
347 }
348
349 /**
350 * Returns the current XMLOutputProcessor instance in use by the
351 * XMLOutputter.
352 *
353 * @return the current XMLOutputProcessor instance.
354 */
355 public XMLOutputProcessor getXMLOutputProcessor() {
356 return myProcessor;
357 }
358
359 /**
360 * Sets a new XMLOutputProcessor instance for this XMLOutputter. Note the
361 * processor object is expected to be thread-safe.
362 *
363 * @param processor
364 * the new XMLOutputProcesor to use for output
365 */
366 public void setXMLOutputProcessor(XMLOutputProcessor processor) {
367 this.myProcessor = processor;
368 }
369
370 /*
371 * =======================================================================
372 * API - Output to STREAM Methods ... All methods defer to the WRITER
373 * equivalents
374 * =======================================================================
375 */
376
377 /**
378 * This will print the <code>{@link Document}</code> to the given
379 * OutputStream. The characters are printed using the encoding specified in
380 * the constructor, or a default of UTF-8.
381 *
382 * @param doc
383 * <code>Document</code> to format.
384 * @param out
385 * <code>OutputStream</code> to use.
386 * @throws IOException
387 * if there's any problem writing.
388 * @throws NullPointerException
389 * if the specified content is null.
390 */
391 public final void output(Document doc, OutputStream out)
392 throws IOException {
393 output(doc, makeWriter(out, myFormat));
394 }
395
396 /**
397 * This will print the <code>{@link DocType}</code> to the given
398 * OutputStream.
399 *
400 * @param doctype
401 * <code>DocType</code> to output.
402 * @param out
403 * <code>OutputStream</code> to use.
404 * @throws IOException
405 * if there's any problem writing.
406 * @throws NullPointerException
407 * if the specified content is null.
408 */
409 public final void output(DocType doctype, OutputStream out) throws IOException {
410 output(doctype, makeWriter(out, myFormat));
411 }
412
413 /**
414 * Print out an <code>{@link Element}</code>, including its
415 * <code>{@link Attribute}</code>s, and all contained (child) elements, etc.
416 *
417 * @param element
418 * <code>Element</code> to output.
419 * @param out
420 * <code>OutputStream</code> to use.
421 * @throws IOException
422 * if there's any problem writing.
423 * @throws NullPointerException
424 * if the specified content is null.
425 */
426 public final void output(Element element, OutputStream out) throws IOException {
427 output(element, makeWriter(out, myFormat));
428 }
429
430 /**
431 * This will handle printing out an <code>{@link
432 * Element}</code>'s content only, not including its tag, and attributes.
433 * This can be useful for printing the content of an element that contains
434 * HTML, like "&lt;description&gt;JDOM is
435 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
436 *
437 * @param element
438 * <code>Element</code> to output.
439 * @param out
440 * <code>OutputStream</code> to use.
441 * @throws IOException
442 * if there's any problem writing.
443 * @throws NullPointerException
444 * if the specified content is null.
445 */
446 public final void outputElementContent(Element element, OutputStream out)
447 throws IOException {
448 outputElementContent(element, makeWriter(out, myFormat));
449 }
450
451 /**
452 * This will handle printing out a list of nodes. This can be useful for
453 * printing the content of an element that contains HTML, like
454 * "&lt;description&gt;JDOM is &lt;b&gt;fun&gt;!&lt;/description&gt;".
455 * <p>
456 * The list is assumed to contain legal JDOM nodes. If other content is
457 * coerced on to the list it will cause ClassCastExceptions, and null Lists
458 * or null list members will cause NullPointerException.
459 *
460 * @param list
461 * <code>List</code> of nodes.
462 * @param out
463 * <code>OutputStream</code> to use.
464 * @throws IOException
465 * if there's any problem writing.
466 * @throws ClassCastException
467 * if non-{@link Content} is forced in to the list
468 * @throws NullPointerException
469 * if the List is null or contains null members.
470 */
471 public final void output(List<? extends Content> list, OutputStream out)
472 throws IOException {
473 output(list, makeWriter(out, myFormat)); // output() flushes
474 }
475
476 /**
477 * Print out a <code>{@link CDATA}</code> node.
478 *
479 * @param cdata
480 * <code>CDATA</code> to output.
481 * @param out
482 * <code>OutputStream</code> to use.
483 * @throws IOException
484 * if there's any problem writing.
485 * @throws NullPointerException
486 * if the specified content is null.
487 */
488 public final void output(CDATA cdata, OutputStream out) throws IOException {
489 output(cdata, makeWriter(out, myFormat)); // output() flushes
490 }
491
492 /**
493 * Print out a <code>{@link Text}</code> node. Perfoms the necessary entity
494 * escaping and whitespace stripping.
495 *
496 * @param text
497 * <code>Text</code> to output.
498 * @param out
499 * <code>OutputStream</code> to use.
500 * @throws IOException
501 * if there's any problem writing.
502 * @throws NullPointerException
503 * if the specified content is null.
504 */
505 public final void output(Text text, OutputStream out) throws IOException {
506 output(text, makeWriter(out, myFormat)); // output() flushes
507 }
508
509 /**
510 * Print out a <code>{@link Comment}</code>.
511 *
512 * @param comment
513 * <code>Comment</code> to output.
514 * @param out
515 * <code>OutputStream</code> to use.
516 * @throws IOException
517 * if there's any problem writing.
518 * @throws NullPointerException
519 * if the specified content is null.
520 */
521 public final void output(Comment comment, OutputStream out) throws IOException {
522 output(comment, makeWriter(out, myFormat)); // output() flushes
523 }
524
525 /**
526 * Print out a <code>{@link ProcessingInstruction}</code>.
527 *
528 * @param pi
529 * <code>ProcessingInstruction</code> to output.
530 * @param out
531 * <code>OutputStream</code> to use.
532 * @throws IOException
533 * if there's any problem writing.
534 * @throws NullPointerException
535 * if the specified content is null.
536 */
537 public final void output(ProcessingInstruction pi, OutputStream out)
538 throws IOException {
539 output(pi, makeWriter(out, myFormat)); // output() flushes
540 }
541
542 /**
543 * Print out a <code>{@link EntityRef}</code>.
544 *
545 * @param entity
546 * <code>EntityRef</code> to output.
547 * @param out
548 * <code>OutputStream</code> to use.
549 * @throws IOException
550 * if there's any problem writing.
551 * @throws NullPointerException
552 * if the specified content is null.
553 */
554 public void output(EntityRef entity, OutputStream out) throws IOException {
555 output(entity, makeWriter(out, myFormat)); // output() flushes
556 }
557
558 /*
559 * =======================================================================
560 * API - Output to STRING Methods ... All methods defer to the WRITER
561 * equivalents
562 * =======================================================================
563 */
564
565 /**
566 * Return a string representing a {@link Document}. Uses an internal
567 * StringWriter.
568 * <p>
569 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
570 * specified encoding.
571 *
572 * @param doc
573 * <code>Document</code> to format.
574 * @return the input content formatted as an XML String.
575 * @throws NullPointerException
576 * if the specified content is null.
577 */
578 public final String outputString(Document doc) {
579 StringWriter out = new StringWriter();
580 try {
581 output(doc, out); // output() flushes
582 } catch (IOException e) {
583 // swallow - will never happen.
584 }
585 return out.toString();
586 }
587
588 /**
589 * Return a string representing a {@link DocType}.
590 * <p>
591 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
592 * specified encoding.
593 *
594 * @param doctype
595 * <code>DocType</code> to format.
596 * @return the input content formatted as an XML String.
597 * @throws NullPointerException
598 * if the specified content is null.
599 */
600 public final String outputString(DocType doctype) {
601 StringWriter out = new StringWriter();
602 try {
603 output(doctype, out); // output() flushes
604 } catch (IOException e) {
605 // swallow - will never happen.
606 }
607 return out.toString();
608 }
609
610 /**
611 * Return a string representing an {@link Element}.
612 * <p>
613 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
614 * specified encoding.
615 *
616 * @param element
617 * <code>Element</code> to format.
618 * @return the input content formatted as an XML String.
619 * @throws NullPointerException
620 * if the specified content is null.
621 */
622 public final String outputString(Element element) {
623 StringWriter out = new StringWriter();
624 try {
625 output(element, out); // output() flushes
626 } catch (IOException e) {
627 // swallow - will never happen.
628 }
629 return out.toString();
630 }
631
632 /**
633 * Return a string representing a List of {@link Content} nodes. <br>
634 * The list is assumed to contain legal JDOM nodes. If other content is
635 * coerced on to the list it will cause ClassCastExceptions, and null List
636 * members will cause NullPointerException.
637 * <p>
638 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
639 * specified encoding.
640 *
641 * @param list
642 * <code>List</code> to format.
643 * @return the input content formatted as an XML String.
644 * @throws ClassCastException
645 * if non-{@link Content} is forced in to the list
646 * @throws NullPointerException
647 * if the List is null or contains null members.
648 */
649 public final String outputString(List<? extends Content> list) {
650 StringWriter out = new StringWriter();
651 try {
652 output(list, out); // output() flushes
653 } catch (IOException e) {
654 // swallow - will never happen.
655 }
656 return out.toString();
657 }
658
659 /**
660 * Return a string representing a {@link CDATA} node.
661 * <p>
662 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
663 * specified encoding.
664 *
665 * @param cdata
666 * <code>CDATA</code> to format.
667 * @return the input content formatted as an XML String.
668 * @throws NullPointerException
669 * if the specified content is null.
670 */
671 public final String outputString(CDATA cdata) {
672 StringWriter out = new StringWriter();
673 try {
674 output(cdata, out); // output() flushes
675 } catch (IOException e) {
676 // swallow - will never happen.
677 }
678 return out.toString();
679 }
680
681 /**
682 * Return a string representing a {@link Text} node.
683 * <p>
684 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
685 * specified encoding.
686 *
687 * @param text
688 * <code>Text</code> to format.
689 * @return the input content formatted as an XML String.
690 * @throws NullPointerException
691 * if the specified content is null.
692 */
693 public final String outputString(Text text) {
694 StringWriter out = new StringWriter();
695 try {
696 output(text, out); // output() flushes
697 } catch (IOException e) {
698 // swallow - will never happen.
699 }
700 return out.toString();
701 }
702
703 /**
704 * Return a string representing a {@link Comment}.
705 * <p>
706 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
707 * specified encoding.
708 *
709 * @param comment
710 * <code>Comment</code> to format.
711 * @return the input content formatted as an XML String.
712 * @throws NullPointerException
713 * if the specified content is null.
714 */
715 public final String outputString(Comment comment) {
716 StringWriter out = new StringWriter();
717 try {
718 output(comment, out); // output() flushes
719 } catch (IOException e) {
720 // swallow - will never happen.
721 }
722 return out.toString();
723 }
724
725 /**
726 * Return a string representing a {@link ProcessingInstruction}.
727 * <p>
728 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
729 * specified encoding.
730 *
731 * @param pi
732 * <code>ProcessingInstruction</code> to format.
733 * @return the input content formatted as an XML String.
734 * @throws NullPointerException
735 * if the specified content is null.
736 */
737 public final String outputString(ProcessingInstruction pi) {
738 StringWriter out = new StringWriter();
739 try {
740 output(pi, out); // output() flushes
741 } catch (IOException e) {
742 // swallow - will never happen.
743 }
744 return out.toString();
745 }
746
747 /**
748 * Return a string representing an {@link EntityRef}.
749 * <p>
750 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
751 * specified encoding.
752 *
753 * @param entity
754 * <code>EntityRef</code> to format.
755 * @return the input content formatted as an XML String.
756 * @throws NullPointerException
757 * if the specified content is null.
758 */
759 public final String outputString(EntityRef entity) {
760 StringWriter out = new StringWriter();
761 try {
762 output(entity, out); // output() flushes
763 } catch (IOException e) {
764 // swallow - will never happen.
765 }
766 return out.toString();
767 }
768
769 /**
770 * This will handle printing out an <code>{@link
771 * Element}</code>'s content only, not including its tag, and attributes.
772 * This can be useful for printing the content of an element that contains
773 * HTML, like "&lt;description&gt;JDOM is
774 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
775 * <p>
776 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
777 * specified encoding.
778 *
779 * @param element
780 * <code>Element</code> to output.
781 * @return the input content formatted as an XML String.
782 * @throws NullPointerException
783 * if the specified content is null.
784 */
785 public final String outputElementContentString(Element element) {
786 StringWriter out = new StringWriter();
787 try {
788 outputElementContent(element, out); // output() flushes
789 } catch (IOException e) {
790 // swallow - will never happen.
791 }
792 return out.toString();
793 }
794
795 /*
796 * ========================================================================
797 * API - Output to WRITER Methods ... These are the core methods that the
798 * Stream and String output methods call. On the other hand, these methods
799 * defer to the protected/override methods. These methods flush the writer.
800 * ========================================================================
801 */
802
803 /**
804 * This will print the <code>Document</code> to the given Writer.
805 * <p>
806 * Warning: using your own Writer may cause the outputter's preferred
807 * character encoding to be ignored. If you use encodings other than UTF-8,
808 * we recommend using the method that takes an OutputStream instead.
809 * </p>
810 *
811 * @param doc
812 * <code>Document</code> to format.
813 * @param out
814 * <code>Writer</code> to use.
815 * @throws IOException
816 * - if there's any problem writing.
817 * @throws NullPointerException
818 * if the specified content is null.
819 */
820 public final void output(Document doc, Writer out) throws IOException {
821 myProcessor.process(out, myFormat, doc);
822 out.flush();
823 }
824
825 /**
826 * Print out the <code>{@link DocType}</code>.
827 *
828 * @param doctype
829 * <code>DocType</code> to output.
830 * @param out
831 * <code>Writer</code> to use.
832 * @throws IOException
833 * - if there's any problem writing.
834 * @throws NullPointerException
835 * if the specified content is null.
836 */
837 public final void output(DocType doctype, Writer out) throws IOException {
838 myProcessor.process(out, myFormat, doctype);
839 out.flush();
840 }
841
842 /**
843 * Print out an <code>{@link Element}</code>, including its
844 * <code>{@link Attribute}</code>s, and all contained (child) elements, etc.
845 *
846 * @param element
847 * <code>Element</code> to output.
848 * @param out
849 * <code>Writer</code> to use.
850 * @throws IOException
851 * - if there's any problem writing.
852 * @throws NullPointerException
853 * if the specified content is null.
854 */
855 public final void output(Element element, Writer out) throws IOException {
856 // If this is the root element we could pre-initialize the
857 // namespace stack with the namespaces
858 myProcessor.process(out, myFormat, element);
859 out.flush();
860 }
861
862 /**
863 * This will handle printing out an <code>{@link
864 * Element}</code>'s content only, not including its tag, and attributes.
865 * This can be useful for printing the content of an element that contains
866 * HTML, like "&lt;description&gt;JDOM is
867 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
868 *
869 * @param element
870 * <code>Element</code> to output.
871 * @param out
872 * <code>Writer</code> to use.
873 * @throws IOException
874 * - if there's any problem writing.
875 * @throws NullPointerException
876 * if the specified content is null.
877 */
878 public final void outputElementContent(Element element, Writer out)
879 throws IOException {
880 myProcessor.process(out, myFormat, element.getContent());
881 out.flush();
882 }
883
884 /**
885 * This will handle printing out a list of nodes. This can be useful for
886 * printing the content of an element that contains HTML, like
887 * "&lt;description&gt;JDOM is &lt;b&gt;fun&gt;!&lt;/description&gt;".
888 *
889 * @param list
890 * <code>List</code> of nodes.
891 * @param out
892 * <code>Writer</code> to use.
893 * @throws IOException
894 * - if there's any problem writing.
895 * @throws NullPointerException
896 * if the specified content is null.
897 */
898 public final void output(List<? extends Content> list, Writer out)
899 throws IOException {
900 myProcessor.process(out, myFormat, list);
901 out.flush();
902 }
903
904 /**
905 * Print out a <code>{@link CDATA}</code> node.
906 *
907 * @param cdata
908 * <code>CDATA</code> to output.
909 * @param out
910 * <code>Writer</code> to use.
911 * @throws IOException
912 * - if there's any problem writing.
913 * @throws NullPointerException
914 * if the specified content is null.
915 */
916 public final void output(CDATA cdata, Writer out) throws IOException {
917 myProcessor.process(out, myFormat, cdata);
918 out.flush();
919 }
920
921 /**
922 * Print out a <code>{@link Text}</code> node. Perfoms the necessary entity
923 * escaping and whitespace stripping.
924 *
925 * @param text
926 * <code>Text</code> to output.
927 * @param out
928 * <code>Writer</code> to use.
929 * @throws IOException
930 * - if there's any problem writing.
931 * @throws NullPointerException
932 * if the specified content is null.
933 */
934 public final void output(Text text, Writer out) throws IOException {
935 myProcessor.process(out, myFormat, text);
936 out.flush();
937 }
938
939 /**
940 * Print out a <code>{@link Comment}</code>.
941 *
942 * @param comment
943 * <code>Comment</code> to output.
944 * @param out
945 * <code>Writer</code> to use.
946 * @throws IOException
947 * - if there's any problem writing.
948 * @throws NullPointerException
949 * if the specified content is null.
950 */
951 public final void output(Comment comment, Writer out) throws IOException {
952 myProcessor.process(out, myFormat, comment);
953 out.flush();
954 }
955
956 /**
957 * Print out a <code>{@link ProcessingInstruction}</code>.
958 *
959 * @param pi
960 * <code>ProcessingInstruction</code> to output.
961 * @param out
962 * <code>Writer</code> to use.
963 * @throws IOException
964 * - if there's any problem writing.
965 * @throws NullPointerException
966 * if the specified content is null.
967 */
968 public final void output(ProcessingInstruction pi, Writer out)
969 throws IOException {
970 myProcessor.process(out, myFormat, pi);
971 out.flush();
972 }
973
974 /**
975 * Print out an <code>{@link EntityRef}</code>.
976 *
977 * @param entity
978 * <code>EntityRef</code> to output.
979 * @param out
980 * <code>Writer</code> to use.
981 * @throws IOException
982 * - if there's any problem writing.
983 * @throws NullPointerException
984 * if the specified content is null.
985 */
986 public final void output(EntityRef entity, Writer out) throws IOException {
987 myProcessor.process(out, myFormat, entity);
988 out.flush();
989 }
990
991 /*
992 * ========================================================================
993 * SpecialCaseMethods for maintaining API Compatibility
994 * ========================================================================
995 */
996
997 /**
998 * Escape any characters in the input string in such a way that the returned
999 * value is valid as output in an XML Attribute value.
1000 *
1001 * @param str
1002 * the input String to escape
1003 * @return the escaped version of the input String
1004 */
1005 public String escapeAttributeEntities(String str) {
1006 return DEFAULTPROCESSOR.escapeAttributeEntities(str, myFormat);
1007 }
1008
1009 /**
1010 * Escape any characters in the input string in such a way that the returned
1011 * value is valid as output in an XML Element text.
1012 *
1013 * @param str
1014 * the input String to escape
1015 * @return the escaped version of the input String
1016 */
1017 public String escapeElementEntities(String str) {
1018 return DEFAULTPROCESSOR.escapeElementEntities(str, myFormat);
1019 }
1020
1021 /*
1022 * ========================================================================
1023 * Basic Support methods.
1024 * ========================================================================
1025 */
1026
1027 /**
1028 * Returns a cloned copy of this XMLOutputter.
1029 */
1030 @Override
1031 public XMLOutputter2 clone() {
1032 // Implementation notes: Since all state of an XMLOutputter is
1033 // embodied in simple private instance variables, Object.clone
1034 // can be used. Note that since Object.clone is totally
1035 // broken, we must catch an exception that will never be
1036 // thrown.
1037 try {
1038 return (XMLOutputter2) super.clone();
1039 } catch (java.lang.CloneNotSupportedException e) {
1040 // even though this should never ever happen, it's still
1041 // possible to fool Java into throwing a
1042 // CloneNotSupportedException. If that happens, we
1043 // shouldn't swallow it.
1044 throw new RuntimeException(e.toString());
1045 }
1046 }
1047
1048 /**
1049 * Return a string listing of the settings for this XMLOutputter instance.
1050 *
1051 * @return a string listing the settings for this XMLOutputter instance
1052 */
1053 @Override
1054 public String toString() {
1055 StringBuilder buffer = new StringBuilder();
1056 buffer.append("XMLOutputter[omitDeclaration = ");
1057 buffer.append(myFormat.omitDeclaration);
1058 buffer.append(", ");
1059 buffer.append("encoding = ");
1060 buffer.append(myFormat.encoding);
1061 buffer.append(", ");
1062 buffer.append("omitEncoding = ");
1063 buffer.append(myFormat.omitEncoding);
1064 buffer.append(", ");
1065 buffer.append("indent = '");
1066 buffer.append(myFormat.indent);
1067 buffer.append("'");
1068 buffer.append(", ");
1069 buffer.append("expandEmptyElements = ");
1070 buffer.append(myFormat.expandEmptyElements);
1071 buffer.append(", ");
1072 buffer.append("lineSeparator = '");
1073 for (char ch : myFormat.lineSeparator.toCharArray()) {
1074 switch (ch) {
1075 case '\r':
1076 buffer.append("\\r");
1077 break;
1078 case '\n':
1079 buffer.append("\\n");
1080 break;
1081 case '\t':
1082 buffer.append("\\t");
1083 break;
1084 default:
1085 buffer.append("[" + ((int) ch) + "]");
1086 break;
1087 }
1088 }
1089 buffer.append("', ");
1090 buffer.append("textMode = ");
1091 buffer.append(myFormat.mode + "]");
1092 return buffer.toString();
1093 }
1094
1095 }
0 <body>
1
2 Classes to output JDOM documents to various destinations. The most common
3 outputter class is XMLOutputter which outputs a document (or part of a
4 document) as a stream of bytes. Format and EscapeStrategy support the
5 XMLOutputter in letting you choose how the output should be formatted and how
6 special characters should be escaped.
7
8 SAXOutputter lets you output as a stream of SAX events (handy especially in
9 transformations). JDOMLocator supports SAXOutputter and helps you observe the
10 SAX output process.
11
12 DOMOutputter lets you output a JDOM document as a DOM tree.
13
14 StAXStreamOutputter lets you output the JDOM content to an XMLStreamWriter, and
15 the StAXEventOutputter lets you output the JDOM content to an XMLEventWriter.
16
17 </body>
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.List;
59
60 import org.jdom.Attribute;
61 import org.jdom.CDATA;
62 import org.jdom.Comment;
63 import org.jdom.Content;
64 import org.jdom.Content.CType;
65 import org.jdom.Document;
66 import org.jdom.Element;
67 import org.jdom.EntityRef;
68 import org.jdom.JDOMConstants;
69 import org.jdom.Namespace;
70 import org.jdom.ProcessingInstruction;
71 import org.jdom.Text;
72 import org.jdom.output.DOMOutputter;
73 import org.jdom.output.Format;
74 import org.jdom.output.Format.TextMode;
75 import org.jdom.util.NamespaceStack;
76
77 /**
78 * This class provides a concrete implementation of {@link DOMOutputProcessor}
79 * for supporting the {@link DOMOutputter}.
80 * <p>
81 * <h2>Overview</h2>
82 * <p>
83 * This class is marked abstract even though all methods are fully implemented.
84 * The <code>process*(...)</code> methods are public because they match the
85 * DOMOutputProcessor interface but the remaining methods are all protected.
86 * <p>
87 * People who want to create a custom DOMOutputProcessor for DOMOutputter
88 * are able to extend this class and modify any functionality they want. Before
89 * sub-classing this you should first check to see if the {@link Format} class
90 * can get you the results you want.
91 * <p>
92 * <b><i>Subclasses of this should have reentrant methods.</i></b> This is
93 * easiest to accomplish simply by not allowing any instance fields. If your
94 * sub-class has an instance field/variable, then it's probably broken.
95 * <p>
96 * <h2>The Stacks</h2>
97 * <p>
98 * One significant feature of this implementation is that it creates and
99 * maintains both a {@link NamespaceStack} and {@link FormatStack} that are
100 * managed in the
101 * {@link #printElement(FormatStack, NamespaceStack, org.w3c.dom.Document, Element)}
102 * method. The stacks are pushed and popped in that method only. They
103 * significantly improve the performance and readability of the code.
104 * <p>
105 * The NamespaceStack is only sent through to the
106 * {@link #printElement(FormatStack, NamespaceStack, org.w3c.dom.Document, Element)}
107 * and
108 * {@link #printContent(FormatStack, NamespaceStack, org.w3c.dom.Document, org.w3c.dom.Node, Walker)}
109 * methods, but the FormatStack is pushed through to all print* Methods.
110 * <p>
111 * <h2>Content Processing</h2>
112 * <p>
113 * This class delegates the formatting of the content to the Walker classes
114 * and you can create your own custom walker by overriding the
115 * {@link #buildWalker(FormatStack, List, boolean)} method.
116 *
117 * @see DOMOutputter
118 * @see DOMOutputProcessor
119 * @since JDOM2
120 * @author Rolf Lear
121 */
122 public abstract class AbstractDOMOutputProcessor extends
123 AbstractOutputProcessor implements DOMOutputProcessor {
124
125 /**
126 * This will handle adding any <code>{@link Namespace}</code> attributes to
127 * the DOM tree.
128 *
129 * @param ns
130 * <code>Namespace</code> to add definition of
131 */
132 private static String getXmlnsTagFor(Namespace ns) {
133 String attrName = "xmlns";
134 if (!ns.getPrefix().equals("")) {
135 attrName += ":";
136 attrName += ns.getPrefix();
137 }
138 return attrName;
139 }
140
141 /* *******************************************
142 * DOMOutputProcessor implementation.
143 * *******************************************
144 */
145
146 @Override
147 public org.w3c.dom.Document process(org.w3c.dom.Document basedoc,
148 Format format, Document doc) {
149 return printDocument(new FormatStack(format), new NamespaceStack(),
150 basedoc, doc);
151 }
152
153 @Override
154 public org.w3c.dom.Element process(org.w3c.dom.Document basedoc,
155 Format format, Element element) {
156 return printElement(new FormatStack(format), new NamespaceStack(),
157 basedoc, element);
158 }
159
160 @Override
161 public List<org.w3c.dom.Node> process(org.w3c.dom.Document basedoc,
162 Format format, List<? extends Content> list) {
163 List<org.w3c.dom.Node> ret = new ArrayList<org.w3c.dom.Node>(
164 list.size());
165 FormatStack fstack = new FormatStack(format);
166 NamespaceStack nstack = new NamespaceStack();
167 for (Content c : list) {
168 fstack.push();
169 try {
170 org.w3c.dom.Node node = helperContentDispatcher(fstack, nstack,
171 basedoc, c);
172 if (node != null) {
173 ret.add(node);
174 }
175 } finally {
176 fstack.pop();
177 }
178 }
179 return ret;
180 }
181
182 @Override
183 public org.w3c.dom.CDATASection process(org.w3c.dom.Document basedoc,
184 Format format, CDATA cdata) {
185 final List<CDATA> list = Collections.singletonList(cdata);
186 final FormatStack fstack = new FormatStack(format);
187 final Walker walker = buildWalker(fstack, list, false);
188 if (walker.hasNext()) {
189 final Content c = walker.next();
190 if (c == null) {
191 return printCDATA(fstack, basedoc, new CDATA(walker.text()));
192 }
193 if (c.getCType() == CType.CDATA) {
194 return printCDATA(fstack, basedoc, (CDATA)c);
195 }
196 }
197 // return an empty string if nothing happened.
198 return null;
199 }
200
201 @Override
202 public org.w3c.dom.Text process(org.w3c.dom.Document basedoc,
203 Format format, Text text) {
204 final List<Text> list = Collections.singletonList(text);
205 final FormatStack fstack = new FormatStack(format);
206 final Walker walker = buildWalker(fstack, list, false);
207 if (walker.hasNext()) {
208 final Content c = walker.next();
209 if (c == null) {
210 return printText(fstack, basedoc, new Text(walker.text()));
211 }
212 if (c.getCType() == CType.Text) {
213 return printText(fstack, basedoc, (Text)c);
214 }
215 }
216 // return an empty string if nothing happened.
217 return null;
218 }
219
220 @Override
221 public org.w3c.dom.Comment process(org.w3c.dom.Document basedoc,
222 Format format, Comment comment) {
223 return printComment(new FormatStack(format), basedoc, comment);
224 }
225
226 @Override
227 public org.w3c.dom.ProcessingInstruction process(
228 org.w3c.dom.Document basedoc, Format format,
229 ProcessingInstruction pi) {
230 return printProcessingInstruction(new FormatStack(format), basedoc, pi);
231 }
232
233 @Override
234 public org.w3c.dom.EntityReference process(org.w3c.dom.Document basedoc,
235 Format format, EntityRef entity) {
236 return printEntityRef(new FormatStack(format), basedoc, entity);
237 }
238
239 @Override
240 public org.w3c.dom.Attr process(org.w3c.dom.Document basedoc, Format format,
241 Attribute attribute) {
242 return printAttribute(new FormatStack(format), basedoc, attribute);
243 }
244
245 /* *******************************************
246 * Support methods for output. Should all be protected. All content-type
247 * print methods have a FormatStack. Only printContent is responsible for
248 * outputting appropriate indenting and newlines, which are easily available
249 * using the FormatStack.getLevelIndent() and FormatStack.getLevelEOL().
250 * *******************************************
251 */
252
253 /**
254 * This will handle printing of a {@link Document}.
255 *
256 * @param fstack
257 * the FormatStack
258 * @param nstack
259 * the NamespaceStack
260 * @param basedoc
261 * The org.w3c.dom.Document for creating DOM Nodes
262 * @param doc
263 * <code>Document</code> to write.
264 * @return The input JDOM document converted to a DOM document.
265 */
266 protected org.w3c.dom.Document printDocument(final FormatStack fstack,
267 final NamespaceStack nstack, final org.w3c.dom.Document basedoc,
268 final Document doc) {
269
270 if (!fstack.isOmitDeclaration()) {
271 basedoc.setXmlVersion("1.0");
272 }
273
274 final int sz = doc.getContentSize();
275
276 if (sz > 0) {
277 for (int i = 0; i < sz; i++) {
278 final Content c = doc.getContent(i);
279 org.w3c.dom.Node n = null;
280 switch (c.getCType()) {
281 case Comment :
282 n = printComment(fstack, basedoc, (Comment)c);
283 break;
284 case DocType :
285 // cannot simply add a DocType to a DOM object
286 // it is added when the DOM Document is created.
287 // leave n as null
288 break;
289 case Element :
290 n = printElement(fstack, nstack, basedoc, (Element)c);
291 break;
292 case ProcessingInstruction :
293 n = printProcessingInstruction(fstack, basedoc,
294 (ProcessingInstruction)c);
295 break;
296 default :
297 // do nothing.
298 }
299 if (n != null) {
300 basedoc.appendChild(n);
301 }
302 }
303 }
304
305 return basedoc;
306 }
307
308 /**
309 * This will handle printing of a {@link ProcessingInstruction}.
310 *
311 * @param fstack
312 * the FormatStack
313 * @param basedoc
314 * The org.w3c.dom.Document for creating DOM Nodes
315 * @param pi
316 * <code>ProcessingInstruction</code> to write.
317 * @return The input JDOM ProcessingInstruction converted to a DOM
318 * ProcessingInstruction.
319 */
320 protected org.w3c.dom.ProcessingInstruction printProcessingInstruction(
321 final FormatStack fstack, final org.w3c.dom.Document basedoc,
322 final ProcessingInstruction pi) {
323 String target = pi.getTarget();
324 String rawData = pi.getData();
325 if (rawData == null || rawData.trim().length() == 0) {
326 rawData = "";
327 }
328 return basedoc.createProcessingInstruction(target, rawData);
329 }
330
331 /**
332 * This will handle printing of a {@link Comment}.
333 *
334 * @param fstack
335 * the FormatStack
336 * @param basedoc
337 * The org.w3c.dom.Document for creating DOM Nodes
338 * @param comment
339 * <code>Comment</code> to write.
340 * @return The input JDOM Comment converted to a DOM Comment
341 */
342 protected org.w3c.dom.Comment printComment(final FormatStack fstack,
343 final org.w3c.dom.Document basedoc, final Comment comment) {
344 return basedoc.createComment(comment.getText());
345 }
346
347 /**
348 * This will handle printing of an {@link EntityRef}.
349 *
350 * @param fstack
351 * the FormatStack
352 * @param basedoc
353 * The org.w3c.dom.Document for creating DOM Nodes
354 * @param entity
355 * <code>EntotyRef</code> to write.
356 * @return The input JDOM EntityRef converted to a DOM EntityReference
357 */
358 protected org.w3c.dom.EntityReference printEntityRef(
359 final FormatStack fstack, final org.w3c.dom.Document basedoc,
360 final EntityRef entity) {
361 return basedoc.createEntityReference(entity.getName());
362 }
363
364 /**
365 * This will handle printing of a {@link CDATA}.
366 *
367 * @param fstack
368 * the FormatStack
369 * @param basedoc
370 * The org.w3c.dom.Document for creating DOM Nodes
371 * @param cdata
372 * <code>CDATA</code> to write.
373 * @return The input JDOM CDATA converted to a DOM CDATASection
374 */
375 protected org.w3c.dom.CDATASection printCDATA(final FormatStack fstack,
376 final org.w3c.dom.Document basedoc, final CDATA cdata) {
377 // CDATAs are treated like text, not indented/newline content.
378 return basedoc.createCDATASection(cdata.getText());
379 }
380
381 /**
382 * This will handle printing of a {@link Text}.
383 *
384 * @param fstack
385 * the FormatStack
386 * @param basedoc
387 * The org.w3c.dom.Document for creating DOM Nodes
388 * @param text
389 * <code>Text</code> to write.
390 * @return The input JDOM Text converted to a DOM Text
391 */
392 protected org.w3c.dom.Text printText(final FormatStack fstack,
393 final org.w3c.dom.Document basedoc, final Text text) {
394 return basedoc.createTextNode(text.getText());
395 }
396
397 /**
398 * This will handle printing of a {@link Attribute}.
399 *
400 * @param fstack
401 * the FormatStack
402 * @param basedoc
403 * The org.w3c.dom.Document for creating DOM Nodes
404 * @param attribute
405 * <code>Attribute</code> to write.
406 * @return The input JDOM Attribute converted to a DOM Attr
407 */
408 protected org.w3c.dom.Attr printAttribute(final FormatStack fstack,
409 final org.w3c.dom.Document basedoc, final Attribute attribute) {
410 if (!attribute.isSpecified() && fstack.isSpecifiedAttributesOnly()) {
411 return null;
412 }
413 org.w3c.dom.Attr attr = basedoc.createAttributeNS(
414 attribute.getNamespaceURI(), attribute.getQualifiedName());
415 attr.setValue(attribute.getValue());
416 return attr;
417 }
418
419 /**
420 * This will handle printing of an {@link Element}.
421 * <p>
422 * This method arranges for outputting the Element infrastructure including
423 * Namespace Declarations and Attributes.
424 * <p>
425 * The actual formatting of the content is managed by the Walker created for
426 * the Element's content.
427 * <p>
428 *
429 * @param fstack
430 * the FormatStack
431 * @param nstack
432 * the NamespaceStack
433 * @param basedoc
434 * The org.w3c.dom.Document for creating DOM Nodes
435 * @param element
436 * <code>Element</code> to write.
437 * @return The input JDOM Element converted to a DOM Element
438 */
439 protected org.w3c.dom.Element printElement(final FormatStack fstack,
440 final NamespaceStack nstack, final org.w3c.dom.Document basedoc,
441 final Element element) {
442
443 nstack.push(element);
444 try {
445
446 TextMode textmode = fstack.getTextMode();
447
448 // Check for xml:space and adjust format settings
449 final String space = element.getAttributeValue("space",
450 Namespace.XML_NAMESPACE);
451
452 if ("default".equals(space)) {
453 textmode = fstack.getDefaultMode();
454 } else if ("preserve".equals(space)) {
455 textmode = TextMode.PRESERVE;
456 }
457
458 org.w3c.dom.Element ret = basedoc.createElementNS(
459 element.getNamespaceURI(), element.getQualifiedName());
460
461 for (Namespace ns : nstack.addedForward()) {
462 if (ns == Namespace.XML_NAMESPACE) {
463 continue;
464 }
465 ret.setAttributeNS(JDOMConstants.NS_URI_XMLNS, getXmlnsTagFor(ns), ns.getURI());
466 }
467
468 if (element.hasAttributes()) {
469 for (Attribute att : element.getAttributes()) {
470 final org.w3c.dom.Attr a = printAttribute(fstack, basedoc, att);
471 if (a != null) {
472 ret.setAttributeNodeNS(a);
473 }
474 }
475 }
476
477 final List<Content> content = element.getContent();
478
479 if (!content.isEmpty()) {
480 fstack.push();
481 try {
482 fstack.setTextMode(textmode);
483 Walker walker = buildWalker(fstack, content, false);
484
485 if (!walker.isAllText() && fstack.getPadBetween() != null) {
486 // we need to newline/indent
487 final org.w3c.dom.Text n = basedoc.createTextNode(
488 fstack.getPadBetween());
489 ret.appendChild(n);
490 }
491
492 printContent(fstack, nstack, basedoc, ret, walker);
493
494 if (!walker.isAllText() && fstack.getPadLast() != null) {
495 // we need to newline/indent
496 final org.w3c.dom.Text n = basedoc.createTextNode(
497 fstack.getPadLast());
498 ret.appendChild(n);
499 }
500
501 } finally {
502 fstack.pop();
503 }
504 }
505
506 return ret;
507
508 } finally {
509 nstack.pop();
510 }
511 }
512
513 /**
514 * This will handle printing of a List of {@link Content}. Uses the Walker
515 * to ensure formatting.
516 *
517 * @param fstack
518 * the FormatStack
519 * @param nstack
520 * the NamespaceStack
521 * @param basedoc
522 * The org.w3c.dom.Document for creating DOM Nodes
523 * @param target
524 * the DOM node this content should be appended to.
525 * @param walker
526 * <code>List</code> of <code>Content</code> to write.
527 */
528 protected void printContent(final FormatStack fstack,
529 final NamespaceStack nstack, final org.w3c.dom.Document basedoc,
530 final org.w3c.dom.Node target, final Walker walker) {
531
532 while (walker.hasNext()) {
533 final Content c = walker.next();
534 org.w3c.dom.Node n = null;
535 if (c == null) {
536 // Formatted Text or CDATA
537 final String text = walker.text();
538 if (walker.isCDATA()) {
539 n = printCDATA(fstack, basedoc, new CDATA(text));
540 } else {
541 n = printText(fstack, basedoc, new Text(text));
542 }
543 } else {
544 n = helperContentDispatcher(fstack, nstack,
545 basedoc, c);
546 }
547 if (n != null) {
548 target.appendChild(n);
549 }
550 }
551
552 }
553
554 /**
555 * This method contains code which is reused in a number of places. It
556 * simply determines what content is passed in, and dispatches it to the
557 * correct print* method.
558 *
559 * @param fstack
560 * The current FormatStack
561 * @param nstack
562 * the NamespaceStack
563 * @param basedoc
564 * The org.w3c.dom.Document for creating DOM Nodes
565 * @param content
566 * The content to dispatch
567 * @return the input JDOM Content converted to a DOM Node.
568 */
569 protected org.w3c.dom.Node helperContentDispatcher(
570 final FormatStack fstack, final NamespaceStack nstack,
571 final org.w3c.dom.Document basedoc, final Content content) {
572 switch (content.getCType()) {
573 case CDATA:
574 return printCDATA(fstack, basedoc, (CDATA) content);
575 case Comment:
576 return printComment(fstack, basedoc, (Comment) content);
577 case Element:
578 return printElement(fstack, nstack, basedoc, (Element) content);
579 case EntityRef:
580 return printEntityRef(fstack, basedoc, (EntityRef) content);
581 case ProcessingInstruction:
582 return printProcessingInstruction(fstack, basedoc,
583 (ProcessingInstruction) content);
584 case Text:
585 return printText(fstack, basedoc, (Text) content);
586 case DocType:
587 return null;
588 default:
589 throw new IllegalStateException("Unexpected Content "
590 + content.getCType());
591 }
592 }
593
594 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in mtsource and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of mtsource code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.Iterator;
57 import java.util.List;
58 import java.util.NoSuchElementException;
59
60 import org.jdom.CDATA;
61 import org.jdom.Content;
62 import org.jdom.internal.ArrayCopy;
63 import org.jdom.output.EscapeStrategy;
64 import org.jdom.output.Format;
65
66 /**
67 * This Walker implementation walks a list of Content in a Formatted form of
68 * some sort.
69 * <p>
70 * The JDOM content can be loosely categorised in to 'Text-like' content
71 * (consisting of Text, CDATA, and EntityRef), and everything else. This
72 * distinction is significant for for this class and it's sub-classes.
73 * <p>
74 * There will be text manipulation, and some (but not necessarily
75 * all) Text-like content will be returned as text() instead of next().
76 * <p>
77 * The trick in this class is that it deals with the regular content, and
78 * delegates the Text-like content to the sub-classes.
79 * <p>
80 * Subclasses are tasked with analysing chunks of Text-like content in the
81 * {@link #analyzeMultiText(MultiText, int, int)} method. The subclasses are
82 * responsible for adding the relevant text content to the suppliedMultiText
83 * instance in such a way as to result in the correct format.
84 * <p>
85 * The Subclass needs to concern itself with only the text portion because this
86 * abstract class will ensure the Text-like content is appropriately indented.
87 *
88 * @author Rolf Lear
89 */
90 public abstract class AbstractFormattedWalker implements Walker {
91
92 /*
93 * We use Text instances to return formatted text to the caller.
94 * We do not need to validate the Text content... it is 'safe' to
95 * not use the default Text class.
96 */
97 private static final CDATA CDATATOKEN = new CDATA("");
98
99 /**
100 * Indicate how text content should be added
101 * @author Rolf Lear
102 *
103 */
104 protected enum Trim {
105 /** Left Trim */
106 LEFT,
107 /** Right Trim */
108 RIGHT,
109 /** Both Trim */
110 BOTH,
111 /** Trim Both and replace all internal whitespace with a single space*/
112 COMPACT,
113 /** No Trimming at all */
114 NONE
115 }
116
117 private static final Iterator<Content> EMPTYIT = new Iterator<Content>() {
118 @Override
119 public boolean hasNext() {
120 return false;
121 }
122
123 @Override
124 public Content next() {
125 throw new NoSuchElementException("Cannot call next() on an empty iterator.");
126 }
127
128 @Override
129 public void remove() {
130 throw new UnsupportedOperationException("Cannot remove from an empty iterator.");
131 }
132 };
133
134 /**
135 * Collect together the items that constitute formatted Text-like content.
136 *
137 * @author Rolf Lear
138 *
139 */
140 protected final class MultiText {
141
142
143 /**
144 * This is private so only this abstract class can create instances.
145 */
146 private MultiText() {
147 }
148
149 /**
150 * Ensure we have space for at least one more text-like item.
151 */
152 private void ensurespace() {
153 if (mtsize >= mtdata.length) {
154 mtdata = ArrayCopy.copyOf(mtdata, mtsize + 1 + (mtsize / 2));
155 mttext = ArrayCopy.copyOf(mttext, mtdata.length);
156 }
157 }
158
159 /**
160 * Handle the case where we have been accumulating true text content,
161 * and the next item is not more text.
162 * @param postspace true if the last char in the text should be a space
163 */
164 private void closeText() {
165 if (mtbuffer.length() == 0) {
166 // empty text does not need adding at all.
167 return;
168 }
169 ensurespace();
170 mtdata[mtsize] = null;
171 mttext[mtsize++] = mtbuffer.toString();
172 mtbuffer.setLength(0);
173 }
174
175 /**
176 * Append some text to the text-like sequence that will be treated as
177 * plain XML text (PCDATA). If the last content added to this text-like
178 * sequence then this new text will be appended directly to the previous
179 * text.
180 *
181 * @param trim How to prepare the Text content
182 * @param text The actual Text content.
183 */
184 public void appendText(final Trim trim, final String text) {
185 final int tlen = text.length();
186 if (tlen == 0) {
187 return;
188 }
189 String toadd = null;
190 switch (trim) {
191 case NONE:
192 toadd = text;
193 break;
194 case BOTH:
195 toadd = Format.trimBoth(text);
196 break;
197 case LEFT:
198 toadd = Format.trimLeft(text);
199 break;
200 case RIGHT:
201 toadd = Format.trimRight(text);
202 break;
203 case COMPACT:
204 toadd = Format.compact(text);
205 break;
206 }
207 if (toadd != null) {
208 toadd = escapeText(toadd);
209 mtbuffer.append(toadd);
210 mtgottext = true;
211 }
212 }
213
214 private String escapeText(final String text) {
215 if (escape == null || !fstack.getEscapeOutput()) {
216 return text;
217 }
218 return Format.escapeText(escape, endofline, text);
219 }
220
221 private String escapeCDATA(final String text) {
222 if (escape == null) {
223 return text;
224 }
225 return text;
226 }
227 /**
228 * Append some text to the text-like sequence that will be treated as
229 * CDATA.
230 * @param trim How to prepare the CDATA content
231 * @param text The actual CDATA content.
232 */
233 public void appendCDATA(final Trim trim, final String text) {
234 // this resets the mtbuffer too.
235 closeText();
236 String toadd = null;
237 switch (trim) {
238 case NONE:
239 toadd = text;
240 break;
241 case BOTH:
242 toadd = Format.trimBoth(text);
243 break;
244 case LEFT:
245 toadd = Format.trimLeft(text);
246 break;
247 case RIGHT:
248 toadd = Format.trimRight(text);
249 break;
250 case COMPACT:
251 toadd = Format.compact(text);
252 break;
253 }
254
255 toadd = escapeCDATA(toadd);
256 ensurespace();
257 // mark this as being CDATA text
258 mtdata[mtsize] = CDATATOKEN;
259 mttext[mtsize++] = toadd;
260
261 mtgottext = true;
262
263 }
264
265 /**
266 * Simple method that ensures the text is processed, regardless of
267 * content, and is never escaped.
268 * @param text
269 */
270 private void forceAppend(final String text) {
271 mtgottext = true;
272 mtbuffer.append(text);
273 }
274
275 /**
276 * Add some JDOM Content (typically an EntityRef) that will be treated
277 * as part of the Text-like sequence.
278 * @param c the content to add.
279 */
280 public void appendRaw(final Content c) {
281 closeText();
282 ensurespace();
283 mttext[mtsize] = null;
284 mtdata[mtsize++] = c;
285 mtbuffer.setLength(0);
286
287 }
288
289 /**
290 * Indicate that there is no further content to be added to the
291 * text-like sequence.
292 */
293 public void done() {
294 if (mtpostpad && newlineindent != null) {
295 // this will be ignored if there was not some content.
296 mtbuffer.append(newlineindent);
297 }
298 if (mtgottext) {
299 closeText();
300 }
301 mtbuffer.setLength(0);
302 }
303
304 }
305
306
307
308
309 private Content pending = null;
310 private final Iterator<? extends Content> content;
311 private final boolean alltext;
312 private final boolean allwhite;
313 private final String newlineindent;
314 private final String endofline;
315 private final EscapeStrategy escape;
316 private final FormatStack fstack;
317 private boolean hasnext = true;
318
319
320 // MultiText handling changed in 2.0.5
321 // MultiText is something quite complicated, but it goes something like this:
322 // XML Content is either text-like, or its not. If we encounter text-like content
323 // then we find out how many text-like contents are in a row, and we add them to a
324 // multi-text. We then either get to the end of the content, or a non-text content.
325 // If we complete the multitext, we then move on to the non-text item, and we set multitext
326 // to null. Both multitect and pendingmt are thus null.
327 // If the content following the non-text is then text-like, we populate pendingmt.
328 // bottom line is that multitext and pendingmt can never both be set.
329 // we use one set of variables to back up both of them. This is fast, and safe in a single
330 // threaded environment (which the Walkers are guaranteed to be in).
331 // all MultiText-specific variables have the names mt*
332 private MultiText multitext = null;
333 private MultiText pendingmt = null;
334 private final MultiText holdingmt = new MultiText();
335
336 private final StringBuilder mtbuffer = new StringBuilder();
337 // if there should be indenting after this text.
338 private boolean mtpostpad;
339 // indicate whether there is something actually added.
340 private boolean mtgottext = false;
341 // the number of mixed content values.
342 private int mtsize = 0;
343 private int mtsourcesize = 0;
344 private Content[] mtsource = new Content[8];
345 // the location of the processed content.
346 private Content[] mtdata = new Content[8];
347 // whether the mixed content should be returned as raw JDOM objects
348 private String[] mttext = new String[8];
349
350 // the current cursor in the mixed content.
351 private int mtpos = -1;
352 // we cheat here by using Boolean as a three-state option...
353 // we expect it to be null often.
354 private Boolean mtwasescape;
355
356 /**
357 * Create a Walker that preserves all content in its raw state.
358 * @param xx the content to walk.
359 * @param fstack the current FormatStack
360 * @param doescape Whether Text values should be escaped.
361 */
362 public AbstractFormattedWalker(final List<? extends Content> xx,
363 final FormatStack fstack, final boolean doescape) {
364 super();
365 this.fstack = fstack;
366 this.content = xx.isEmpty() ? EMPTYIT : xx.iterator();
367 this.escape = doescape ? fstack.getEscapeStrategy() : null;
368 newlineindent = fstack.getPadBetween();
369 endofline = fstack.getLevelEOL();
370 if (!content.hasNext()) {
371 alltext = true;
372 allwhite = true;
373 } else {
374 boolean atext = false;
375 boolean awhite = false;
376 pending = content.next();
377 if (isTextLike(pending)) {
378 // the first item in the list is Text-like, and we pre-check
379 // to see whether all content is text.... and whether it amounts
380 // to something.
381 pendingmt = buildMultiText(true);
382 analyzeMultiText(pendingmt, 0, mtsourcesize);
383 pendingmt.done();
384
385 if (pending == null) {
386 atext = true;
387 awhite = mtsize == 0;
388 }
389 if (mtsize == 0) {
390 // first content in list is ignorable.
391 pendingmt = null;
392 }
393 }
394 alltext = atext;
395 allwhite = awhite;
396 }
397 hasnext = pendingmt != null || pending != null;
398 }
399
400 @Override
401 public final Content next() {
402
403 if (!hasnext) {
404 throw new NoSuchElementException("Cannot walk off end of Content");
405 }
406
407 if (multitext != null && mtpos + 1 >= mtsize) {
408 // finished this multitext. need to move on.
409 multitext = null;
410 resetMultiText();
411 }
412 if (pendingmt != null) {
413 // we have a multi-text pending from the last block
414 // this will only be the case when the previous value was non-text.
415 if (mtwasescape != null &&
416 fstack.getEscapeOutput() != mtwasescape.booleanValue()) {
417 // we calculated pending with one escape strategy, but it changed...
418 // we need to recalculate it....
419
420 mtsize = 0;
421 mtwasescape = fstack.getEscapeOutput();
422 analyzeMultiText(pendingmt, 0, mtsourcesize);
423 pendingmt.done();
424 }
425 multitext = pendingmt;
426 pendingmt = null;
427 }
428
429 if (multitext != null) {
430
431 // OK, we have text-like content to push back.
432 // and it still has values in it.
433 // advance the cursor
434 mtpos++;
435
436 final Content ret = mttext[mtpos] == null
437 ? mtdata[mtpos] : null;
438
439
440 // we can calculate the hasnext
441 hasnext = mtpos + 1 < mtsize ||
442 pending != null;
443
444 // return null to indicate text content.
445 return ret;
446 }
447
448 // non-text, increment and return content.
449 final Content ret = pending;
450 pending = content.hasNext() ? content.next() : null;
451
452 // OK, we are returning some content.
453 // we need to determine the state of the next loop.
454 // cursor at this point has been advanced!
455 if (pending == null) {
456 hasnext = false;
457 } else {
458 // there is some more content.
459 // we need to inspect it to determine whether it is good
460 if (isTextLike(pending)) {
461 // calculate what this next text-like content looks like.
462 pendingmt = buildMultiText(false);
463 analyzeMultiText(pendingmt, 0, mtsourcesize);
464 pendingmt.done();
465
466 if (mtsize > 0) {
467 hasnext = true;
468 } else {
469 // all white text... perhaps we need indenting anyway.
470 // buildMultiText has moved on the pending value....
471 if (pending != null && newlineindent != null) {
472 // yes, we need indenting.
473 // redefine the pending.
474 resetMultiText();
475 pendingmt = holdingmt;
476 pendingmt.forceAppend(newlineindent);
477 pendingmt.done();
478 hasnext = true;
479 } else {
480 pendingmt = null;
481 hasnext = pending != null;
482 }
483 }
484 } else {
485 // it is non-text content... we have more content.
486 // but, we just returned non-text content. We may need to indent
487 if (newlineindent != null) {
488 resetMultiText();
489 pendingmt = holdingmt;
490 pendingmt.forceAppend(newlineindent);
491 pendingmt.done();
492 }
493 hasnext = true;
494 }
495 }
496 return ret;
497 }
498
499 private void resetMultiText() {
500 mtsourcesize = 0;
501 mtpos = -1;
502 mtsize = 0;
503 mtgottext = false;
504 mtpostpad = false;
505 mtwasescape = null;
506 mtbuffer.setLength(0);
507 }
508
509 /**
510 * Add the content at the specified indices to the provided MultiText.
511 * @param mtext the MultiText to append to.
512 * @param offset The first Text-like content to add to the MultiText
513 * @param len The number of Text-like content items to add.
514 */
515 protected abstract void analyzeMultiText(MultiText mtext, int offset, int len);
516
517 /**
518 * Get the content at a position in the input content. Useful for subclasses
519 * in their {@link #analyzeMultiText(MultiText, int, int)} calls.
520 * @param index the index to get the content at.
521 * @return the content at the index.
522 */
523 protected final Content get(final int index) {
524 return mtsource[index];
525 }
526
527 @Override
528 public final boolean isAllText() {
529 return alltext;
530 }
531
532 @Override
533 public final boolean hasNext() {
534 return hasnext;
535 }
536
537 /**
538 * This method was changed in 2.0.5
539 * It now is only called when building the content of the variable pendingmt
540 * This is important, because only pendingmt can be referenced when analyzing
541 * the MultiText content.
542 * @param first
543 * @return The updated MultiText containing the correct sequence of Text-like content
544 */
545 private final MultiText buildMultiText(final boolean first) {
546 // set up a sequence where the next bunch of stuff is text.
547 if (!first && newlineindent != null) {
548 mtbuffer.append(newlineindent);
549 }
550 mtsourcesize = 0;
551 do {
552 if (mtsourcesize >= mtsource.length) {
553 mtsource = ArrayCopy.copyOf(mtsource, mtsource.length * 2);
554 }
555 mtsource[mtsourcesize++] = pending;
556 pending = content.hasNext() ? content.next() : null;
557 } while (pending != null && isTextLike(pending));
558
559 mtpostpad = pending != null;
560 mtwasescape = fstack.getEscapeOutput();
561 return holdingmt;
562 }
563
564 @Override
565 public final String text() {
566 if (multitext == null || mtpos >= mtsize) {
567 return null;
568 }
569 return mttext[mtpos];
570 }
571
572 @Override
573 public final boolean isCDATA() {
574 if (multitext == null || mtpos >= mtsize) {
575 return false;
576 }
577 if (mttext[mtpos] == null) {
578 return false;
579 }
580
581 return mtdata[mtpos] == CDATATOKEN;
582 }
583
584 @Override
585 public final boolean isAllWhitespace() {
586 return allwhite;
587 }
588
589 private final boolean isTextLike(final Content c) {
590 switch (c.getCType()) {
591 case Text:
592 case CDATA:
593 case EntityRef:
594 return true;
595 default:
596 // nothing.
597 }
598 return false;
599 }
600
601
602 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.List;
57
58 import org.jdom.Content;
59
60 /**
61 * Methods common/useful for all Outputter processors.
62 *
63 * @since JDOM2
64 * @author Rolf Lear
65 */
66 public abstract class AbstractOutputProcessor {
67
68 /*
69 * ========================================================================
70 * Support methods for Text-content formatting. Should all be protected. The
71 * following are used when printing Text-based data. Because of complicated
72 * multi-sequential text sometimes the requirements are odd. All Text
73 * content will be output using these methods, which is why there is the None
74 * version.
75 * ========================================================================
76 */
77
78 /**
79 * Create a walker to process Content List values.
80 * <p>
81 * If you require a custom walker to process content in a specific way
82 * then you probably want to override this method to build the walker you
83 * want.
84 *
85 * @param fstack The current FormatStack for the walker (this should not be
86 * modified by the Walker).
87 * @param content The list of content to walk.
88 * @param escape If you want the Text values to be XMLEscaped then supply
89 * a non-null EscapeStrategy to use.
90 * @return the created walker.
91 */
92 protected Walker buildWalker(final FormatStack fstack,
93 final List<? extends Content> content, boolean escape) {
94
95 switch (fstack.getTextMode()) {
96 case PRESERVE:
97 return new WalkerPRESERVE(content);
98 case NORMALIZE:
99 return new WalkerNORMALIZE(content, fstack, escape);
100 case TRIM:
101 return new WalkerTRIM(content, fstack, escape);
102 case TRIM_FULL_WHITE:
103 return new WalkerTRIM_FULL_WHITE(content, fstack, escape);
104 }
105 // all cases should be handled in the switch statement above. If someone
106 // creates a new TextMode though, then it will create a warning in
107 // eclipse above, and the code will fall through to this 'default' raw
108 // instance.
109 return new WalkerPRESERVE(content);
110 }
111
112 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import static org.jdom.JDOMConstants.*;
57
58 import java.io.IOException;
59 import java.io.StringReader;
60 import java.lang.reflect.InvocationTargetException;
61 import java.lang.reflect.Method;
62 import java.util.Collections;
63 import java.util.List;
64
65 import org.xml.sax.ContentHandler;
66 import org.xml.sax.DTDHandler;
67 import org.xml.sax.InputSource;
68 import org.xml.sax.SAXException;
69 import org.xml.sax.SAXParseException;
70 import org.xml.sax.XMLReader;
71 import org.xml.sax.ext.DeclHandler;
72 import org.xml.sax.ext.LexicalHandler;
73 import org.xml.sax.helpers.AttributesImpl;
74 import org.xml.sax.helpers.DefaultHandler;
75 import org.xml.sax.helpers.XMLReaderFactory;
76
77 import org.jdom.Attribute;
78 import org.jdom.AttributeType;
79 import org.jdom.CDATA;
80 import org.jdom.Comment;
81 import org.jdom.Content;
82 import org.jdom.DocType;
83 import org.jdom.Document;
84 import org.jdom.Element;
85 import org.jdom.EntityRef;
86 import org.jdom.JDOMException;
87 import org.jdom.Namespace;
88 import org.jdom.ProcessingInstruction;
89 import org.jdom.Text;
90 import org.jdom.output.Format;
91 import org.jdom.output.Format.TextMode;
92 import org.jdom.output.XMLOutputter2;
93 import org.jdom.util.NamespaceStack;
94
95 /**
96 * Outputs a JDOM document as a stream of SAX2 events.
97 * <p>
98 * Most ContentHandler callbacks are supported. Neither
99 * <code>ignorableWhitespace()</code> nor <code>skippedEntity()</code> have been
100 * implemented.
101 * <p>
102 * At this time, it is not possible to access notations and unparsed entity
103 * references in a DTD from JDOM. Therefore, full <code>DTDHandler</code>
104 * call-backs have not been implemented yet.
105 * <p>
106 * The <code>ErrorHandler</code> call-backs have not been implemented, since
107 * these are supposed to be invoked when the document is parsed and at this
108 * point the document exists in memory and is known to have no errors.
109 * </p>
110 * The SAX2 API does not support whitespace formatting outside the root element.
111 * As a consequence any Formatting options that would normally affect the
112 * structures outside the root element will be ignored.
113 *
114 * @author Brett McLaughlin
115 * @author Jason Hunter
116 * @author Fred Trimble
117 * @author Bradley S. Huffman
118 * @author Rolf Lear
119 */
120 public class AbstractSAXOutputProcessor extends AbstractOutputProcessor
121 implements SAXOutputProcessor {
122
123 private static void locate(SAXTarget out) {
124 out.getContentHandler().setDocumentLocator(out.getLocator());
125 }
126
127 @Override
128 public void process(SAXTarget out, Format format, Document doc)
129 throws JDOMException {
130 try {
131 locate(out);
132 printDocument(out, new FormatStack(format), new NamespaceStack(),
133 doc);
134 } catch (SAXException se) {
135 throw new JDOMException(
136 "Encountered a SAX exception processing the Document: ", se);
137 }
138 }
139
140 @Override
141 public void process(SAXTarget out, Format format, DocType doctype)
142 throws JDOMException {
143 try {
144 locate(out);
145 printDocType(out, new FormatStack(format), doctype);
146 } catch (SAXException se) {
147 throw new JDOMException(
148 "Encountered a SAX exception processing the DocType: ", se);
149 }
150 }
151
152 @Override
153 public void process(SAXTarget out, Format format, Element element)
154 throws JDOMException {
155 try {
156 locate(out);
157 printElement(out, new FormatStack(format), new NamespaceStack(),
158 element);
159 } catch (SAXException se) {
160 throw new JDOMException(
161 "Encountered a SAX exception processing the Element: ", se);
162 }
163 }
164
165 @Override
166 public void process(SAXTarget out, Format format,
167 List<? extends Content> list) throws JDOMException {
168 try {
169 locate(out);
170 final FormatStack fstack = new FormatStack(format);
171 final Walker walker = buildWalker(fstack, list, false);
172 printContent(out, fstack, new NamespaceStack(), walker);
173 } catch (SAXException se) {
174 throw new JDOMException(
175 "Encountered a SAX exception processing the List: ", se);
176 }
177 }
178
179 @Override
180 public void process(SAXTarget out, Format format, CDATA cdata)
181 throws JDOMException {
182 try {
183 locate(out);
184 final List<CDATA> list = Collections.singletonList(cdata);
185 final FormatStack fstack = new FormatStack(format);
186 final Walker walker = buildWalker(fstack, list, false);
187 printContent(out, fstack, new NamespaceStack(), walker);
188 } catch (SAXException se) {
189 throw new JDOMException(
190 "Encountered a SAX exception processing the CDATA: ", se);
191 }
192 }
193
194 @Override
195 public void process(SAXTarget out, Format format, Text text)
196 throws JDOMException {
197 try {
198 locate(out);
199 final List<Text> list = Collections.singletonList(text);
200 final FormatStack fstack = new FormatStack(format);
201 final Walker walker = buildWalker(fstack, list, false);
202 printContent(out, fstack, new NamespaceStack(), walker);
203 } catch (SAXException se) {
204 throw new JDOMException(
205 "Encountered a SAX exception processing the Text: ", se);
206 }
207 }
208
209 @Override
210 public void process(SAXTarget out, Format format, Comment comment)
211 throws JDOMException {
212 try {
213 locate(out);
214 printComment(out, new FormatStack(format), comment);
215 } catch (SAXException se) {
216 throw new JDOMException(
217 "Encountered a SAX exception processing the Comment: ", se);
218 }
219 }
220
221 @Override
222 public void process(SAXTarget out, Format format, ProcessingInstruction pi)
223 throws JDOMException {
224 try {
225 locate(out);
226 printProcessingInstruction(out, new FormatStack(format), pi);
227 } catch (SAXException se) {
228 throw new JDOMException(
229 "Encountered a SAX exception processing the ProcessingInstruction: ",
230 se);
231 }
232 }
233
234 @Override
235 public void process(SAXTarget out, Format format, EntityRef entity)
236 throws JDOMException {
237 try {
238 locate(out);
239 printEntityRef(out, new FormatStack(format), entity);
240 } catch (SAXException se) {
241 throw new JDOMException(
242 "Encountered a SAX exception processing the EntityRef: ",
243 se);
244 }
245 }
246
247 @Override
248 public void processAsDocument(SAXTarget out, Format format,
249 List<? extends Content> nodes) throws JDOMException {
250 try {
251 if ((nodes == null) || (nodes.size() == 0)) {
252 return;
253 }
254
255 locate(out);
256 // contentHandler.setDocumentLocator()
257 out.getContentHandler().startDocument();
258
259 FormatStack fstack = new FormatStack(format);
260
261 // Fire DTD events .. if there is a DocType node
262 if (out.isReportDTDEvents()) {
263 for (Content c : nodes) {
264 if (c instanceof DocType) {
265 printDocType(out, fstack, (DocType)c);
266 // fire only the first DocType's events
267 // subsequent ones are ignored.
268 break;
269 }
270 }
271 }
272
273 Walker walker = buildWalker(fstack, nodes, false);
274
275 printContent(out, fstack, new NamespaceStack(), walker);
276
277 // contentHandler.endDocument()
278 out.getContentHandler().endDocument();
279 } catch (SAXException se) {
280 throw new JDOMException(
281 "Encountered a SAX exception processing the List: ", se);
282 }
283 }
284
285 @Override
286 public void processAsDocument(SAXTarget out, Format format, Element node)
287 throws JDOMException {
288 try {
289 if (node == null) {
290 return;
291 }
292
293 locate(out);
294 // contentHandler.setDocumentLocator()
295 out.getContentHandler().startDocument();
296
297 printElement(out, new FormatStack(format), new NamespaceStack(),
298 node);
299
300 // contentHandler.endDocument()
301 out.getContentHandler().endDocument();
302 } catch (SAXException se) {
303 throw new JDOMException(
304 "Encountered a SAX exception processing the Element: ", se);
305 }
306 }
307
308 /* *******************************************
309 * Support methods for output. Should all be protected. All content-type
310 * print methods have a FormatStack. Only printContent is responsible for
311 * outputting appropriate indenting and newlines, which are easily available
312 * using the FormatStack.getLevelIndent() and FormatStack.getLevelEOL().
313 * *******************************************
314 */
315
316 /**
317 * This will handle printing of a {@link Document}.
318 *
319 * @param out
320 * <code>SAXTarget</code> to use.
321 * @param fstack
322 * the FormatStack
323 * @param nstack
324 * the NamespaceStack
325 * @param document
326 * <code>Document</code> to write.
327 * @throws SAXException
328 * if the destination SAXTarget fails
329 */
330 protected void printDocument(final SAXTarget out, final FormatStack fstack,
331 final NamespaceStack nstack, final Document document)
332 throws SAXException {
333 if (document == null) {
334 return;
335 }
336
337 // contentHandler.startDocument()
338 out.getContentHandler().startDocument();
339
340 // Fire DTD events
341 if (out.isReportDTDEvents()) {
342 printDocType(out, fstack, document.getDocType());
343 }
344
345 // Handle root element, as well as any root level
346 // processing instructions and comments
347 // ignore DocType, if any.
348 final int sz = document.getContentSize();
349
350 if (sz > 0) {
351 for (int i = 0; i < sz; i++) {
352 final Content c = document.getContent(i);
353 out.getLocator().setNode(c);
354 switch (c.getCType()) {
355 case Comment :
356 printComment(out, fstack, (Comment) c);
357 break;
358 case DocType :
359 // cannot simply add a DocType to a SAX stream
360 // it is added when the Stream is created.
361 break;
362 case Element :
363 printElement(out, fstack, nstack, (Element)c);
364 break;
365 case ProcessingInstruction :
366 printProcessingInstruction(out, fstack,
367 (ProcessingInstruction)c);
368 break;
369 default :
370 // do nothing.
371 }
372 }
373 }
374
375 // contentHandler.endDocument()
376 out.getContentHandler().endDocument();
377
378 }
379
380 /**
381 * This will handle printing of a {@link DocType}.
382 *
383 * @param out
384 * <code>SAXTarget</code> to use.
385 * @param fstack
386 * the FormatStack
387 * @param docType
388 * <code>DocType</code> to write.
389 * @throws SAXException
390 * if the destination SAXTarget fails
391 */
392 protected void printDocType(final SAXTarget out, final FormatStack fstack,
393 final DocType docType) throws SAXException {
394
395 // Fire DTD-related events only if handlers have been registered.
396 final DTDHandler dtdHandler = out.getDTDHandler();
397 final DeclHandler declHandler = out.getDeclHandler();
398 if ((docType != null)
399 && ((dtdHandler != null) || (declHandler != null))) {
400
401 // Build a dummy XML document that only references the DTD...
402 String dtdDoc = new XMLOutputter2().outputString(docType);
403
404 try {
405 // And parse it to fire DTD events.
406 createDTDParser(out).parse(
407 new InputSource(new StringReader(dtdDoc)));
408
409 // We should never reach this point as the document is
410 // ill-formed; it does not have any root element.
411 } catch (SAXParseException e) {
412 // Expected exception: There's no root element in document.
413 } catch (IOException e) {
414 throw new SAXException("DTD parsing error", e);
415 }
416 }
417
418 }
419
420 /**
421 * This will handle printing of a {@link ProcessingInstruction}.
422 *
423 * @param out
424 * <code>SAXTarget</code> to use.
425 * @param fstack
426 * the FormatStack
427 * @param pi
428 * <code>ProcessingInstruction</code> to write.
429 * @throws SAXException
430 * if the destination SAXTarget fails
431 */
432 protected void printProcessingInstruction(final SAXTarget out,
433 final FormatStack fstack, final ProcessingInstruction pi)
434 throws SAXException {
435 out.getContentHandler().processingInstruction(pi.getTarget(),
436 pi.getData());
437 }
438
439 /**
440 * This will handle printing of a {@link Comment}.
441 *
442 * @param out
443 * <code>SAXTarget</code> to use.
444 * @param fstack
445 * the FormatStack
446 * @param comment
447 * <code>Comment</code> to write.
448 * @throws SAXException
449 * if the destination SAXTarget fails
450 */
451 protected void printComment(final SAXTarget out, final FormatStack fstack,
452 final Comment comment) throws SAXException {
453 if (out.getLexicalHandler() != null) {
454 char[] c = comment.getText().toCharArray();
455 out.getLexicalHandler().comment(c, 0, c.length);
456 }
457 }
458
459 /**
460 * This will handle printing of an {@link EntityRef}.
461 *
462 * @param out
463 * <code>SAXTarget</code> to use.
464 * @param fstack
465 * the FormatStack
466 * @param entity
467 * <code>EntotyRef</code> to write.
468 * @throws SAXException
469 * if the destination SAXTarget fails
470 */
471 protected void printEntityRef(final SAXTarget out,
472 final FormatStack fstack, final EntityRef entity)
473 throws SAXException {
474 out.getContentHandler().skippedEntity(entity.getName());
475 }
476
477 /**
478 * This will handle printing of a {@link CDATA}.
479 *
480 * @param out
481 * <code>SAXTarget</code> to use.
482 * @param fstack
483 * the FormatStack
484 * @param cdata
485 * <code>CDATA</code> to write.
486 * @throws SAXException
487 * if the destination SAXTarget fails
488 */
489 protected void printCDATA(final SAXTarget out, final FormatStack fstack,
490 final CDATA cdata) throws SAXException {
491 // CDATAs are treated like text, not indented/newline content.
492 final LexicalHandler lexicalHandler = out.getLexicalHandler();
493 final char[] chars = cdata.getText().toCharArray();
494 if (lexicalHandler != null) {
495 lexicalHandler.startCDATA();
496 out.getContentHandler().characters(chars, 0, chars.length);
497 lexicalHandler.endCDATA();
498 } else {
499 out.getContentHandler().characters(chars, 0, chars.length);
500 }
501 }
502
503 /**
504 * This will handle printing of a {@link Text}.
505 *
506 * @param out
507 * <code>SAXTarget</code> to use.
508 * @param fstack
509 * the FormatStack
510 * @param text
511 * <code>Text</code> to write.
512 * @throws SAXException
513 * if the destination SAXTarget fails
514 */
515 protected void printText(final SAXTarget out, final FormatStack fstack,
516 final Text text) throws SAXException {
517 final char[] chars = text.getText().toCharArray();
518 out.getContentHandler().characters(chars, 0, chars.length);
519 }
520
521 /**
522 * This will handle printing of an {@link Element}.
523 * <p>
524 * This method arranges for outputting the Element infrastructure including
525 * Namespace Declarations and Attributes.
526 *
527 * @param out
528 * <code>SAXTarget</code> to use.
529 * @param fstack
530 * the FormatStack
531 * @param nstack
532 * the NamespaceStack
533 * @param element
534 * <code>Element</code> to write.
535 * @throws SAXException
536 * if the destination SAXTarget fails
537 */
538 protected void printElement(final SAXTarget out, final FormatStack fstack,
539 final NamespaceStack nstack, final Element element)
540 throws SAXException {
541
542 final ContentHandler ch = out.getContentHandler();
543 final Object origloc = out.getLocator().getNode();
544 nstack.push(element);
545 try {
546
547 // update locator
548 out.getLocator().setNode(element);
549
550 AttributesImpl atts = new AttributesImpl();
551
552 // contentHandler.startPrefixMapping()
553 for (Namespace ns : nstack.addedForward()) {
554 ch.startPrefixMapping(ns.getPrefix(), ns.getURI());
555 if (out.isDeclareNamespaces()) {
556 // add a physical attribute if requested.
557 String prefix = ns.getPrefix();
558 if (prefix.equals("")) {
559 atts.addAttribute("", "", "xmlns", "CDATA", ns.getURI());
560 } else {
561 atts.addAttribute("", "", "xmlns:" + ns.getPrefix(),
562 "CDATA", ns.getURI());
563 }
564 }
565 }
566
567 // Allocate attribute list.
568 if (element.hasAttributes()) {
569 for (Attribute a : element.getAttributes()) {
570 if (!a.isSpecified() && fstack.isSpecifiedAttributesOnly()) {
571 continue;
572 }
573 atts.addAttribute(a.getNamespaceURI(), a.getName(),
574 a.getQualifiedName(),
575 getAttributeTypeName(a.getAttributeType()),
576 a.getValue());
577 }
578 }
579
580 // contentHandler.startElement()
581 ch.startElement(element.getNamespaceURI(), element.getName(),
582 element.getQualifiedName(), atts);
583
584 final List<Content> content = element.getContent();
585
586 // OK, now we print out the meat of the Element
587 if (!content.isEmpty()) {
588 TextMode textmode = fstack.getTextMode();
589
590 // Check for xml:space and adjust format settings
591 final String space = element.getAttributeValue("space",
592 Namespace.XML_NAMESPACE);
593
594 if ("default".equals(space)) {
595 textmode = fstack.getDefaultMode();
596 } else if ("preserve".equals(space)) {
597 textmode = TextMode.PRESERVE;
598 }
599
600 fstack.push();
601 try {
602 fstack.setTextMode(textmode);
603 Walker walker = buildWalker(fstack, content, false);
604 if (walker.hasNext()) {
605
606 if (!walker.isAllText()
607 && fstack.getPadBetween() != null) {
608 // we need to newline/indent
609 final String indent = fstack.getPadBetween();
610 printText(out, fstack, new Text(indent));
611 }
612
613 printContent(out, fstack, nstack, walker);
614
615 if (!walker.isAllText() &&
616 fstack.getPadLast() != null) {
617 // we need to newline/indent
618 final String indent =
619 fstack.getPadLast();
620 printText(out, fstack, new Text(indent));
621 }
622
623 }
624
625 } finally {
626 fstack.pop();
627 }
628 }
629
630 // contentHandler.endElement()
631 out.getContentHandler().endElement(element.getNamespaceURI(),
632 element.getName(), element.getQualifiedName());
633
634 // contentHandler.endPrefixMapping()
635 // de-map in reverse order to the mapping.
636 for (Namespace ns : nstack.addedReverse()) {
637 ch.endPrefixMapping(ns.getPrefix());
638 }
639
640 } finally {
641 nstack.pop();
642 out.getLocator().setNode(origloc);
643 }
644 }
645
646 /**
647 * This will handle printing of a List of {@link Content}.
648 * <p>
649 * It relies on the appropriate Walker to get the formatting right.
650 *
651 * @param out
652 * <code>SAXTarget</code> to use.
653 * @param fstack
654 * the FormatStack
655 * @param nstack
656 * the NamespaceStack
657 * @param walker
658 * <code>Waker</code> of <code>Content</code> to write.
659 * @throws SAXException
660 * if the destination SAXTarget fails
661 */
662 protected void printContent(final SAXTarget out, final FormatStack fstack,
663 final NamespaceStack nstack, final Walker walker)
664 throws SAXException {
665
666 while (walker.hasNext()) {
667 final Content c = walker.next();
668 if (c == null) {
669 // Formatted Text or CDATA
670 final String text = walker.text();
671 if (walker.isCDATA()) {
672 printCDATA(out, fstack, new CDATA(text));
673 } else {
674 printText(out, fstack, new Text(text));
675 }
676 } else {
677 switch (c.getCType()) {
678 case CDATA:
679 printCDATA(out, fstack, (CDATA)c);
680 break;
681 case Comment:
682 printComment(out, fstack, (Comment)c);
683 break;
684 case DocType:
685 // do nothing.
686 break;
687 case Element :
688 printElement(out, fstack, nstack, (Element)c);
689 break;
690 case EntityRef:
691 printEntityRef(out, fstack, (EntityRef)c);
692 break;
693 case ProcessingInstruction:
694 printProcessingInstruction(out, fstack,
695 (ProcessingInstruction)c);
696 break;
697 case Text:
698 printText(out, fstack, (Text)c);
699 break;
700 }
701 }
702 }
703 }
704
705 /**
706 * <p>
707 * Returns the SAX 2.0 attribute type string from the type of a JDOM
708 * Attribute.
709 * </p>
710 *
711 * @param type
712 * <code>int</code> the type of the JDOM attribute.
713 * @return <code>String</code> the SAX 2.0 attribute type string.
714 * @see org.jdom.Attribute#getAttributeType
715 * @see org.xml.sax.Attributes#getType
716 */
717 private static String getAttributeTypeName(AttributeType type) {
718 switch (type) {
719 case UNDECLARED:
720 return "CDATA";
721 default:
722 return type.name();
723 }
724 }
725
726 /**
727 * <p>
728 * Creates a SAX XMLReader.
729 * </p>
730 *
731 * @return <code>XMLReader</code> a SAX2 parser.
732 * @throws Exception
733 * if no parser can be created.
734 */
735 protected XMLReader createParser() throws Exception {
736 XMLReader parser = null;
737
738 // Try using JAXP...
739 // Note we need JAXP 1.1, and if JAXP 1.0 is all that's
740 // available then the getXMLReader call fails and we skip
741 // to the hard coded default parser
742 try {
743 Class<?> factoryClass = Class
744 .forName("javax.xml.parsers.SAXParserFactory");
745
746 // factory = SAXParserFactory.newInstance();
747 Method newParserInstance = factoryClass.getMethod("newInstance");
748 Object factory = newParserInstance.invoke(null);
749
750 // jaxpParser = factory.newSAXParser();
751 Method newSAXParser = factoryClass.getMethod("newSAXParser");
752 Object jaxpParser = newSAXParser.invoke(factory);
753
754 // parser = jaxpParser.getXMLReader();
755 Class<? extends Object> parserClass = jaxpParser.getClass();
756 Method getXMLReader = parserClass.getMethod("getXMLReader");
757 parser = (XMLReader) getXMLReader.invoke(jaxpParser);
758 } catch (ClassNotFoundException e) {
759 // e.printStackTrace();
760 } catch (InvocationTargetException e) {
761 // e.printStackTrace();
762 } catch (NoSuchMethodException e) {
763 // e.printStackTrace();
764 } catch (IllegalAccessException e) {
765 // e.printStackTrace();
766 }
767
768 // Check to see if we got a parser yet, if not, try to use a
769 // hard coded default
770 if (parser == null) {
771 parser = XMLReaderFactory
772 .createXMLReader("org.apache.xerces.parsers.SAXParser");
773 }
774 return parser;
775 }
776
777 /**
778 * <p>
779 * This will create a SAX XMLReader capable of parsing a DTD and configure
780 * it so that the DTD parsing events are routed to the handlers registered
781 * onto this SAXOutputter.
782 * </p>
783 *
784 * @return <code>XMLReader</code> a SAX2 parser.
785 * @throws JDOMException
786 * if no parser can be created.
787 */
788 private XMLReader createDTDParser(SAXTarget out) throws SAXException {
789 XMLReader parser = null;
790
791 // Get a parser instance
792 try {
793 parser = createParser();
794 } catch (Exception ex1) {
795 throw new SAXException("Error in SAX parser allocation", ex1);
796 }
797
798 // Register handlers
799 if (out.getDTDHandler() != null) {
800 parser.setDTDHandler(out.getDTDHandler());
801 }
802 if (out.getEntityResolver() != null) {
803 parser.setEntityResolver(out.getEntityResolver());
804 }
805 if (out.getLexicalHandler() != null) {
806 try {
807 parser.setProperty(SAX_PROPERTY_LEXICAL_HANDLER,
808 out.getLexicalHandler());
809 } catch (SAXException ex1) {
810 try {
811 parser.setProperty(SAX_PROPERTY_LEXICAL_HANDLER_ALT,
812 out.getLexicalHandler());
813 } catch (SAXException ex2) {
814 // Forget it!
815 }
816 }
817 }
818 if (out.getDeclHandler() != null) {
819 try {
820 parser.setProperty(SAX_PROPERTY_DECLARATION_HANDLER,
821 out.getDeclHandler());
822 } catch (SAXException ex1) {
823 try {
824 parser.setProperty(SAX_PROPERTY_DECLARATION_HANDLER_ALT,
825 out.getDeclHandler());
826 } catch (SAXException ex2) {
827 // Forget it!
828 }
829 }
830 }
831
832 // Absorb errors as much as possible, per Laurent
833 parser.setErrorHandler(new DefaultHandler());
834
835 return parser;
836 }
837
838 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.io.StringWriter;
57 import java.util.ArrayList;
58 import java.util.Collections;
59 import java.util.Iterator;
60 import java.util.List;
61
62 import javax.xml.stream.XMLEventFactory;
63 import javax.xml.stream.XMLStreamException;
64 import javax.xml.stream.util.XMLEventConsumer;
65
66 import org.jdom.Attribute;
67 import org.jdom.CDATA;
68 import org.jdom.Comment;
69 import org.jdom.Content;
70 import org.jdom.Content.CType;
71 import org.jdom.DocType;
72 import org.jdom.Document;
73 import org.jdom.Element;
74 import org.jdom.EntityRef;
75 import org.jdom.Namespace;
76 import org.jdom.ProcessingInstruction;
77 import org.jdom.Text;
78 import org.jdom.Verifier;
79 import org.jdom.output.Format;
80 import org.jdom.output.Format.TextMode;
81 import org.jdom.output.StAXEventOutputter;
82 import org.jdom.util.NamespaceStack;
83
84 /**
85 * This class provides a concrete implementation of {@link StAXEventProcessor}
86 * for supporting the {@link StAXEventOutputter}.
87 * <p>
88 * <h2>Overview</h2>
89 * <p>
90 * This class is marked abstract even though all methods are fully implemented.
91 * The <code>process*(...)</code> methods are public because they match the
92 * StAXEventProcessor interface but the remaining methods are all protected.
93 * <p>
94 * People who want to create a custom StAXEventProcessor for StAXEventOutputter are
95 * able to extend this class and modify any functionality they want. Before
96 * sub-classing this you should first check to see if the {@link Format} class
97 * can get you the results you want.
98 * <p>
99 * <b><i>Subclasses of this should have reentrant methods.</i></b> This is
100 * easiest to accomplish simply by not allowing any instance fields. If your
101 * sub-class has an instance field/variable, then it's probably broken.
102 * <p>
103 * <h2>The Stacks</h2>
104 * <p>
105 * One significant feature of this implementation is that it creates and
106 * maintains both a {@link NamespaceStack} and {@link FormatStack} that are
107 * managed in the
108 * {@link #printElement(XMLEventConsumer, FormatStack, NamespaceStack, XMLEventFactory, Element)} method.
109 * The stacks are pushed and popped in that method only. They significantly
110 * improve the performance and readability of the code.
111 * <p>
112 * The NamespaceStack is only sent through to the
113 * {@link #printElement(XMLEventConsumer, FormatStack, NamespaceStack, XMLEventFactory, Element)} and
114 * {@link #printContent(XMLEventConsumer, FormatStack, NamespaceStack, XMLEventFactory, Walker)} methods, but
115 * the FormatStack is pushed through to all print* Methods.
116 *
117 * @see StAXEventOutputter
118 * @see StAXEventProcessor
119 * @since JDOM2
120 * @author Rolf Lear
121 */
122 public abstract class AbstractStAXEventProcessor extends AbstractOutputProcessor
123 implements StAXEventProcessor {
124
125 private static final class NSIterator implements Iterator<javax.xml.stream.events.Namespace> {
126 private final Iterator<Namespace> source;
127 private final XMLEventFactory fac;
128
129 public NSIterator(Iterator<Namespace> source, XMLEventFactory fac) {
130 super();
131 this.source = source;
132 this.fac = fac;
133 }
134
135 @Override
136 public boolean hasNext() {
137 return source.hasNext();
138 }
139
140 @Override
141 public javax.xml.stream.events.Namespace next() {
142 Namespace ns = source.next();
143 return fac.createNamespace(ns.getPrefix(), ns.getURI());
144 }
145
146 @Override
147 public void remove() {
148 throw new UnsupportedOperationException("Cannot remove Namespaces");
149
150 }
151
152 }
153 private static final class AttIterator implements Iterator<javax.xml.stream.events.Attribute> {
154 private final Iterator<Attribute> source;
155 private final XMLEventFactory fac;
156
157 public AttIterator(final Iterator<Attribute> source, final XMLEventFactory fac,
158 final boolean specifiedAttributesOnly) {
159 super();
160 // remove not-specified Attributes if needed....
161 this.source = specifiedAttributesOnly ? specified(source) : source;
162 this.fac = fac;
163 }
164
165 private Iterator<Attribute> specified(Iterator<Attribute> src) {
166 if (src == null) {
167 return null;
168 }
169 final ArrayList<Attribute> al = new ArrayList<Attribute>();
170 while (src.hasNext()) {
171 Attribute att = src.next();
172 if (att.isSpecified()) {
173 al.add(att);
174 }
175 }
176 return al.isEmpty() ? null : al.iterator();
177 }
178
179 @Override
180 public boolean hasNext() {
181 return source != null && source.hasNext();
182 }
183
184 @Override
185 public javax.xml.stream.events.Attribute next() {
186 final Attribute att = source.next();
187 final Namespace ns = att.getNamespace();
188 if (ns == Namespace.NO_NAMESPACE) {
189 return fac.createAttribute(att.getName(), att.getValue());
190 }
191 return fac.createAttribute(ns.getPrefix(), ns.getURI(),
192 att.getName(), att.getValue());
193 }
194
195 @Override
196 public void remove() {
197 throw new UnsupportedOperationException("Cannot remove attributes");
198
199 }
200
201 }
202
203
204
205 /* *******************************************
206 * StAXEventProcessor implementation.
207 * *******************************************
208 */
209
210 /*
211 * (non-Javadoc)
212 *
213 * @see org.jdom.output.StAXEventProcessor#process(java.io.XMLEventConsumer,
214 * org.jdom.Document, org.jdom.output.Format)
215 */
216 @Override
217 public void process(final XMLEventConsumer out, final Format format,
218 final XMLEventFactory eventfactory, final Document doc) throws XMLStreamException {
219 printDocument(out, new FormatStack(format), new NamespaceStack(), eventfactory, doc);
220 }
221
222 /*
223 * (non-Javadoc)
224 *
225 * @see org.jdom.output.StAXEventProcessor#process(java.io.XMLEventConsumer,
226 * org.jdom.DocType, org.jdom.output.Format)
227 */
228 @Override
229 public void process(final XMLEventConsumer out, final Format format,
230 final XMLEventFactory eventfactory, final DocType doctype) throws XMLStreamException {
231 printDocType(out, new FormatStack(format), eventfactory, doctype);
232 }
233
234 /*
235 * (non-Javadoc)
236 *
237 * @see org.jdom.output.StAXEventProcessor#process(java.io.XMLEventConsumer,
238 * org.jdom.Element, org.jdom.output.Format)
239 */
240 @Override
241 public void process(final XMLEventConsumer out, final Format format,
242 final XMLEventFactory eventfactory, final Element element) throws XMLStreamException {
243 // If this is the root element we could pre-initialize the
244 // namespace stack with the namespaces
245 printElement(out, new FormatStack(format), new NamespaceStack(),
246 eventfactory, element);
247 }
248
249 /*
250 * (non-Javadoc)
251 *
252 * @see org.jdom.output.StAXEventProcessor#process(java.io.XMLEventConsumer,
253 * java.util.List, org.jdom.output.Format)
254 */
255 @Override
256 public void process(final XMLEventConsumer out, final Format format,
257 final XMLEventFactory eventfactory, final List<? extends Content> list)
258 throws XMLStreamException {
259 final FormatStack fstack = new FormatStack(format);
260 final Walker walker = buildWalker(fstack, list, false);
261 printContent(out, new FormatStack(format), new NamespaceStack(), eventfactory, walker);
262 }
263
264 /*
265 * (non-Javadoc)
266 *
267 * @see org.jdom.output.StAXEventProcessor#process(java.io.XMLEventConsumer,
268 * org.jdom.CDATA, org.jdom.output.Format)
269 */
270 @Override
271 public void process(final XMLEventConsumer out, final Format format,
272 final XMLEventFactory eventfactory, final CDATA cdata) throws XMLStreamException {
273 final List<CDATA> list = Collections.singletonList(cdata);
274 final FormatStack fstack = new FormatStack(format);
275 final Walker walker = buildWalker(fstack, list, false);
276 if (walker.hasNext()) {
277 final Content c = walker.next();
278 if (c == null) {
279 printCDATA(out, fstack, eventfactory, new CDATA(walker.text()));
280 } else if (c.getCType() == CType.CDATA) {
281 printCDATA(out, fstack, eventfactory, (CDATA)c);
282 }
283 }
284 }
285
286 /*
287 * (non-Javadoc)
288 *
289 * @see org.jdom.output.StAXEventProcessor#process(java.io.XMLEventConsumer,
290 * org.jdom.Text, org.jdom.output.Format)
291 */
292 @Override
293 public void process(final XMLEventConsumer out, final Format format,
294 final XMLEventFactory eventfactory, final Text text) throws XMLStreamException {
295 final List<Text> list = Collections.singletonList(text);
296 final FormatStack fstack = new FormatStack(format);
297 final Walker walker = buildWalker(fstack, list, false);
298 if (walker.hasNext()) {
299 final Content c = walker.next();
300 if (c == null) {
301 printText(out, fstack, eventfactory, new Text(walker.text()));
302 } else if (c.getCType() == CType.Text) {
303 printText(out, fstack, eventfactory, (Text)c);
304 }
305 }
306 }
307
308 /*
309 * (non-Javadoc)
310 *
311 * @see org.jdom.output.StAXEventProcessor#process(java.io.XMLEventConsumer,
312 * org.jdom.Comment, org.jdom.output.Format)
313 */
314 @Override
315 public void process(final XMLEventConsumer out, final Format format,
316 final XMLEventFactory eventfactory, final Comment comment) throws XMLStreamException {
317 printComment(out, new FormatStack(format), eventfactory, comment);
318 }
319
320 /*
321 * (non-Javadoc)
322 *
323 * @see org.jdom.output.StAXEventProcessor#process(java.io.XMLEventConsumer,
324 * org.jdom.ProcessingInstruction, org.jdom.output.Format)
325 */
326 @Override
327 public void process(final XMLEventConsumer out, final Format format,
328 final XMLEventFactory eventfactory, final ProcessingInstruction pi) throws XMLStreamException {
329 FormatStack fstack = new FormatStack(format);
330 // Output PI verbatim, disregarding TrAX escaping PIs.
331 fstack.setIgnoreTrAXEscapingPIs(true);
332 printProcessingInstruction(out, fstack, eventfactory, pi);
333 }
334
335 /*
336 * (non-Javadoc)
337 *
338 * @see org.jdom.output.StAXEventProcessor#process(java.io.XMLEventConsumer,
339 * org.jdom.EntityRef, org.jdom.output.Format)
340 */
341 @Override
342 public void process(final XMLEventConsumer out, final Format format,
343 final XMLEventFactory eventfactory, final EntityRef entity) throws XMLStreamException {
344 printEntityRef(out, new FormatStack(format), eventfactory, entity);
345 }
346
347 /* *******************************************
348 * Support methods for output. Should all be protected. All content-type
349 * print methods have a FormatStack. Only printContent is responsible for
350 * outputting appropriate indenting and newlines, which are easily available
351 * using the FormatStack.getLevelIndent() and FormatStack.getLevelEOL().
352 * *******************************************
353 */
354
355 /**
356 * This will handle printing of a {@link Document}.
357 *
358 * @param out
359 * <code>XMLEventConsumer</code> to use.
360 * @param fstack
361 * the FormatStack
362 * @param nstack
363 * the NamespaceStack
364 * @param eventfactory
365 * The XMLEventFactory for creating XMLEvents
366 * @param doc
367 * <code>Document</code> to write.
368 * @throws XMLStreamException
369 * if the destination XMLEventConsumer fails
370 */
371 protected void printDocument(final XMLEventConsumer out, final FormatStack fstack,
372 final NamespaceStack nstack, final XMLEventFactory eventfactory, final Document doc) throws XMLStreamException {
373
374 if (fstack.isOmitDeclaration()) {
375 // this actually writes the declaration as version 1, UTF-8
376 out.add(eventfactory.createStartDocument(null, null));
377 } else if (fstack.isOmitEncoding()) {
378 out.add(eventfactory.createStartDocument(null, "1.0"));
379 if (fstack.getLineSeparator() != null) {
380 out.add(eventfactory.createCharacters(fstack.getLineSeparator()));
381 }
382 } else {
383 out.add(eventfactory.createStartDocument(fstack.getEncoding(), "1.0"));
384 if (fstack.getLineSeparator() != null) {
385 out.add(eventfactory.createCharacters(fstack.getLineSeparator()));
386 }
387 }
388
389 // If there is no root element then we cannot use the normal ways to
390 // access the ContentList because Document throws an exception.
391 // so we hack it and just access it by index.
392 List<Content> list = doc.hasRootElement() ? doc.getContent() :
393 new ArrayList<Content>(doc.getContentSize());
394 if (list.isEmpty()) {
395 final int sz = doc.getContentSize();
396 for (int i = 0; i < sz; i++) {
397 list.add(doc.getContent(i));
398 }
399 }
400
401 Walker walker = buildWalker(fstack, list, false);
402 if (walker.hasNext()) {
403 while (walker.hasNext()) {
404
405 final Content c = walker.next();
406
407 // we do not ignore Text-like things in the Document.
408 // the walker creates the indenting for us.
409 if (c == null) {
410 // but, what we do is ensure it is all whitespace, and not CDATA
411 final String padding = walker.text();
412 if (padding != null && Verifier.isAllXMLWhitespace(padding) &&
413 !walker.isCDATA()) {
414 // we do not use the escaping or text* method because this
415 // content is outside of the root element, and thus is not
416 // strict text.
417 out.add(eventfactory.createCharacters(padding));
418 }
419 } else {
420 switch (c.getCType()) {
421 case Comment :
422 printComment(out, fstack, eventfactory, (Comment) c);
423 break;
424 case DocType :
425 printDocType(out, fstack, eventfactory, (DocType)c);
426 break;
427 case Element :
428 printElement(out, fstack, nstack, eventfactory,
429 (Element)c);
430 break;
431 case ProcessingInstruction :
432 printProcessingInstruction(out, fstack, eventfactory,
433 (ProcessingInstruction)c);
434 break;
435 default :
436 // do nothing.
437 }
438 }
439
440 }
441
442 if (fstack.getLineSeparator() != null) {
443 out.add(eventfactory.createCharacters(fstack.getLineSeparator()));
444 }
445 }
446
447 out.add(eventfactory.createEndDocument());
448
449 }
450
451 /**
452 * This will handle printing of a {@link DocType}.
453 *
454 * @param out
455 * <code>XMLEventConsumer</code> to use.
456 * @param fstack
457 * the FormatStack
458 * @param eventfactory
459 * The XMLEventFactory for creating XMLEvents
460 * @param docType
461 * <code>DocType</code> to write.
462 * @throws XMLStreamException
463 * if the destination XMLEventConsumer fails
464 */
465 protected void printDocType(final XMLEventConsumer out, final FormatStack fstack,
466 final XMLEventFactory eventfactory, final DocType docType) throws XMLStreamException {
467
468 final String publicID = docType.getPublicID();
469 final String systemID = docType.getSystemID();
470 final String internalSubset = docType.getInternalSubset();
471 boolean hasPublic = false;
472
473 // Declaration is never indented.
474 // write(out, fstack.getLevelIndent());
475
476 StringWriter sw = new StringWriter();
477
478 sw.write("<!DOCTYPE ");
479 sw.write(docType.getElementName());
480 if (publicID != null) {
481 sw.write(" PUBLIC \"");
482 sw.write(publicID);
483 sw.write("\"");
484 hasPublic = true;
485 }
486 if (systemID != null) {
487 if (!hasPublic) {
488 sw.write(" SYSTEM");
489 }
490 sw.write(" \"");
491 sw.write(systemID);
492 sw.write("\"");
493 }
494 if ((internalSubset != null) && (!internalSubset.equals(""))) {
495 sw.write(" [");
496 sw.write(fstack.getLineSeparator());
497 sw.write(docType.getInternalSubset());
498 sw.write("]");
499 }
500 sw.write(">");
501
502 // DocType does not write it's own EOL
503 // for compatibility reasons. Only
504 // when output from inside a Content set.
505 // write(out, fstack.getLineSeparator());
506 out.add(eventfactory.createDTD(sw.toString()));
507 }
508
509 /**
510 * This will handle printing of a {@link ProcessingInstruction}.
511 *
512 * @param out
513 * <code>XMLEventConsumer</code> to use.
514 * @param fstack
515 * the FormatStack
516 * @param eventfactory
517 * The XMLEventFactory for creating XMLEvents
518 * @param pi
519 * <code>ProcessingInstruction</code> to write.
520 * @throws XMLStreamException
521 * if the destination XMLEventConsumer fails
522 */
523 protected void printProcessingInstruction(final XMLEventConsumer out,
524 final FormatStack fstack, final XMLEventFactory eventfactory, final ProcessingInstruction pi)
525 throws XMLStreamException {
526 String target = pi.getTarget();
527 String rawData = pi.getData();
528 if (rawData != null && rawData.trim().length() > 0) {
529 out.add(eventfactory.createProcessingInstruction(target, rawData));
530 } else {
531 out.add(eventfactory.createProcessingInstruction(target, ""));
532 }
533 }
534
535 /**
536 * This will handle printing of a {@link Comment}.
537 *
538 * @param out
539 * <code>XMLEventConsumer</code> to use.
540 * @param fstack
541 * the FormatStack
542 * @param eventfactory
543 * The XMLEventFactory for creating XMLEvents
544 * @param comment
545 * <code>Comment</code> to write.
546 * @throws XMLStreamException
547 * if the destination XMLEventConsumer fails
548 */
549 protected void printComment(final XMLEventConsumer out, final FormatStack fstack,
550 final XMLEventFactory eventfactory, final Comment comment) throws XMLStreamException {
551 out.add(eventfactory.createComment(comment.getText()));
552 }
553
554 /**
555 * This will handle printing of an {@link EntityRef}.
556 *
557 * @param out
558 * <code>XMLEventConsumer</code> to use.
559 * @param fstack
560 * the FormatStack
561 * @param eventfactory
562 * The XMLEventFactory for creating XMLEvents
563 * @param entity
564 * <code>EntotyRef</code> to write.
565 * @throws XMLStreamException
566 * if the destination XMLEventConsumer fails
567 */
568 protected void printEntityRef(final XMLEventConsumer out, final FormatStack fstack,
569 final XMLEventFactory eventfactory, final EntityRef entity) throws XMLStreamException {
570 out.add(eventfactory.createEntityReference(entity.getName(), null));
571 }
572
573 /**
574 * This will handle printing of a {@link CDATA}.
575 *
576 * @param out
577 * <code>XMLEventConsumer</code> to use.
578 * @param fstack
579 * the FormatStack
580 * @param eventfactory
581 * The XMLEventFactory for creating XMLEvents
582 * @param cdata
583 * <code>CDATA</code> to write.
584 * @throws XMLStreamException
585 * if the destination XMLEventConsumer fails
586 */
587 protected void printCDATA(final XMLEventConsumer out, final FormatStack fstack,
588 final XMLEventFactory eventfactory, final CDATA cdata) throws XMLStreamException {
589 // CDATAs are treated like text, not indented/newline content.
590 out.add(eventfactory.createCData(cdata.getText()));
591 }
592
593 /**
594 * This will handle printing of a {@link Text}.
595 *
596 * @param out
597 * <code>XMLEventConsumer</code> to use.
598 * @param fstack
599 * the FormatStack
600 * @param eventfactory
601 * The XMLEventFactory for creating XMLEvents
602 * @param text
603 * <code>Text</code> to write.
604 * @throws XMLStreamException
605 * if the destination XMLEventConsumer fails
606 */
607 protected void printText(final XMLEventConsumer out, final FormatStack fstack,
608 final XMLEventFactory eventfactory, final Text text) throws XMLStreamException {
609 out.add(eventfactory.createCharacters(text.getText()));
610 }
611
612 /**
613 * This will handle printing of an {@link Element}.
614 * <p>
615 * This method arranges for outputting the Element infrastructure including
616 * Namespace Declarations and Attributes.
617 * <p>
618 *
619 * @param out
620 * <code>XMLEventConsumer</code> to use.
621 * @param fstack
622 * the FormatStack
623 * @param nstack
624 * the NamespaceStack
625 * @param eventfactory
626 * The XMLEventFactory for creating XMLEvents
627 * @param element
628 * <code>Element</code> to write.
629 * @throws XMLStreamException
630 * if the destination XMLEventConsumer fails
631 */
632 protected void printElement(final XMLEventConsumer out, final FormatStack fstack,
633 final NamespaceStack nstack, final XMLEventFactory eventfactory,
634 final Element element) throws XMLStreamException {
635
636 nstack.push(element);
637 try {
638
639 Namespace ns = element.getNamespace();
640 Iterator<Attribute> ait = element.hasAttributes() ?
641 element.getAttributes().iterator() :
642 null;
643 if (ns == Namespace.NO_NAMESPACE) {
644 out.add(eventfactory.createStartElement("", "", element.getName(),
645 new AttIterator(ait, eventfactory, fstack.isSpecifiedAttributesOnly()),
646 new NSIterator(nstack.addedForward().iterator(), eventfactory)));
647 } else if ("".equals(ns.getPrefix())) {
648 out.add(eventfactory.createStartElement("", ns.getURI(), element.getName(),
649 new AttIterator(ait, eventfactory, fstack.isSpecifiedAttributesOnly()),
650 new NSIterator(nstack.addedForward().iterator(), eventfactory)));
651 } else {
652 out.add(eventfactory.createStartElement(ns.getPrefix(), ns.getURI(), element.getName(),
653 new AttIterator(ait, eventfactory, fstack.isSpecifiedAttributesOnly()),
654 new NSIterator(nstack.addedForward().iterator(), eventfactory)));
655 }
656 ait = null;
657
658 final List<Content> content = element.getContent();
659
660 if (!content.isEmpty()) {
661 TextMode textmode = fstack.getTextMode();
662
663 // Check for xml:space and adjust format settings
664 final String space = element.getAttributeValue("space",
665 Namespace.XML_NAMESPACE);
666
667 if ("default".equals(space)) {
668 textmode = fstack.getDefaultMode();
669 }
670 else if ("preserve".equals(space)) {
671 textmode = TextMode.PRESERVE;
672 }
673
674 fstack.push();
675 try {
676
677 fstack.setTextMode(textmode);
678
679 final Walker walker = buildWalker(fstack, content, false);
680 if (walker.hasNext()) {
681 if (!walker.isAllText() && fstack.getPadBetween() != null) {
682 // we need to newline/indent
683 final String indent = fstack.getPadBetween();
684 printText(out, fstack, eventfactory, new Text(indent));
685 }
686
687 printContent(out, fstack, nstack, eventfactory, walker);
688
689 if (!walker.isAllText() && fstack.getPadLast() != null) {
690 // we need to newline/indent
691 final String indent = fstack.getPadLast();
692 printText(out, fstack, eventfactory, new Text(indent));
693 }
694 }
695 } finally {
696 fstack.pop();
697 }
698
699 }
700
701 out.add(eventfactory.createEndElement(element.getNamespacePrefix(),
702 element.getNamespaceURI(), element.getName(),
703 new NSIterator(nstack.addedReverse().iterator(), eventfactory)));
704
705
706 } finally {
707 nstack.pop();
708 }
709 }
710
711 /**
712 * This will handle printing of a List of {@link Content}.
713 * <p>
714 *
715 * @param out
716 * <code>XMLEventConsumer</code> to use.
717 * @param fstack
718 * the FormatStack
719 * @param nstack
720 * the NamespaceStack
721 * @param eventfactory
722 * The XMLEventFactory for creating XMLEvents
723 * @param walker
724 * <code>Walker</code> of <code>Content</code> to write.
725 * @throws XMLStreamException
726 * if the destination XMLEventConsumer fails
727 */
728 protected void printContent(final XMLEventConsumer out,
729 final FormatStack fstack, final NamespaceStack nstack,
730 final XMLEventFactory eventfactory, final Walker walker)
731 throws XMLStreamException {
732
733 while (walker.hasNext()) {
734
735 final Content content = walker.next();
736
737 if (content == null) {
738 if (walker.isCDATA()) {
739 printCDATA(out, fstack, eventfactory, new CDATA(walker.text()));
740 } else {
741 printText(out, fstack, eventfactory, new Text(walker.text()));
742 }
743 } else {
744 switch (content.getCType()) {
745 case CDATA:
746 printCDATA(out, fstack, eventfactory, (CDATA) content);
747 break;
748 case Comment:
749 printComment(out, fstack, eventfactory, (Comment) content);
750 break;
751 case Element:
752 printElement(out, fstack, nstack, eventfactory, (Element) content);
753 break;
754 case EntityRef:
755 printEntityRef(out, fstack, eventfactory, (EntityRef) content);
756 break;
757 case ProcessingInstruction:
758 printProcessingInstruction(out, fstack, eventfactory,
759 (ProcessingInstruction) content);
760 break;
761 case Text:
762 printText(out, fstack, eventfactory, (Text) content);
763 break;
764 case DocType:
765 printDocType(out, fstack, eventfactory, (DocType) content);
766 break;
767 default:
768 throw new IllegalStateException(
769 "Unexpected Content " + content.getCType());
770
771 }
772 }
773 }
774 }
775 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.io.StringWriter;
57 import java.util.ArrayList;
58 import java.util.Collections;
59 import java.util.List;
60
61 import javax.xml.stream.XMLStreamException;
62 import javax.xml.stream.XMLStreamWriter;
63
64 import org.jdom.Attribute;
65 import org.jdom.CDATA;
66 import org.jdom.Comment;
67 import org.jdom.Content;
68 import org.jdom.JDOMConstants;
69 import org.jdom.Content.CType;
70 import org.jdom.DocType;
71 import org.jdom.Document;
72 import org.jdom.Element;
73 import org.jdom.EntityRef;
74 import org.jdom.Namespace;
75 import org.jdom.ProcessingInstruction;
76 import org.jdom.Text;
77 import org.jdom.Verifier;
78 import org.jdom.output.Format;
79 import org.jdom.output.Format.TextMode;
80 import org.jdom.output.StAXStreamOutputter;
81 import org.jdom.util.NamespaceStack;
82
83 /**
84 * This class provides a concrete implementation of {@link StAXStreamProcessor}
85 * for supporting the {@link StAXStreamOutputter}.
86 * <p>
87 * <h2>Overview</h2>
88 * <p>
89 * This class is marked abstract even though all methods are fully implemented.
90 * The <code>process*(...)</code> methods are public because they match the
91 * StAXStreamProcessor interface but the remaining methods are all protected.
92 * <p>
93 * People who want to create a custom StAXStreamProcessor for StAXStreamOutputter are
94 * able to extend this class and modify any functionality they want. Before
95 * sub-classing this you should first check to see if the {@link Format} class
96 * can get you the results you want.
97 * <p>
98 * <b><i>Subclasses of this should have reentrant methods.</i></b> This is
99 * easiest to accomplish simply by not allowing any instance fields. If your
100 * sub-class has an instance field/variable, then it's probably broken.
101 * <p>
102 * <h2>The Stacks</h2>
103 * <p>
104 * One significant feature of this implementation is that it creates and
105 * maintains both a {@link NamespaceStack} and {@link FormatStack} that are
106 * managed in the
107 * {@link #printElement(XMLStreamWriter, FormatStack, NamespaceStack, Element)} method.
108 * The stacks are pushed and popped in that method only. They significantly
109 * improve the performance and readability of the code.
110 * <p>
111 * The NamespaceStack is only sent through to the
112 * {@link #printElement(XMLStreamWriter, FormatStack, NamespaceStack, Element)} and
113 * {@link #printContent(XMLStreamWriter, FormatStack, NamespaceStack, Walker)} methods, but
114 * the FormatStack is pushed through to all print* Methods.
115 * <p>
116 *
117 * @see StAXStreamOutputter
118 * @see StAXStreamProcessor
119 * @since JDOM2
120 * @author Rolf Lear
121 */
122 public abstract class AbstractStAXStreamProcessor
123 extends AbstractOutputProcessor implements StAXStreamProcessor {
124
125
126 /* *******************************************
127 * StAXStreamProcessor implementation.
128 * *******************************************
129 */
130
131 /*
132 * (non-Javadoc)
133 *
134 * @see org.jdom.output.StAXStreamProcessor#process(java.io.XMLStreamWriter,
135 * org.jdom.Document, org.jdom.output.Format)
136 */
137 @Override
138 public void process(final XMLStreamWriter out, final Format format,
139 final Document doc) throws XMLStreamException {
140 printDocument(out, new FormatStack(format), new NamespaceStack(), doc);
141 out.flush();
142 }
143
144 /*
145 * (non-Javadoc)
146 *
147 * @see org.jdom.output.StAXStreamProcessor#process(java.io.XMLStreamWriter,
148 * org.jdom.DocType, org.jdom.output.Format)
149 */
150 @Override
151 public void process(final XMLStreamWriter out, final Format format,
152 final DocType doctype) throws XMLStreamException {
153 printDocType(out, new FormatStack(format), doctype);
154 out.flush();
155 }
156
157 /*
158 * (non-Javadoc)
159 *
160 * @see org.jdom.output.StAXStreamProcessor#process(java.io.XMLStreamWriter,
161 * org.jdom.Element, org.jdom.output.Format)
162 */
163 @Override
164 public void process(final XMLStreamWriter out, final Format format,
165 final Element element) throws XMLStreamException {
166 // If this is the root element we could pre-initialize the
167 // namespace stack with the namespaces
168 printElement(out, new FormatStack(format), new NamespaceStack(),
169 element);
170 out.flush();
171 }
172
173 /*
174 * (non-Javadoc)
175 *
176 * @see org.jdom.output.StAXStreamProcessor#process(java.io.XMLStreamWriter,
177 * java.util.List, org.jdom.output.Format)
178 */
179 @Override
180 public void process(final XMLStreamWriter out, final Format format,
181 final List<? extends Content> list)
182 throws XMLStreamException {
183 final FormatStack fstack = new FormatStack(format);
184 final Walker walker = buildWalker(fstack, list, false);
185 printContent(out, fstack, new NamespaceStack(), walker);
186 out.flush();
187 }
188
189 /*
190 * (non-Javadoc)
191 *
192 * @see org.jdom.output.StAXStreamProcessor#process(java.io.XMLStreamWriter,
193 * org.jdom.CDATA, org.jdom.output.Format)
194 */
195 @Override
196 public void process(final XMLStreamWriter out, final Format format,
197 final CDATA cdata) throws XMLStreamException {
198 final List<CDATA> list = Collections.singletonList(cdata);
199 final FormatStack fstack = new FormatStack(format);
200 final Walker walker = buildWalker(fstack, list, false);
201 if (walker.hasNext()) {
202 final Content c = walker.next();
203 if (c == null) {
204 printCDATA(out, fstack, new CDATA(walker.text()));
205 } else if (c.getCType() == CType.CDATA) {
206 printCDATA(out, fstack, (CDATA)c);
207 }
208 }
209 out.flush();
210 }
211
212 /*
213 * (non-Javadoc)
214 *
215 * @see org.jdom.output.StAXStreamProcessor#process(java.io.XMLStreamWriter,
216 * org.jdom.Text, org.jdom.output.Format)
217 */
218 @Override
219 public void process(final XMLStreamWriter out, final Format format,
220 final Text text) throws XMLStreamException {
221 final List<Text> list = Collections.singletonList(text);
222 final FormatStack fstack = new FormatStack(format);
223 final Walker walker = buildWalker(fstack, list, false);
224 if (walker.hasNext()) {
225 final Content c = walker.next();
226 if (c == null) {
227 printText(out, fstack, new Text(walker.text()));
228 } else if (c.getCType() == CType.Text) {
229 printText(out, fstack, (Text)c);
230 }
231 }
232 out.flush();
233 }
234
235 /*
236 * (non-Javadoc)
237 *
238 * @see org.jdom.output.StAXStreamProcessor#process(java.io.XMLStreamWriter,
239 * org.jdom.Comment, org.jdom.output.Format)
240 */
241 @Override
242 public void process(final XMLStreamWriter out, final Format format,
243 final Comment comment) throws XMLStreamException {
244 printComment(out, new FormatStack(format), comment);
245 out.flush();
246 }
247
248 /*
249 * (non-Javadoc)
250 *
251 * @see org.jdom.output.StAXStreamProcessor#process(java.io.XMLStreamWriter,
252 * org.jdom.ProcessingInstruction, org.jdom.output.Format)
253 */
254 @Override
255 public void process(final XMLStreamWriter out, final Format format,
256 final ProcessingInstruction pi) throws XMLStreamException {
257 FormatStack fstack = new FormatStack(format);
258 // Output PI verbatim, disregarding TrAX escaping PIs.
259 fstack.setIgnoreTrAXEscapingPIs(true);
260 printProcessingInstruction(out, fstack, pi);
261 out.flush();
262 }
263
264 /*
265 * (non-Javadoc)
266 *
267 * @see org.jdom.output.StAXStreamProcessor#process(java.io.XMLStreamWriter,
268 * org.jdom.EntityRef, org.jdom.output.Format)
269 */
270 @Override
271 public void process(final XMLStreamWriter out, final Format format,
272 final EntityRef entity) throws XMLStreamException {
273 printEntityRef(out, new FormatStack(format), entity);
274 out.flush();
275 }
276
277 /* *******************************************
278 * Support methods for output. Should all be protected. All content-type
279 * print methods have a FormatStack. Only printContent is responsible for
280 * outputting appropriate indenting and newlines, which are easily available
281 * using the FormatStack.getLevelIndent() and FormatStack.getLevelEOL().
282 * *******************************************
283 */
284
285 /**
286 * This will handle printing of a {@link Document}.
287 *
288 * @param out
289 * <code>XMLStreamWriter</code> to use.
290 * @param fstack
291 * the FormatStack
292 * @param nstack
293 * the NamespaceStack
294 * @param doc
295 * <code>Document</code> to write.
296 * @throws XMLStreamException
297 * if the destination XMLStreamWriter fails
298 */
299 protected void printDocument(final XMLStreamWriter out, final FormatStack fstack,
300 final NamespaceStack nstack, final Document doc) throws XMLStreamException {
301
302 if (fstack.isOmitDeclaration()) {
303 // this actually writes the declaration as version 1, UTF-8
304 out.writeStartDocument();
305 if (fstack.getLineSeparator() != null) {
306 out.writeCharacters(fstack.getLineSeparator());
307 }
308 } else if (fstack.isOmitEncoding()) {
309 out.writeStartDocument("1.0");
310 if (fstack.getLineSeparator() != null) {
311 out.writeCharacters(fstack.getLineSeparator());
312 }
313 } else {
314 out.writeStartDocument(fstack.getEncoding(), "1.0");
315 if (fstack.getLineSeparator() != null) {
316 out.writeCharacters(fstack.getLineSeparator());
317 }
318 }
319
320 // we can output characters outside the Root element in StAX Event
321 // code... so, take advantage.
322 // If there is no root element then we cannot use the normal ways to
323 // access the ContentList because Document throws an exception.
324 // so we hack it and just access it by index.
325 List<Content> list = doc.hasRootElement() ? doc.getContent() :
326 new ArrayList<Content>(doc.getContentSize());
327 if (list.isEmpty()) {
328 final int sz = doc.getContentSize();
329 for (int i = 0; i < sz; i++) {
330 list.add(doc.getContent(i));
331 }
332 }
333 Walker walker = buildWalker(fstack, list, false);
334 if (walker.hasNext()) {
335 while (walker.hasNext()) {
336
337 final Content c = walker.next();
338 // we do not ignore Text-like things in the Document.
339 // the walker creates the indenting for us.
340 if (c == null) {
341 // but, what we do is ensure it is all whitespace, and not CDATA
342 final String padding = walker.text();
343 if (padding != null && Verifier.isAllXMLWhitespace(padding) &&
344 !walker.isCDATA()) {
345 // we do not use the escaping or text* method because this
346 // content is outside of the root element, and thus is not
347 // strict text.
348 out.writeCharacters(padding);
349 }
350 } else {
351 switch (c.getCType()) {
352 case Comment :
353 printComment(out, fstack, (Comment)c);
354 break;
355 case DocType :
356 printDocType(out, fstack, (DocType)c);
357 break;
358 case Element :
359 printElement(out, fstack, nstack, (Element)c);
360 break;
361 case ProcessingInstruction :
362 printProcessingInstruction(out, fstack,
363 (ProcessingInstruction)c);
364 break;
365 case Text :
366 final String padding = ((Text)c).getText();
367 if (padding != null && Verifier.isAllXMLWhitespace(padding)) {
368 // we do not use the escaping or text* method because this
369 // content is outside of the root element, and thus is not
370 // strict text.
371 out.writeCharacters(padding);
372 }
373 default :
374 // do nothing.
375 }
376 }
377
378 }
379
380 if (fstack.getLineSeparator() != null) {
381 out.writeCharacters(fstack.getLineSeparator());
382 }
383 }
384
385 out.writeEndDocument();
386
387 }
388
389 /**
390 * This will handle printing of a {@link DocType}.
391 *
392 * @param out
393 * <code>XMLStreamWriter</code> to use.
394 * @param fstack
395 * the FormatStack
396 * @param docType
397 * <code>DocType</code> to write.
398 * @throws XMLStreamException
399 * if the destination XMLStreamWriter fails
400 */
401 protected void printDocType(final XMLStreamWriter out, final FormatStack fstack,
402 final DocType docType) throws XMLStreamException {
403
404 final String publicID = docType.getPublicID();
405 final String systemID = docType.getSystemID();
406 final String internalSubset = docType.getInternalSubset();
407 boolean hasPublic = false;
408
409 // Declaration is never indented.
410 // write(out, fstack.getLevelIndent());
411
412 StringWriter sw = new StringWriter();
413
414 sw.write("<!DOCTYPE ");
415 sw.write(docType.getElementName());
416 if (publicID != null) {
417 sw.write(" PUBLIC \"");
418 sw.write(publicID);
419 sw.write("\"");
420 hasPublic = true;
421 }
422 if (systemID != null) {
423 if (!hasPublic) {
424 sw.write(" SYSTEM");
425 }
426 sw.write(" \"");
427 sw.write(systemID);
428 sw.write("\"");
429 }
430 if ((internalSubset != null) && (!internalSubset.equals(""))) {
431 sw.write(" [");
432 sw.write(fstack.getLineSeparator());
433 sw.write(docType.getInternalSubset());
434 sw.write("]");
435 }
436 sw.write(">");
437
438 // DocType does not write it's own EOL
439 // for compatibility reasons. Only
440 // when output from inside a Content set.
441 // write(out, fstack.getLineSeparator());
442 out.writeDTD(sw.toString());
443 }
444
445 /**
446 * This will handle printing of a {@link ProcessingInstruction}.
447 *
448 * @param out
449 * <code>XMLStreamWriter</code> to use.
450 * @param fstack
451 * the FormatStack
452 * @param pi
453 * <code>ProcessingInstruction</code> to write.
454 * @throws XMLStreamException
455 * if the destination XMLStreamWriter fails
456 */
457 protected void printProcessingInstruction(final XMLStreamWriter out,
458 final FormatStack fstack, final ProcessingInstruction pi)
459 throws XMLStreamException {
460 String target = pi.getTarget();
461 String rawData = pi.getData();
462 if (rawData != null && rawData.trim().length() > 0) {
463 out.writeProcessingInstruction(target, rawData);
464 } else {
465 out.writeProcessingInstruction(target);
466 }
467 }
468
469 /**
470 * This will handle printing of a {@link Comment}.
471 *
472 * @param out
473 * <code>XMLStreamWriter</code> to use.
474 * @param fstack
475 * the FormatStack
476 * @param comment
477 * <code>Comment</code> to write.
478 * @throws XMLStreamException
479 * if the destination XMLStreamWriter fails
480 */
481 protected void printComment(final XMLStreamWriter out, final FormatStack fstack,
482 final Comment comment) throws XMLStreamException {
483 out.writeComment(comment.getText());
484 }
485
486 /**
487 * This will handle printing of an {@link EntityRef}.
488 *
489 * @param out
490 * <code>XMLStreamWriter</code> to use.
491 * @param fstack
492 * the FormatStack
493 * @param entity
494 * <code>EntotyRef</code> to write.
495 * @throws XMLStreamException
496 * if the destination XMLStreamWriter fails
497 */
498 protected void printEntityRef(final XMLStreamWriter out, final FormatStack fstack,
499 final EntityRef entity) throws XMLStreamException {
500 out.writeEntityRef(entity.getName());
501 }
502
503 /**
504 * This will handle printing of a {@link CDATA}.
505 *
506 * @param out
507 * <code>XMLStreamWriter</code> to use.
508 * @param fstack
509 * the FormatStack
510 * @param cdata
511 * <code>CDATA</code> to write.
512 * @throws XMLStreamException
513 * if the destination XMLStreamWriter fails
514 */
515 protected void printCDATA(final XMLStreamWriter out, final FormatStack fstack,
516 final CDATA cdata) throws XMLStreamException {
517 // CDATAs are treated like text, not indented/newline content.
518 out.writeCData(cdata.getText());
519 }
520
521 /**
522 * This will handle printing of a {@link Text}.
523 *
524 * @param out
525 * <code>XMLStreamWriter</code> to use.
526 * @param fstack
527 * the FormatStack
528 * @param text
529 * <code>Text</code> to write.
530 * @throws XMLStreamException
531 * if the destination XMLStreamWriter fails
532 */
533 protected void printText(final XMLStreamWriter out, final FormatStack fstack,
534 final Text text) throws XMLStreamException {
535 out.writeCharacters(text.getText());
536 }
537
538 /**
539 * This will handle printing of an {@link Element}.
540 *
541 * @param out
542 * <code>XMLStreamWriter</code> to use.
543 * @param fstack
544 * the FormatStack
545 * @param nstack
546 * the NamespaceStack
547 * @param element
548 * <code>Element</code> to write.
549 * @throws XMLStreamException
550 * if the destination XMLStreamWriter fails
551 */
552 protected void printElement(final XMLStreamWriter out, final FormatStack fstack,
553 final NamespaceStack nstack, final Element element) throws XMLStreamException {
554
555 final ArrayList<String> restore = new ArrayList<String>();
556 nstack.push(element);
557 try {
558 for (Namespace nsa : nstack.addedForward()) {
559 restore.add(nsa.getPrefix());
560 if (JDOMConstants.NS_PREFIX_DEFAULT.equals(nsa.getPrefix())) {
561 out.setDefaultNamespace(nsa.getURI());
562 } else {
563 out.setPrefix(nsa.getPrefix(), nsa.getURI());
564 }
565 }
566
567 final List<Content> content = element.getContent();
568
569 TextMode textmode = fstack.getTextMode();
570
571
572 // OK, we play silly-buggers with the walker here in this class.
573 // we need to know what sort of Element we have, expanded or not.
574 // as a result, we need to know if we have content or not, and
575 // the walker can be empty if it is all formatted out.
576 // so we need to know the walker before we start the element.
577 // if the walker resolves to nothing then we set it to null
578 // as an indication that there is not sub-content.
579 Walker walker = null;
580
581 if (!content.isEmpty()) {
582
583 // Check for xml:space and adjust format settings
584 final String space = element.getAttributeValue("space",
585 Namespace.XML_NAMESPACE);
586
587 if ("default".equals(space)) {
588 textmode = fstack.getDefaultMode();
589 }
590 else if ("preserve".equals(space)) {
591 textmode = TextMode.PRESERVE;
592 }
593
594 fstack.push();
595 try {
596 fstack.setTextMode(textmode);
597 walker = buildWalker(fstack, content, false);
598 if (!walker.hasNext()) {
599 // rip out the walker if there is no content.
600 walker = null;
601 }
602 } finally {
603 fstack.pop();
604 }
605 }
606
607 // Three conditions that determine the required output.
608 // do we have an expanded element( <emt></emt> or an single <emt />
609 // if there is any printable content, or if expandempty is set
610 // then we must expand.
611 boolean expandit = walker != null || fstack.isExpandEmptyElements();
612
613 final Namespace ns = element.getNamespace();
614 if (expandit) {
615 out.writeStartElement(ns.getPrefix(), element.getName(), ns.getURI());
616
617 // Print the element's namespace, if appropriate
618 for (final Namespace nsd : nstack.addedForward()) {
619 printNamespace(out, fstack, nsd);
620 }
621
622 // Print out attributes
623 if (element.hasAttributes()) {
624 for (final Attribute attribute : element.getAttributes()) {
625 printAttribute(out, fstack, attribute);
626 }
627 }
628
629 // This neatens up the output stream for some reason - bug in standard StAX
630 // implementation requires us to close off the Element start tag before we
631 // start adding new Namespaces to child contexts...
632 out.writeCharacters("");
633
634 // OK, now we print out the meat of the Element
635 if (walker != null) {
636 // we need to re-create the walker/fstack.
637 fstack.push();
638 try {
639 fstack.setTextMode(textmode);
640 if (!walker.isAllText() && fstack.getPadBetween() != null) {
641 // we need to newline/indent
642 final String indent = fstack.getPadBetween();
643 printText(out, fstack, new Text(indent));
644 }
645
646 printContent(out, fstack, nstack, walker);
647
648 if (!walker.isAllText() && fstack.getPadLast() != null) {
649 // we need to newline/indent
650 final String indent = fstack.getPadLast();
651 printText(out, fstack, new Text(indent));
652 }
653 } finally {
654 fstack.pop();
655 }
656 }
657
658 out.writeEndElement();
659
660 } else {
661 // implies:
662 // fstack.isExpandEmpty... is false
663 // and content.isEmpty()
664 // or textonly == true
665 // and preserve == false
666 // and whiteonly == true
667
668 out.writeEmptyElement(ns.getPrefix(), element.getName(), ns.getURI());
669
670 // Print the element's namespace, if appropriate
671 for (final Namespace nsd : nstack.addedForward()) {
672 printNamespace(out, fstack, nsd);
673 }
674
675 // Print out attributes
676 for (final Attribute attribute : element.getAttributes()) {
677 printAttribute(out, fstack, attribute);
678 }
679 // This neatens up the output stream for some reason.
680 out.writeCharacters("");
681 }
682
683 } finally {
684 nstack.pop();
685 for (String pfx : restore) {
686 for (final Namespace nsa : nstack) {
687 if (nsa.getPrefix().equals(pfx)) {
688 if (JDOMConstants.NS_PREFIX_DEFAULT.equals(nsa.getPrefix())) {
689 out.setDefaultNamespace(nsa.getURI());
690 } else {
691 out.setPrefix(nsa.getPrefix(), nsa.getURI());
692 }
693 break;
694 }
695 }
696 }
697
698 }
699 }
700
701 /**
702 * This will handle printing of a List of {@link Content}.
703 * <p>
704 *
705 * @param out
706 * <code>XMLStreamWriter</code> to use.
707 * @param fstack
708 * the FormatStack
709 * @param nstack
710 * the NamespaceStack
711 * @param walker
712 * <code>Walker</code> of <code>Content</code> to write.
713 * @throws XMLStreamException
714 * if the destination XMLStreamWriter fails
715 */
716 protected void printContent(final XMLStreamWriter out,
717 final FormatStack fstack, final NamespaceStack nstack,
718 final Walker walker) throws XMLStreamException {
719
720 while (walker.hasNext()) {
721 final Content content = walker.next();
722
723 if (content == null) {
724 if (walker.isCDATA()) {
725 printCDATA(out, fstack, new CDATA(walker.text()));
726 } else {
727 printText(out, fstack, new Text(walker.text()));
728 }
729 } else {
730 switch (content.getCType()) {
731 case CDATA:
732 printCDATA(out, fstack, (CDATA) content);
733 break;
734 case Comment:
735 printComment(out, fstack, (Comment) content);
736 break;
737 case Element:
738 printElement(out, fstack, nstack, (Element) content);
739 break;
740 case EntityRef:
741 printEntityRef(out, fstack, (EntityRef) content);
742 break;
743 case ProcessingInstruction:
744 printProcessingInstruction(out, fstack,
745 (ProcessingInstruction) content);
746 break;
747 case Text:
748 printText(out, fstack, (Text) content);
749 break;
750 case DocType:
751 printDocType(out, fstack, (DocType) content);
752 break;
753 default:
754 throw new IllegalStateException(
755 "Unexpected Content " + content.getCType());
756
757 }
758 }
759 }
760
761 }
762
763
764 /**
765 * This will handle printing of any needed <code>{@link Namespace}</code>
766 * declarations.
767 *
768 * @param out
769 * <code>XMLStreamWriter</code> to use.
770 * @param fstack
771 * The current FormatStack
772 * @param ns
773 * <code>Namespace</code> to print definition of
774 * @throws XMLStreamException
775 * if the output fails
776 */
777 protected void printNamespace(final XMLStreamWriter out, final FormatStack fstack,
778 final Namespace ns) throws XMLStreamException {
779 final String prefix = ns.getPrefix();
780 final String uri = ns.getURI();
781
782 out.writeNamespace(prefix, uri);
783 }
784
785 /**
786 * This will handle printing of an <code>{@link Attribute}</code>.
787 *
788 * @param out
789 * <code>XMLStreamWriter</code> to use.
790 * @param fstack
791 * The current FormatStack
792 * @param attribute
793 * <code>Attribute</code> to output
794 * @throws XMLStreamException
795 * if the output fails
796 */
797 protected void printAttribute(final XMLStreamWriter out, final FormatStack fstack,
798 final Attribute attribute) throws XMLStreamException {
799
800 if (!attribute.isSpecified() && fstack.isSpecifiedAttributesOnly()) {
801 return;
802 }
803
804 final Namespace ns = attribute.getNamespace();
805 if (ns == Namespace.NO_NAMESPACE) {
806 out.writeAttribute(attribute.getName(), attribute.getValue());
807 } else {
808 out.writeAttribute(ns.getPrefix(), ns.getURI(),
809 attribute.getName(), attribute.getValue());
810 }
811 }
812
813 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.io.IOException;
57 import java.io.Writer;
58 import java.util.ArrayList;
59 import java.util.Collections;
60 import java.util.List;
61
62 import javax.xml.transform.Result;
63
64 import org.jdom.Attribute;
65 import org.jdom.CDATA;
66 import org.jdom.Comment;
67 import org.jdom.Content;
68 import org.jdom.DocType;
69 import org.jdom.Document;
70 import org.jdom.Element;
71 import org.jdom.EntityRef;
72 import org.jdom.IllegalDataException;
73 import org.jdom.Namespace;
74 import org.jdom.ProcessingInstruction;
75 import org.jdom.Text;
76 import org.jdom.Verifier;
77 import org.jdom.output.Format;
78 import org.jdom.output.Format.TextMode;
79 import org.jdom.output.XMLOutputter2;
80 import org.jdom.util.NamespaceStack;
81
82 /**
83 * This class provides a concrete implementation of {@link XMLOutputProcessor}
84 * for supporting the {@link XMLOutputter2}.
85 * <p>
86 * <h2>Overview</h2>
87 * <p>
88 * This class is marked abstract even though all methods are fully implemented.
89 * The <code>process*(...)</code> methods are public because they match the
90 * XMLOutputProcessor interface but the remaining methods are all protected.
91 * <p>
92 * People who want to create a custom XMLOutputProcessor for XMLOutputter are
93 * able to extend this class and modify any functionality they want. Before
94 * sub-classing this you should first check to see if the {@link Format} class
95 * can get you the results you want.
96 * <p>
97 * <b><i>Subclasses of this should have reentrant methods.</i></b> This is
98 * easiest to accomplish simply by not allowing any instance fields. If your
99 * sub-class has an instance field/variable, then it's probably broken.
100 * <p>
101 * <h2>The Stacks</h2>
102 * <p>
103 * One significant feature of this implementation is that it creates and
104 * maintains both a {@link NamespaceStack} and {@link FormatStack} that are
105 * managed in the
106 * {@link #printElement(Writer, FormatStack, NamespaceStack, Element)} method.
107 * The stacks are pushed and popped in that method only. They significantly
108 * improve the performance and readability of the code.
109 * <p>
110 * The NamespaceStack is only sent through to the
111 * {@link #printElement(Writer, FormatStack, NamespaceStack, Element)} and
112 * {@link #printContent(Writer, FormatStack, NamespaceStack, Walker)} methods,
113 * but the FormatStack is pushed through to all print* Methods.
114 * <p>
115 * <h2>Text Processing</h2>
116 * <p>
117 * In XML the concept of 'Text' can be loosely defined as anything that can be
118 * found between an Element's start and end tags, excluding Comments and
119 * Processing Instructions. When considered from a JDOM perspective, this means
120 * {@link Text}, {@link CDATA} and {@link EntityRef} content. This will be
121 * referred to as 'Text-like content'
122 * <p>
123 * XMLOutputter delegates the management and formatting of Content to a
124 * Walker instance. See {@link Walker} and its various implementations for
125 * details on how the Element content is processed.
126 * <p>
127 * Because the Walker interface specifies that Text/CDATA content may be
128 * returned as either Text/CDATA instances or as formatted String values
129 * this class sometimes uses printCDATA(...) and printText(...), and sometimes
130 * uses the more direct {@link #textCDATA(Writer, String)} or
131 * {@link #textRaw(Writer, String)} as
132 * appropriate. In other words, subclasses should probably override these second
133 * methods instead of the print methods.
134 * <p>
135 * <h2>Non-Text Content</h2>
136 * <p>
137 * Non-text content is processed via the respective print* methods. The usage
138 * should be logical based on the method name.
139 * <p>
140 * The general observations are:
141 * <ul>
142 * <li>printElement - maintains the Stacks, prints the element open tags, with
143 * attributes and namespaces. It checks to see whether the Element is text-only,
144 * or has non-text content. If it is text-only there is no indent/newline
145 * handling and it delegates to the correct text-type print method, otherwise it
146 * delegates to printContent.
147 * <li>printContent is called to output all lists of Content. It assumes that
148 * all whitespace indentation/newlines are appropriate before it is called, but
149 * it will ensure that padding is appropriate between the items in the list.
150 * </ul>
151 * <p>
152 * <h2>Final Notes</h2> No methods actually write to the destination Writer
153 * except the <code>write(...)</code> methods. Thus, all other methods do their
154 * respective processing and delegate the actual destination output to the
155 * {@link #write(Writer, char)} or {@link #write(Writer, String)} methods.
156 * <p>
157 * All Text-like content (printCDATA, printText, and printEntityRef) will
158 * ultimately be output through the the text* methods (and no other content).
159 * <p>
160 *
161 * @see XMLOutputter2
162 * @see XMLOutputProcessor
163 * @since JDOM2
164 * @author Rolf Lear
165 */
166 public abstract class AbstractXMLOutputProcessor extends AbstractOutputProcessor
167 implements XMLOutputProcessor {
168
169 /** Simple constant for an open-CDATA */
170 protected static final String CDATAPRE = "<![CDATA[";
171 /** Simple constant for a close-CDATA */
172 protected static final String CDATAPOST = "]]>";
173
174
175
176 /* *******************************************
177 * XMLOutputProcessor implementation.
178 * *******************************************
179 */
180
181 /*
182 * (non-Javadoc)
183 *
184 * @see org.jdom.output.XMLOutputProcessor#process(java.io.Writer,
185 * org.jdom.Document, org.jdom.output.Format)
186 */
187 @Override
188 public void process(final Writer out, final Format format,
189 final Document doc) throws IOException {
190 printDocument(out, new FormatStack(format), new NamespaceStack(), doc);
191 out.flush();
192 }
193
194 /*
195 * (non-Javadoc)
196 *
197 * @see org.jdom.output.XMLOutputProcessor#process(java.io.Writer,
198 * org.jdom.DocType, org.jdom.output.Format)
199 */
200 @Override
201 public void process(final Writer out, final Format format,
202 final DocType doctype) throws IOException {
203 printDocType(out, new FormatStack(format), doctype);
204 out.flush();
205 }
206
207 /*
208 * (non-Javadoc)
209 *
210 * @see org.jdom.output.XMLOutputProcessor#process(java.io.Writer,
211 * org.jdom.Element, org.jdom.output.Format)
212 */
213 @Override
214 public void process(final Writer out, final Format format,
215 final Element element) throws IOException {
216 // If this is the root element we could pre-initialize the
217 // namespace stack with the namespaces
218 printElement(out, new FormatStack(format), new NamespaceStack(),
219 element);
220 out.flush();
221 }
222
223 /*
224 * (non-Javadoc)
225 *
226 * @see org.jdom.output.XMLOutputProcessor#process(java.io.Writer,
227 * java.util.List, org.jdom.output.Format)
228 */
229 @Override
230 public void process(final Writer out, final Format format,
231 final List<? extends Content> list)
232 throws IOException {
233 FormatStack fstack = new FormatStack(format);
234 Walker walker = buildWalker(fstack, list, true);
235 printContent(out, fstack, new NamespaceStack(), walker);
236 out.flush();
237 }
238
239 /*
240 * (non-Javadoc)
241 *
242 * @see org.jdom.output.XMLOutputProcessor#process(java.io.Writer,
243 * org.jdom.CDATA, org.jdom.output.Format)
244 */
245 @Override
246 public void process(final Writer out, final Format format,
247 final CDATA cdata) throws IOException {
248 // we use the powers of the Walker to manage text-like content.
249 final List<CDATA> list = Collections.singletonList(cdata);
250 FormatStack fstack = new FormatStack(format);
251 final Walker walker = buildWalker(fstack, list, true);
252 if (walker.hasNext()) {
253 printContent(out, fstack, new NamespaceStack(), walker);
254 }
255 out.flush();
256 }
257
258 /*
259 * (non-Javadoc)
260 *
261 * @see org.jdom.output.XMLOutputProcessor#process(java.io.Writer,
262 * org.jdom.Text, org.jdom.output.Format)
263 */
264 @Override
265 public void process(final Writer out, final Format format,
266 final Text text) throws IOException {
267 // we use the powers of the Walker to manage text-like content.
268 final List<Text> list = Collections.singletonList(text);
269 FormatStack fstack = new FormatStack(format);
270 final Walker walker = buildWalker(fstack, list, true);
271 if (walker.hasNext()) {
272 printContent(out, fstack, new NamespaceStack(), walker);
273 }
274 out.flush();
275 }
276
277 /*
278 * (non-Javadoc)
279 *
280 * @see org.jdom.output.XMLOutputProcessor#process(java.io.Writer,
281 * org.jdom.Comment, org.jdom.output.Format)
282 */
283 @Override
284 public void process(final Writer out, final Format format,
285 final Comment comment) throws IOException {
286 printComment(out, new FormatStack(format), comment);
287 out.flush();
288 }
289
290 /*
291 * (non-Javadoc)
292 *
293 * @see org.jdom.output.XMLOutputProcessor#process(java.io.Writer,
294 * org.jdom.ProcessingInstruction, org.jdom.output.Format)
295 */
296 @Override
297 public void process(final Writer out, final Format format,
298 final ProcessingInstruction pi) throws IOException {
299 FormatStack fstack = new FormatStack(format);
300 // Output PI verbatim, disregarding TrAX escaping PIs.
301 fstack.setIgnoreTrAXEscapingPIs(true);
302 printProcessingInstruction(out, fstack, pi);
303 out.flush();
304 }
305
306 /*
307 * (non-Javadoc)
308 *
309 * @see org.jdom.output.XMLOutputProcessor#process(java.io.Writer,
310 * org.jdom.EntityRef, org.jdom.output.Format)
311 */
312 @Override
313 public void process(final Writer out, final Format format,
314 final EntityRef entity) throws IOException {
315 printEntityRef(out, new FormatStack(format), entity);
316 out.flush();
317 }
318
319 /*
320 * ========================================================================
321 * Methods that actually write data to output. None of the other methods
322 * should directly write to the output unless they use these methods.
323 * ========================================================================
324 */
325
326 /**
327 * Print some string value to the output. Null values are ignored. This
328 * ignore-null property is used for a few tricks.
329 *
330 * @param out
331 * The Writer to write to.
332 * @param str
333 * The String to write (can be null).
334 * @throws IOException
335 * if the out Writer fails.
336 */
337 protected void write(final Writer out, final String str) throws IOException {
338 if (str == null) {
339 return;
340 }
341 out.write(str);
342 }
343
344 /**
345 * Write a single character to the output Writer.
346 *
347 * @param out
348 * The Writer to write to.
349 * @param c
350 * The char to write.
351 * @throws IOException
352 * if the Writer fails.
353 */
354 protected void write(final Writer out, final char c) throws IOException {
355 out.write(c);
356 }
357
358 /*
359 * ========================================================================
360 * Support methods for Text-content formatting. Should all be protected. The
361 * following are used when printing Text-based data. Because of complicated
362 * multi-sequential text sometimes the requirements are odd. All Text
363 * content will be output using these methods, which is why there is the None
364 * version.
365 * ========================================================================
366 */
367
368 /**
369 * This will take the three pre-defined entities in XML 1.0 ('&lt;', '&gt;',
370 * and '&amp;' - used specifically in XML elements) as well as CR/NL and
371 * Quote characters which require escaping inside Attribute values and
372 * convert their character representation to the appropriate entity
373 * reference suitable for XML attribute content. Further, some special
374 * characters (e.g. characters that are not valid in the current encoding)
375 * are converted to escaped representations.
376 * <p>
377 * <b>Note:</b> If {@link FormatStack#getEscapeOutput()} is false then no
378 * escaping will happen.
379 *
380 * @param out
381 * The destination Writer
382 * @param fstack
383 * The {@link FormatStack}
384 * @param value
385 * <code>String</code> Attribute value to escape.
386 * @throws IOException
387 * if the destination Writer fails.
388 * @throws IllegalDataException
389 * if an entity can not be escaped
390 */
391 protected void attributeEscapedEntitiesFilter(final Writer out,
392 final FormatStack fstack, final String value) throws IOException {
393
394 if (!fstack.getEscapeOutput()) {
395 // no escaping...
396 write(out, value);
397 return;
398 }
399
400 write(out, Format.escapeAttribute(fstack.getEscapeStrategy(), value));
401
402 }
403
404 /**
405 * Convenience method that simply passes the input str to
406 * {@link #write(Writer, String)}. This could be useful for subclasses to
407 * hook in to. All text-type output will come through this or the
408 * {@link #textRaw(Writer, char)} method.
409 *
410 * @param out
411 * the destination writer.
412 * @param str
413 * the String to write.
414 * @throws IOException
415 * if the Writer fails.
416 */
417 protected void textRaw(final Writer out, final String str) throws IOException {
418 write(out, str);
419 }
420
421 /**
422 * Convenience method that simply passes the input char to
423 * {@link #write(Writer, char)}. This could be useful for subclasses to hook
424 * in to. All text-type output will come through this or the
425 * {@link #textRaw(Writer, String)} method.
426 *
427 * @param out
428 * the destination Writer.
429 * @param ch
430 * the char to write.
431 * @throws IOException
432 * if the Writer fails.
433 */
434 protected void textRaw(final Writer out, final char ch) throws IOException {
435 write(out, ch);
436 }
437
438 /**
439 * Write an {@link EntityRef} to the destination.
440 *
441 * @param out
442 * the destination Writer.
443 * @param name
444 * the EntityRef's name.
445 * @throws IOException
446 * if the Writer fails.
447 */
448 protected void textEntityRef(final Writer out, final String name) throws IOException {
449 textRaw(out, '&');
450 textRaw(out, name);
451 textRaw(out, ';');
452 }
453
454 /**
455 * Write a {@link CDATA} to the destination
456 * @param out the destination Writer
457 * @param text the CDATA text
458 * @throws IOException if the Writer fails.
459 */
460 protected void textCDATA(final Writer out, final String text) throws IOException {
461 textRaw(out, CDATAPRE);
462 textRaw(out, text);
463 textRaw(out, CDATAPOST);
464 }
465
466 /* *******************************************
467 * Support methods for output. Should all be protected. All content-type
468 * print methods have a FormatStack. Only printContent is responsible for
469 * outputting appropriate indenting and newlines, which are easily available
470 * using the FormatStack.getLevelIndent() and FormatStack.getLevelEOL().
471 * *******************************************
472 */
473
474 /**
475 * This will handle printing of a {@link Document}.
476 *
477 * @param out
478 * <code>Writer</code> to use.
479 * @param fstack
480 * the FormatStack
481 * @param nstack
482 * the NamespaceStack
483 * @param doc
484 * <code>Document</code> to write.
485 * @throws IOException
486 * if the destination Writer fails
487 */
488 protected void printDocument(final Writer out, final FormatStack fstack,
489 final NamespaceStack nstack, final Document doc) throws IOException {
490
491
492 // If there is no root element then we cannot use the normal ways to
493 // access the ContentList because Document throws an exception.
494 // so we hack it and just access it by index.
495 List<Content> list = doc.hasRootElement() ? doc.getContent() :
496 new ArrayList<Content>(doc.getContentSize());
497 if (list.isEmpty()) {
498 final int sz = doc.getContentSize();
499 for (int i = 0; i < sz; i++) {
500 list.add(doc.getContent(i));
501 }
502 }
503
504 printDeclaration(out, fstack);
505
506 Walker walker = buildWalker(fstack, list, true);
507 if (walker.hasNext()) {
508 while (walker.hasNext()) {
509
510 final Content c = walker.next();
511 // we do not ignore Text-like things in the Document.
512 // the walker creates the indenting for us.
513 if (c == null) {
514 // but, what we do is ensure it is all whitespace, and not CDATA
515 final String padding = walker.text();
516 if (padding != null && Verifier.isAllXMLWhitespace(padding) &&
517 !walker.isCDATA()) {
518 // we do not use the escaping or text* method because this
519 // content is outside of the root element, and thus is not
520 // strict text.
521 write(out, padding);
522 }
523 } else {
524 switch (c.getCType()) {
525 case Comment :
526 printComment(out, fstack, (Comment)c);
527 break;
528 case DocType :
529 printDocType(out, fstack, (DocType)c);
530 break;
531 case Element :
532 printElement(out, fstack, nstack, (Element)c);
533 break;
534 case ProcessingInstruction :
535 printProcessingInstruction(out, fstack,
536 (ProcessingInstruction)c);
537 break;
538 case Text :
539 final String padding = ((Text)c).getText();
540 if (padding != null && Verifier.isAllXMLWhitespace(padding)) {
541 // we do not use the escaping or text* method because this
542 // content is outside of the root element, and thus is not
543 // strict text.
544 write(out, padding);
545 }
546 default :
547 // do nothing.
548 }
549 }
550
551 }
552
553 if (fstack.getLineSeparator() != null) {
554 write(out, fstack.getLineSeparator());
555 }
556 }
557
558 }
559
560 /**
561 * This will handle printing of the XML declaration. Assumes XML version 1.0
562 * since we don't directly know.
563 *
564 * @param out
565 * <code>Writer</code> to use.
566 * @param fstack
567 * the FormatStack
568 * @throws IOException
569 * if the destination Writer fails
570 */
571 protected void printDeclaration(final Writer out, final FormatStack fstack) throws IOException {
572
573 // Only print the declaration if it's not being omitted
574 if (fstack.isOmitDeclaration()) {
575 return;
576 }
577 // Declaration is never indented.
578 // write(out, fstack.getLevelIndent());
579
580 // Assume 1.0 version
581 if (fstack.isOmitEncoding()) {
582 write(out, "<?xml version=\"1.0\"?>");
583 } else {
584 write(out, "<?xml version=\"1.0\"");
585 write(out, " encoding=\"");
586 write(out, fstack.getEncoding());
587 write(out, "\"?>");
588 }
589
590 // Print new line after decl always, even if no other new lines
591 // Helps the output look better and is semantically
592 // inconsequential
593 // newline(out, fstack);
594 write(out, fstack.getLineSeparator());
595 }
596
597 /**
598 * This will handle printing of a {@link DocType}.
599 *
600 * @param out
601 * <code>Writer</code> to use.
602 * @param fstack
603 * the FormatStack
604 * @param docType
605 * <code>DocType</code> to write.
606 * @throws IOException
607 * if the destination Writer fails
608 */
609 protected void printDocType(final Writer out, final FormatStack fstack,
610 final DocType docType) throws IOException {
611
612 final String publicID = docType.getPublicID();
613 final String systemID = docType.getSystemID();
614 final String internalSubset = docType.getInternalSubset();
615 boolean hasPublic = false;
616
617 // Declaration is never indented.
618 // write(out, fstack.getLevelIndent());
619
620 write(out, "<!DOCTYPE ");
621 write(out, docType.getElementName());
622 if (publicID != null) {
623 write(out, " PUBLIC \"");
624 write(out, publicID);
625 write(out, "\"");
626 hasPublic = true;
627 }
628 if (systemID != null) {
629 if (!hasPublic) {
630 write(out, " SYSTEM");
631 }
632 write(out, " \"");
633 write(out, systemID);
634 write(out, "\"");
635 }
636 if ((internalSubset != null) && (!internalSubset.equals(""))) {
637 write(out, " [");
638 write(out, fstack.getLineSeparator());
639 write(out, docType.getInternalSubset());
640 write(out, "]");
641 }
642 write(out, ">");
643
644 }
645
646 /**
647 * This will handle printing of a {@link ProcessingInstruction}.
648 *
649 * @param out
650 * <code>Writer</code> to use.
651 * @param fstack
652 * the FormatStack
653 * @param pi
654 * <code>ProcessingInstruction</code> to write.
655 * @throws IOException
656 * if the destination Writer fails
657 */
658 protected void printProcessingInstruction(final Writer out,
659 final FormatStack fstack, final ProcessingInstruction pi)
660 throws IOException {
661 String target = pi.getTarget();
662 boolean piProcessed = false;
663
664 if (fstack.isIgnoreTrAXEscapingPIs() == false) {
665 if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING)) {
666 // special case... change the FormatStack
667 fstack.setEscapeOutput(false);
668 piProcessed = true;
669 }
670 else if (target.equals(Result.PI_ENABLE_OUTPUT_ESCAPING)) {
671 // special case... change the FormatStack
672 fstack.setEscapeOutput(true);
673 piProcessed = true;
674 }
675 }
676 if (piProcessed == false) {
677 String rawData = pi.getData();
678
679 // Write <?target data?> or if no data then just <?target?>
680 if (!"".equals(rawData)) {
681 write(out, "<?");
682 write(out, target);
683 write(out, " ");
684 write(out, rawData);
685 write(out, "?>");
686 }
687 else {
688 write(out, "<?");
689 write(out, target);
690 write(out, "?>");
691 }
692 }
693 }
694
695 /**
696 * This will handle printing of a {@link Comment}.
697 *
698 * @param out
699 * <code>Writer</code> to use.
700 * @param fstack
701 * the FormatStack
702 * @param comment
703 * <code>Comment</code> to write.
704 * @throws IOException
705 * if the destination Writer fails
706 */
707 protected void printComment(final Writer out, final FormatStack fstack,
708 final Comment comment) throws IOException {
709 write(out, "<!--");
710 write(out, comment.getText());
711 write(out, "-->");
712 }
713
714 /**
715 * This will handle printing of an {@link EntityRef}.
716 *
717 * @param out
718 * <code>Writer</code> to use.
719 * @param fstack
720 * the FormatStack
721 * @param entity
722 * <code>EntotyRef</code> to write.
723 * @throws IOException
724 * if the destination Writer fails
725 */
726 protected void printEntityRef(final Writer out, final FormatStack fstack,
727 final EntityRef entity) throws IOException {
728 // EntityRefs are treated like text, not indented/newline content.
729 textEntityRef(out, entity.getName());
730 }
731
732 /**
733 * This will handle printing of a {@link CDATA}.
734 *
735 * @param out
736 * <code>Writer</code> to use.
737 * @param fstack
738 * the FormatStack
739 * @param cdata
740 * <code>CDATA</code> to write.
741 * @throws IOException
742 * if the destination Writer fails
743 */
744 protected void printCDATA(final Writer out, final FormatStack fstack,
745 final CDATA cdata) throws IOException {
746 // CDATAs are treated like text, not indented/newline content.
747 textCDATA(out, cdata.getText());
748 }
749
750 /**
751 * This will handle printing of a {@link Text}.
752 *
753 * @param out
754 * <code>Writer</code> to use.
755 * @param fstack
756 * the FormatStack
757 * @param text
758 * <code>Text</code> to write.
759 * @throws IOException
760 * if the destination Writer fails
761 */
762 protected void printText(final Writer out, final FormatStack fstack,
763 final Text text) throws IOException {
764 if (fstack.getEscapeOutput()) {
765 textRaw(out, Format.escapeText(fstack.getEscapeStrategy(),
766 fstack.getLineSeparator(), text.getText()));
767
768 return;
769 }
770 textRaw(out, text.getText());
771 }
772
773 /**
774 * This will handle printing of an {@link Element}.
775 * <p>
776 * This method arranges for outputting the Element infrastructure including
777 * Namespace Declarations and Attributes.
778 *
779 * @param out
780 * <code>Writer</code> to use.
781 * @param fstack
782 * the FormatStack
783 * @param nstack
784 * the NamespaceStack
785 * @param element
786 * <code>Element</code> to write.
787 * @throws IOException
788 * if the destination Writer fails
789 */
790 protected void printElement(final Writer out, final FormatStack fstack,
791 final NamespaceStack nstack, final Element element) throws IOException {
792
793 nstack.push(element);
794 try {
795 final List<Content> content = element.getContent();
796
797 // Print the beginning of the tag plus attributes and any
798 // necessary namespace declarations
799 write(out, "<");
800
801 write(out, element.getQualifiedName());
802
803 // Print the element's namespace, if appropriate
804 for (final Namespace ns : nstack.addedForward()) {
805 printNamespace(out, fstack, ns);
806 }
807
808 // Print out attributes
809 if (element.hasAttributes()) {
810 for (final Attribute attribute : element.getAttributes()) {
811 printAttribute(out, fstack, attribute);
812 }
813 }
814
815 if (content.isEmpty()) {
816 // Case content is empty
817 if (fstack.isExpandEmptyElements()) {
818 write(out, "></");
819 write(out, element.getQualifiedName());
820 write(out, ">");
821 }
822 else {
823 write(out, " />");
824 }
825 // nothing more to do.
826 return;
827 }
828
829 // OK, we have real content to push.
830 fstack.push();
831 try {
832
833 // Check for xml:space and adjust format settings
834 final String space = element.getAttributeValue("space",
835 Namespace.XML_NAMESPACE);
836
837 if ("default".equals(space)) {
838 fstack.setTextMode(fstack.getDefaultMode());
839 }
840 else if ("preserve".equals(space)) {
841 fstack.setTextMode(TextMode.PRESERVE);
842 }
843
844 // note we ensure the FStack is right before creating the walker
845 Walker walker = buildWalker(fstack, content, true);
846
847 if (!walker.hasNext()) {
848 // the walker has formatted out whatever content we had
849 if (fstack.isExpandEmptyElements()) {
850 write(out, "></");
851 write(out, element.getQualifiedName());
852 write(out, ">");
853 }
854 else {
855 write(out, " />");
856 }
857 // nothing more to do.
858 return;
859 }
860 // we have some content.
861 write(out, ">");
862 if (!walker.isAllText()) {
863 // we need to newline/indent
864 textRaw(out, fstack.getPadBetween());
865 }
866
867 printContent(out, fstack, nstack, walker);
868
869 if (!walker.isAllText()) {
870 // we need to newline/indent
871 textRaw(out, fstack.getPadLast());
872 }
873 write(out, "</");
874 write(out, element.getQualifiedName());
875 write(out, ">");
876
877 } finally {
878 fstack.pop();
879 }
880 } finally {
881 nstack.pop();
882 }
883
884 }
885
886 /**
887 * This will handle printing of a List of {@link Content}.
888 * <p>
889 * The list of Content is basically processed as one of three types of
890 * content
891 * <ol>
892 * <li>Consecutive text-type (Text, CDATA, and EntityRef) content
893 * <li>Stand-alone text-type content
894 * <li>Non-text-type content.
895 * </ol>
896 * Although the code looks complex, the theory is conceptually simple:
897 * <ol>
898 * <li>identify one of the three types (consecutive, stand-alone, non-text)
899 * <li>do indent if any is specified.
900 * <li>send the type to the respective print* handler (e.g.
901 * {@link #printCDATA(Writer, FormatStack, CDATA)}, or
902 * {@link #printComment(Writer, FormatStack, Comment)},
903 * <li>do a newline if one is specified.
904 * <li>loop back to 1. until there's no more content to process.
905 * </ol>
906 *
907 * @param out
908 * <code>Writer</code> to use.
909 * @param fstack
910 * the FormatStack
911 * @param nstack
912 * the NamespaceStack
913 * @param walker
914 * {@link Walker} of <code>Content</code> to write.
915 * @throws IOException
916 * if the destination Writer fails
917 */
918 protected void printContent(final Writer out,
919 final FormatStack fstack, final NamespaceStack nstack,
920 final Walker walker)
921 throws IOException {
922
923 while (walker.hasNext()) {
924 Content c = walker.next();
925 if (c == null) {
926 // it is a text value of some sort.
927 final String t = walker.text();
928 if (walker.isCDATA()) {
929 textCDATA(out, t);
930 } else {
931 textRaw(out, t);
932 }
933 } else {
934 switch(c.getCType()) {
935 case CDATA:
936 printCDATA(out, fstack, (CDATA)c);
937 break;
938 case Comment:
939 printComment(out, fstack, (Comment)c);
940 break;
941 case DocType:
942 printDocType(out, fstack, (DocType)c);
943 break;
944 case Element:
945 printElement(out, fstack, nstack, (Element)c);
946 break;
947 case EntityRef:
948 printEntityRef(out, fstack, (EntityRef)c);
949 break;
950 case ProcessingInstruction:
951 printProcessingInstruction(out, fstack,
952 (ProcessingInstruction)c);
953 break;
954 case Text:
955 printText(out, fstack, (Text)c);
956 break;
957 }
958 }
959 }
960
961 }
962
963 /**
964 * This will handle printing of any needed <code>{@link Namespace}</code>
965 * declarations.
966 *
967 * @param out
968 * <code>Writer</code> to use.
969 * @param fstack
970 * The current FormatStack
971 * @param ns
972 * <code>Namespace</code> to print definition of
973 * @throws IOException
974 * if the output fails
975 */
976 protected void printNamespace(final Writer out, final FormatStack fstack,
977 final Namespace ns) throws IOException {
978 final String prefix = ns.getPrefix();
979 final String uri = ns.getURI();
980
981 write(out, " xmlns");
982 if (!prefix.equals("")) {
983 write(out, ":");
984 write(out, prefix);
985 }
986 write(out, "=\"");
987 attributeEscapedEntitiesFilter(out, fstack, uri);
988 write(out, "\"");
989 }
990
991 /**
992 * This will handle printing of an <code>{@link Attribute}</code>.
993 *
994 * @param out
995 * <code>Writer</code> to use.
996 * @param fstack
997 * The current FormatStack
998 * @param attribute
999 * <code>Attribute</code> to output
1000 * @throws IOException
1001 * if the output fails
1002 */
1003 protected void printAttribute(final Writer out, final FormatStack fstack,
1004 final Attribute attribute) throws IOException {
1005
1006 if (!attribute.isSpecified() && fstack.isSpecifiedAttributesOnly()) {
1007 return;
1008 }
1009 write(out, " ");
1010 write(out, attribute.getQualifiedName());
1011 write(out, "=");
1012
1013 write(out, "\"");
1014 attributeEscapedEntitiesFilter(out, fstack, attribute.getValue());
1015 write(out, "\"");
1016 }
1017
1018 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.List;
57
58 import org.jdom.Attribute;
59 import org.jdom.CDATA;
60 import org.jdom.Comment;
61 import org.jdom.Content;
62 import org.jdom.Document;
63 import org.jdom.Element;
64 import org.jdom.EntityRef;
65 import org.jdom.ProcessingInstruction;
66 import org.jdom.Text;
67 import org.jdom.output.DOMOutputter;
68 import org.jdom.output.Format;
69
70 /**
71 * This interface provides a base support for the {@link DOMOutputter}.
72 * <p>
73 * People who want to create a custom DOMOutputProcessor for DOMOutputter are
74 * able to implement this interface with the following notes and restrictions:
75 * <ol>
76 * <li>The DOMOutputter will call one, and only one of the
77 * <code>process(Format,*)</code> methods each time the DOMOutputter is
78 * requested to output some JDOM content. It is thus safe to assume that a
79 * <code>process(Format,*)</code> method can set up any infrastructure needed to
80 * process the content, and that the DOMOutputter will not re-call that method,
81 * or some other <code>process(Format,*)</code> method for the same output
82 * sequence.
83 * <li>The process methods should be thread-safe and reentrant: The same
84 * <code>process(Format,*)</code> method may (will) be called concurrently from
85 * different threads.
86 * </ol>
87 * <p>
88 * The {@link AbstractDOMOutputProcessor} class is a full implementation of this
89 * interface and is fully customisable. People who want a custom DOMOutputter
90 * are encouraged to extend the AbstractDOMOutputProcessor rather than do a full
91 * re-implementation of this interface.
92 *
93 * @see DOMOutputter
94 * @see AbstractDOMOutputProcessor
95 * @since JDOM2
96 * @author Rolf Lear
97 */
98 public interface DOMOutputProcessor {
99
100 /**
101 * This will convert the <code>{@link Document}</code> to the given DOM
102 * Document.
103 * <p>
104 *
105 * @param basedoc
106 * The DOM document to use for the conversion
107 * @param format
108 * <code>Format</code> instance specifying output style
109 * @param doc
110 * <code>Document</code> to format.
111 * @return The same DOM Document as the input document, but with the JDOM
112 * content converted and added.
113 */
114 public org.w3c.dom.Document process(org.w3c.dom.Document basedoc,
115 Format format, Document doc);
116
117 /**
118 * This will convert the <code>{@link Element}</code> using the given DOM
119 * Document to create the resulting DOM Element.
120 *
121 * @param basedoc
122 * The DOM document to use for the conversion
123 * @param format
124 * <code>Format</code> instance specifying output style
125 * @param element
126 * <code>Element</code> to format.
127 * @return The input JDOM Element converted to a DOM Element
128 */
129 public org.w3c.dom.Element process(org.w3c.dom.Document basedoc,
130 Format format, Element element);
131
132 /**
133 * This will convert the list of JDOM <code>{@link Content}</code> using the
134 * given DOM Document to create the resulting list of DOM Nodes.
135 *
136 * @param basedoc
137 * The DOM document to use for the conversion
138 * @param format
139 * <code>Format</code> instance specifying output style
140 * @param list
141 * JDOM <code>Content</code> to convert.
142 * @return The input JDOM Content List converted to a List of DOM Nodes
143 */
144 public List<org.w3c.dom.Node> process(org.w3c.dom.Document basedoc,
145 Format format, List<? extends Content> list);
146
147 /**
148 * This will convert the <code>{@link CDATA}</code> using the given DOM
149 * Document to create the resulting DOM CDATASection.
150 *
151 * @param basedoc
152 * The DOM document to use for the conversion
153 * @param format
154 * <code>Format</code> instance specifying output style
155 * @param cdata
156 * <code>CDATA</code> to format.
157 * @return The input JDOM CDATA converted to a DOM CDATASection
158 */
159 public org.w3c.dom.CDATASection process(org.w3c.dom.Document basedoc,
160 Format format, CDATA cdata);
161
162 /**
163 * This will convert the <code>{@link Text}</code> using the given DOM
164 * Document to create the resulting DOM Text.
165 *
166 * @param basedoc
167 * The DOM document to use for the conversion
168 * @param format
169 * <code>Format</code> instance specifying output style
170 * @param text
171 * <code>Text</code> to format.
172 * @return The input JDOM Text converted to a DOM Text
173 */
174 public org.w3c.dom.Text process(org.w3c.dom.Document basedoc,
175 Format format, Text text);
176
177 /**
178 * This will convert the <code>{@link Comment}</code> using the given DOM
179 * Document to create the resulting DOM Comment.
180 *
181 * @param basedoc
182 * The DOM document to use for the conversion
183 * @param format
184 * <code>Format</code> instance specifying output style
185 * @param comment
186 * <code>Comment</code> to format.
187 * @return The input JDOM Comment converted to a DOM Comment
188 */
189 public org.w3c.dom.Comment process(org.w3c.dom.Document basedoc,
190 Format format, Comment comment);
191
192 /**
193 * This will convert the <code>{@link ProcessingInstruction}</code> using
194 * the given DOM Document to create the resulting DOM ProcessingInstruction.
195 *
196 * @param basedoc
197 * The DOM document to use for the conversion
198 * @param format
199 * <code>Format</code> instance specifying output style
200 * @param pi
201 * <code>ProcessingInstruction</code> to format.
202 * @return The input JDOM ProcessingInstruction converted to a DOM
203 * ProcessingInstruction
204 */
205 public org.w3c.dom.ProcessingInstruction process(
206 org.w3c.dom.Document basedoc, Format format,
207 ProcessingInstruction pi);
208
209 /**
210 * This will convert the <code>{@link EntityRef}</code> using the given DOM
211 * Document to create the resulting DOM EntityReference.
212 *
213 * @param basedoc
214 * The DOM document to use for the conversion
215 * @param format
216 * <code>Format</code> instance specifying output style
217 * @param entity
218 * <code>EntityRef</code> to format.
219 * @return The input JDOM EntityRef converted to a DOM EntityReference
220 */
221 public org.w3c.dom.EntityReference process(org.w3c.dom.Document basedoc,
222 Format format, EntityRef entity);
223
224 /**
225 * This will convert the <code>{@link Attribute}</code> using the given DOM
226 * Document to create the resulting DOM Attr.
227 *
228 * @param basedoc
229 * The DOM document to use for the conversion
230 * @param format
231 * <code>Format</code> instance specifying output style
232 * @param attribute
233 * <code>Attribute</code> to format.
234 * @return The input JDOM Attribute converted to a DOM Attr
235 */
236 public org.w3c.dom.Attr process(org.w3c.dom.Document basedoc,
237 Format format, Attribute attribute);
238
239 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import org.jdom.internal.ArrayCopy;
57 import org.jdom.output.EscapeStrategy;
58 import org.jdom.output.Format;
59 import org.jdom.output.Format.TextMode;
60
61 /**
62 * FormatStack implements a mechanism where the formatting details can be
63 * changed mid-tree, but then get reverted when that tree segment is
64 * complete.
65 * <p>
66 * This class is intended as a working-class for in the various outputter
67 * implementations. It is inly public so that people extending the
68 * Abstract*Processor classes can take advantage of it's functionality.
69 * <p>
70 * The value this class adds is:
71 * <ul>
72 * <li>Fast -
73 * </ul>
74 *
75 * @since JDOM2
76 * @author Rolf Lear
77 */
78 public final class FormatStack {
79
80 private int capacity = 16; // can grow if more than 16 levels in XML
81 private int depth = 0; // current level in XML
82
83 /*
84 * ====================================================================
85 * The following values cannot be changed mid-way through the output
86 * ====================================================================
87 */
88
89 private final TextMode defaultMode; // the base/initial Text mode
90
91 /** The default indent is no spaces (as original document) */
92 private final String indent;
93
94 /** The encoding format */
95 private final String encoding;
96
97 /** New line separator */
98 private final String lineSeparator;
99
100 /**
101 * Whether or not to output the XML declaration - default is
102 * <code>false</code>
103 */
104 private final boolean omitDeclaration;
105
106 /**
107 * Whether or not to output the encoding in the XML declaration -
108 * default is <code>false</code>
109 */
110 private final boolean omitEncoding;
111
112 /**
113 * Whether or not to expand empty elements to
114 * &lt;tagName&gt;&lt;/tagName&gt; - default is <code>false</code>
115 */
116 private final boolean expandEmptyElements;
117
118 /**
119 * Whether or not to output 'specified' Attributes only
120 */
121 private final boolean specifiedAttributesOnly;
122
123 /** entity escape logic */
124 private final EscapeStrategy escapeStrategy;
125
126 /*
127 * ====================================================================
128 * The following values can be changed mid-way through the output, hence
129 * they are arrays.
130 * ====================================================================
131 */
132
133 /** The 'current' accumulated indent */
134 private String[] levelIndent = new String[capacity];
135
136 /** The 'current' End-Of-Line */
137 private String[] levelEOL = new String[capacity];
138
139 /** The padding to put between content items */
140 private String[] levelEOLIndent = new String[capacity];
141
142 /** The padding to put after the last item (typically one less indent) */
143 private String[] termEOLIndent = new String[capacity];
144
145 /**
146 * Whether TrAX output escaping disabling/enabling PIs are ignored or
147 * processed - default is <code>false</code>
148 */
149 private boolean[] ignoreTrAXEscapingPIs = new boolean[capacity];
150
151 /** text handling mode */
152 private TextMode[] mode = new TextMode[capacity];
153
154 /** escape Output logic - can be changed by */
155 private boolean[] escapeOutput = new boolean[capacity];
156
157 /**
158 * Creates a new FormatStack seeded with the specified Format
159 *
160 * @param format
161 * the Format instance to seed the stack with.
162 */
163 public FormatStack(Format format) {
164 indent = format.getIndent();
165 lineSeparator = format.getLineSeparator();
166
167 encoding = format.getEncoding();
168 omitDeclaration = format.getOmitDeclaration();
169 omitEncoding = format.getOmitEncoding();
170 expandEmptyElements = format.getExpandEmptyElements();
171 escapeStrategy = format.getEscapeStrategy();
172 defaultMode = format.getTextMode();
173 specifiedAttributesOnly = format.isSpecifiedAttributesOnly();
174
175 mode[depth] = format.getTextMode();
176 if (mode[depth] == TextMode.PRESERVE) {
177 // undo any special indenting and end-of-line management:
178 levelIndent[depth] = null;
179 levelEOL[depth] = null;
180 levelEOLIndent[depth] = null;
181 termEOLIndent[depth] = null;
182 } else {
183 levelIndent[depth] = format.getIndent() == null
184 ? null : "";
185 levelEOL[depth] = format.getLineSeparator();
186 levelEOLIndent[depth] = levelIndent[depth] == null ?
187 null : levelEOL[depth];
188 termEOLIndent[depth] = levelEOLIndent[depth];
189
190 }
191 ignoreTrAXEscapingPIs[depth] = format.getIgnoreTrAXEscapingPIs();
192 escapeOutput[depth] = true;
193 }
194
195 /**
196 * If the indent strategy changes part way through a stack, we need to
197 * clear the previously calculated reusable 'lower' levels of the stack.
198 */
199 private final void resetReusableIndents() {
200 int d = depth + 1;
201 while (d < levelIndent.length && levelIndent[d] != null) {
202 // all subsequent forays in to lower levels will need to be redone
203 levelIndent[d] = null;
204 d++;
205 }
206 }
207
208 /**
209 * @return the original {@link Format#getIndent()}, may be null
210 */
211 public String getIndent() {
212 return indent;
213 }
214
215 /**
216 * @return the original {@link Format#getLineSeparator()}
217 */
218 public String getLineSeparator() {
219 return lineSeparator;
220 }
221
222 /**
223 * @return the original {@link Format#getEncoding()}
224 */
225 public String getEncoding() {
226 return encoding;
227 }
228
229 /**
230 * @return the original {@link Format#getOmitDeclaration()}
231 */
232 public boolean isOmitDeclaration() {
233 return omitDeclaration;
234 }
235
236 /**
237 * Indicate whether only those Attributes specified in the XML
238 * should be output.
239 * @return true if only the specified Attributes should be output,
240 * false if those Attributes defaulted from the DTD or XML schema
241 * should be output too.
242 */
243 public boolean isSpecifiedAttributesOnly() {
244 return specifiedAttributesOnly;
245 }
246
247 /**
248 * @return the original {@link Format#getOmitEncoding()}
249 */
250 public boolean isOmitEncoding() {
251 return omitEncoding;
252 }
253
254 /**
255 * @return the original {@link Format#getExpandEmptyElements()}
256 */
257 public boolean isExpandEmptyElements() {
258 return expandEmptyElements;
259 }
260
261 /**
262 * @return the original {@link Format#getEscapeStrategy()}
263 */
264 public EscapeStrategy getEscapeStrategy() {
265 return escapeStrategy;
266 }
267
268 /**
269 * @return the current depth's {@link Format#getIgnoreTrAXEscapingPIs()}
270 */
271 public boolean isIgnoreTrAXEscapingPIs() {
272 return ignoreTrAXEscapingPIs[depth];
273 }
274
275 /**
276 * Set the current depth's {@link Format#getIgnoreTrAXEscapingPIs()}
277 *
278 * @param ignoreTrAXEscapingPIs
279 * the boolean value to set.
280 */
281 public void setIgnoreTrAXEscapingPIs(boolean ignoreTrAXEscapingPIs) {
282 this.ignoreTrAXEscapingPIs[depth] = ignoreTrAXEscapingPIs;
283 }
284
285 /**
286 * The escapeOutput flag can be set or unset. When set, Element text and
287 * Attribute values are 'escaped' so that the output is valid XML. When
288 * unset, the Element text and Attribute values are not escaped.
289 *
290 * @return the current depth's escapeOutput flag.
291 */
292 public boolean getEscapeOutput() {
293 return escapeOutput[depth];
294 }
295
296 /**
297 * The escapeOutput flag can be set or unset. When set, Element text and
298 * Attribute values are 'escaped' so that the output is valid XML. When
299 * unset, the Element text and Attribute values are not escaped.
300 *
301 * @param escape
302 * what to set the current level's escapeOutput flag to.
303 */
304 public void setEscapeOutput(boolean escape) {
305 escapeOutput[depth] = escape;
306 }
307
308 /**
309 * @return the TextMode that was originally set for this stack before
310 * any modifications.
311 */
312 public TextMode getDefaultMode() {
313 return defaultMode;
314 }
315
316 /**
317 * @return the current depth's accumulated/maintained indent, may be null
318 */
319 public String getLevelIndent() {
320 return levelIndent[depth];
321 }
322
323 /**
324 * Get the end-of-line indenting sequence for before the first item in an
325 * Element, as well as between subsequent items (but not after the last item)
326 * @return the String EOL sequence followed by an indent. Null if it should
327 * be ignored
328 */
329 public String getPadBetween() {
330 return levelEOLIndent[depth];
331 }
332
333 /**
334 * Get the end-of-line indenting sequence for after the last item in an
335 * Element
336 * @return the String EOL sequence followed by an indent. Null if it should
337 * be ignored
338 */
339 public String getPadLast() {
340 return termEOLIndent[depth];
341 }
342
343 /**
344 * Override the current depth's accumulated line indent.
345 *
346 * @param indent
347 * the indent to set.
348 */
349 public void setLevelIndent(String indent) {
350 this.levelIndent[depth] = indent;
351 levelEOLIndent[depth] = (indent == null || levelEOL[depth] == null) ?
352 null : (levelEOL[depth] + indent);
353 resetReusableIndents();
354 }
355
356 /**
357 * @return the current depth's End-Of-Line sequence, may be null
358 */
359 public String getLevelEOL() {
360 return levelEOL[depth];
361 }
362
363 /**
364 * Set the current depth's End-Of-Line sequence
365 *
366 * @param newline
367 * the new End-Of-Line sequence to set.
368 */
369 public void setLevelEOL(String newline) {
370 this.levelEOL[depth] = newline;
371 resetReusableIndents();
372 }
373
374 /**
375 * @return the current depth's {@link Format#getTextMode()}
376 */
377 public TextMode getTextMode() {
378 return mode[depth];
379 }
380
381 /**
382 * Change the current level's TextMode
383 *
384 * @param mode
385 * the new mode to set.
386 */
387 public void setTextMode(TextMode mode) {
388 if (this.mode[depth] == mode) {
389 return;
390 }
391 this.mode[depth] = mode;
392 switch (mode) {
393 case PRESERVE:
394 levelEOL[depth] = null;
395 levelIndent[depth] = null;
396 levelEOLIndent[depth] = null;
397 termEOLIndent[depth] = null;
398 break;
399 default:
400 levelEOL[depth] = lineSeparator;
401 if (indent == null || lineSeparator == null) {
402 levelEOLIndent[depth] = null;
403 termEOLIndent[depth] = null;
404 } else {
405 if (depth > 0) {
406 final StringBuilder sb = new StringBuilder(indent.length() * depth);
407 for (int i = 1; i < depth; i++) {
408 sb.append(indent);
409 }
410 // the start point was '1', so we are one indent
411 // short, which is just right for the term....
412 termEOLIndent[depth] = lineSeparator + sb.toString();
413 // but we increase it once for the actual indent.
414 sb.append(indent);
415 levelIndent[depth] = sb.toString();
416 } else {
417 termEOLIndent[depth] = lineSeparator;
418 levelIndent[depth] = "";
419 }
420 levelEOLIndent[depth] = lineSeparator + levelIndent[depth];
421 }
422 }
423 resetReusableIndents();
424 }
425
426 /**
427 * Create a new depth level on the stack. The previous level's details
428 * are copied to this level, and the accumulated indent (if any) is
429 * indented further.
430 */
431 public void push() {
432 final int prev = depth++;
433 if (depth >= capacity) {
434 capacity *= 2;
435 levelIndent = ArrayCopy.copyOf(levelIndent, capacity);
436 levelEOL = ArrayCopy.copyOf(levelEOL, capacity);
437 levelEOLIndent = ArrayCopy.copyOf(levelEOLIndent, capacity);
438 termEOLIndent = ArrayCopy.copyOf(termEOLIndent, capacity);
439 ignoreTrAXEscapingPIs = ArrayCopy.copyOf(ignoreTrAXEscapingPIs, capacity);
440 mode = ArrayCopy.copyOf(mode, capacity);
441 escapeOutput = ArrayCopy.copyOf(escapeOutput, capacity);
442 }
443
444 ignoreTrAXEscapingPIs[depth] = ignoreTrAXEscapingPIs[prev];
445 mode[depth] = mode[prev];
446 escapeOutput[depth] = escapeOutput[prev];
447
448 if (levelIndent[prev] == null || levelEOL[prev] == null) {
449 levelIndent[depth] = null;
450 levelEOL[depth] = null;
451 levelEOLIndent[depth] = null;
452 termEOLIndent[depth] = null;
453 } else if (levelIndent[depth] == null) {
454 // we need to build our level details ....
455 // cannot reuse previous ones.
456 levelEOL[depth] = levelEOL[prev];
457 termEOLIndent[depth] = levelEOL[depth] + levelIndent[prev];
458 levelIndent[depth] = levelIndent[prev] + indent;
459 levelEOLIndent[depth] = levelEOL[depth] + levelIndent[depth];
460 }
461 }
462
463 /**
464 * Move back a level on the stack.
465 */
466 public void pop() {
467 // no need to clear previously used members in the stack.
468 // the stack is short-lived, and does not create new instances for
469 // the depth levels, in other words, it does not affect GC and does
470 // not save memory to clear the stack.
471 depth--;
472 }
473
474 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.List;
57
58
59 import org.jdom.Attribute;
60 import org.jdom.CDATA;
61 import org.jdom.Comment;
62 import org.jdom.Content;
63 import org.jdom.DocType;
64 import org.jdom.Document;
65 import org.jdom.Element;
66 import org.jdom.EntityRef;
67 import org.jdom.JDOMException;
68 import org.jdom.ProcessingInstruction;
69 import org.jdom.Text;
70 import org.jdom.output.Format;
71 import org.jdom.output.SAXOutputter;
72
73 /**
74 * This interface provides a base support for the {@link SAXOutputter}.
75 * <p>
76 * People who want to create a custom SAXOutputProcessor for SAXOutputter are
77 * able to implement this interface with the following notes and restrictions:
78 * <ol>
79 * <li>The SAXOutputter will call one, and only one of the
80 * <code>process(SAXTarget,Format,*)</code> methods each time the SAXOutputter
81 * is requested to output some JDOM content. It is thus safe to assume that a
82 * <code>process(SAXTarget,Format,*)</code> method can set up any infrastructure
83 * needed to process the content, and that the SAXOutputter will not re-call
84 * that method, or some other <code>process(SAXTarget,Format,*)</code> method
85 * for the same output sequence.
86 * <li>The process methods should be thread-safe and reentrant: The same
87 * <code>process(SAXTarget,Format,*)</code> method may (will) be called
88 * concurrently from different threads.
89 * </ol>
90 * <p>
91 * The {@link AbstractSAXOutputProcessor} class is a full implementation of this
92 * interface and is fully customisable. People who want a custom SAXOutputter
93 * are encouraged to extend the AbstractSAXOutputProcessor rather than do a full
94 * re-implementation of this interface.
95 *
96 * @see SAXOutputter
97 * @see AbstractSAXOutputProcessor
98 * @since JDOM2
99 * @author Rolf Lear
100 */
101 public interface SAXOutputProcessor {
102
103 /**
104 * This will print the <code>{@link Document}</code> to the given SAXTarget.
105 * <p>
106 * Warning: using your own SAXTarget may cause the outputter's preferred
107 * character encoding to be ignored. If you use encodings other than UTF-8,
108 * we recommend using the method that takes an OutputStream instead.
109 * </p>
110 *
111 * @param out
112 * <code>SAXTarget</code> to use.
113 * @param format
114 * <code>Format</code> instance specifying output style
115 * @param doc
116 * <code>Document</code> to format.
117 * @throws JDOMException
118 * if there is an issue encountered during output.
119 * @throws NullPointerException
120 * if the input content is null
121 */
122 public abstract void process(SAXTarget out, Format format, Document doc)
123 throws JDOMException;
124
125 /**
126 * Print out the <code>{@link DocType}</code>.
127 *
128 * @param out
129 * <code>SAXTarget</code> to use.
130 * @param format
131 * <code>Format</code> instance specifying output style
132 * @param doctype
133 * <code>DocType</code> to output.
134 * @throws JDOMException
135 * if there is an issue encountered during output.
136 * @throws NullPointerException
137 * if the input content is null
138 */
139 public abstract void process(SAXTarget out, Format format, DocType doctype)
140 throws JDOMException;
141
142 /**
143 * Print out an <code>{@link Element}</code>, including its
144 * <code>{@link Attribute}</code>s, and all contained (child) elements, etc.
145 *
146 * @param out
147 * <code>SAXTarget</code> to use.
148 * @param format
149 * <code>Format</code> instance specifying output style
150 * @param element
151 * <code>Element</code> to output.
152 * @throws JDOMException
153 * if there is an issue encountered during output.
154 * @throws NullPointerException
155 * if the input content is null
156 */
157 public abstract void process(SAXTarget out, Format format, Element element)
158 throws JDOMException;
159
160 /**
161 * Print out an <code>{@link Element}</code> encapsulated in start/end
162 * Document SAX events, including its <code>{@link Attribute}</code>s, and
163 * all contained (child) elements, etc.
164 *
165 * @param out
166 * <code>SAXTarget</code> to use.
167 * @param format
168 * <code>Format</code> instance specifying output style
169 * @param element
170 * <code>Element</code> to output.
171 * @throws JDOMException
172 * if there is an issue encountered during output.
173 * @throws NullPointerException
174 * if the input content is null
175 */
176 public void processAsDocument(SAXTarget out, Format format, Element element)
177 throws JDOMException;
178
179 /**
180 * This will handle printing out a list of nodes. This can be useful for
181 * printing the content of an element that contains HTML, like
182 * "&lt;description&gt;JDOM is &lt;b&gt;fun&gt;!&lt;/description&gt;".
183 *
184 * @param out
185 * <code>SAXTarget</code> to use.
186 * @param format
187 * <code>Format</code> instance specifying output style
188 * @param list
189 * <code>List</code> of nodes.
190 * @throws JDOMException
191 * if there is an issue encountered during output.
192 * @throws NullPointerException
193 * if the input list is null or contains null members
194 * @throws ClassCastException
195 * if any of the list members are not {@link Content}
196 */
197 public abstract void process(SAXTarget out, Format format,
198 List<? extends Content> list) throws JDOMException;
199
200 /**
201 * This will handle printing out a list of nodes thats encapsulated in
202 * start/end Document SAX events. This can be useful for printing the
203 * content of an element that contains HTML, like
204 * "&lt;description&gt;JDOM is &lt;b&gt;fun&gt;!&lt;/description&gt;".
205 *
206 * @param out
207 * <code>SAXTarget</code> to use.
208 * @param format
209 * <code>Format</code> instance specifying output style
210 * @param list
211 * <code>List</code> of nodes.
212 * @throws JDOMException
213 * if there is an issue encountered during output.
214 * @throws NullPointerException
215 * if the input list is null or contains null members
216 * @throws ClassCastException
217 * if any of the list members are not {@link Content}
218 */
219 public abstract void processAsDocument(SAXTarget out, Format format,
220 List<? extends Content> list) throws JDOMException;
221
222 /**
223 * Print out a <code>{@link CDATA}</code> node.
224 *
225 * @param out
226 * <code>SAXTarget</code> to use.
227 * @param format
228 * <code>Format</code> instance specifying output style
229 * @param cdata
230 * <code>CDATA</code> to output.
231 * @throws JDOMException
232 * if there is an issue encountered during output.
233 * @throws NullPointerException
234 * if the input content is null
235 */
236 public abstract void process(SAXTarget out, Format format, CDATA cdata)
237 throws JDOMException;
238
239 /**
240 * Print out a <code>{@link Text}</code> node. Perfoms the necessary entity
241 * escaping and whitespace stripping.
242 *
243 * @param out
244 * <code>SAXTarget</code> to use.
245 * @param format
246 * <code>Format</code> instance specifying output style
247 * @param text
248 * <code>Text</code> to output.
249 * @throws JDOMException
250 * if there is an issue encountered during output.
251 * @throws NullPointerException
252 * if the input content is null
253 */
254 public abstract void process(SAXTarget out, Format format, Text text)
255 throws JDOMException;
256
257 /**
258 * Print out a <code>{@link Comment}</code>.
259 *
260 * @param out
261 * <code>SAXTarget</code> to use.
262 * @param format
263 * <code>Format</code> instance specifying output style
264 * @param comment
265 * <code>Comment</code> to output.
266 * @throws JDOMException
267 * if there is an issue encountered during output.
268 * @throws NullPointerException
269 * if the input content is null
270 */
271 public abstract void process(SAXTarget out, Format format, Comment comment)
272 throws JDOMException;
273
274 /**
275 * Print out a <code>{@link ProcessingInstruction}</code>.
276 *
277 * @param out
278 * <code>SAXTarget</code> to use.
279 * @param format
280 * <code>Format</code> instance specifying output style
281 * @param pi
282 * <code>ProcessingInstruction</code> to output.
283 * @throws JDOMException
284 * if there is an issue encountered during output.
285 * @throws NullPointerException
286 * if the input content is null
287 */
288 public abstract void process(SAXTarget out, Format format,
289 ProcessingInstruction pi) throws JDOMException;
290
291 /**
292 * Print out a <code>{@link EntityRef}</code>.
293 *
294 * @param out
295 * <code>SAXTarget</code> to use.
296 * @param format
297 * <code>Format</code> instance specifying output style
298 * @param entity
299 * <code>EntityRef</code> to output.
300 * @throws JDOMException
301 * if there is an issue encountered during output.
302 * @throws NullPointerException
303 * if the input content is null
304 */
305 public abstract void process(SAXTarget out, Format format, EntityRef entity)
306 throws JDOMException;
307
308 }
0 /*--
1
2 Copyright (C) 2011 - 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import org.xml.sax.ContentHandler;
57 import org.xml.sax.DTDHandler;
58 import org.xml.sax.EntityResolver;
59 import org.xml.sax.ErrorHandler;
60 import org.xml.sax.ext.DeclHandler;
61 import org.xml.sax.ext.LexicalHandler;
62
63 import org.jdom.output.JDOMLocator;
64
65 /**
66 * The target for all SAX notifications in this OuputProcessor
67 *
68 * @author Rolf Lear
69 */
70 public final class SAXTarget {
71
72 /**
73 * A locator specific to the SAXOutputter process.
74 * @author Rolf Lear
75 *
76 */
77 public static final class SAXLocator implements JDOMLocator {
78
79 private final String publicid, systemid;
80 private Object node = null ;
81
82 /**
83 * Creates a SAXLocator which implements JDOMLocator
84 * @param publicid This Locator's SystemID
85 * @param systemid This Locator's PublicID
86 */
87 public SAXLocator(String publicid, String systemid) {
88 super();
89 this.publicid = publicid;
90 this.systemid = systemid;
91 }
92
93 @Override
94 public int getColumnNumber() {
95 return -1;
96 }
97
98 @Override
99 public int getLineNumber() {
100 return -1;
101 }
102
103 @Override
104 public String getPublicId() {
105 return publicid;
106 }
107
108 @Override
109 public String getSystemId() {
110 return systemid;
111 }
112
113 @Override
114 public Object getNode() {
115 return node;
116 }
117
118 /**
119 * Set the location on this SAXLocator
120 * @param node The location to set.
121 */
122 public void setNode(Object node) {
123 this.node = node;
124 }
125
126 }
127
128 /** registered <code>ContentHandler</code> */
129 private final ContentHandler contentHandler;
130
131 /** registered <code>ErrorHandler</code> */
132 private final ErrorHandler errorHandler;
133
134 /** registered <code>DTDHandler</code> */
135 private final DTDHandler dtdHandler;
136
137 /** registered <code>EntityResolver</code> */
138 private final EntityResolver entityResolver;
139
140 /** registered <code>LexicalHandler</code> */
141 private final LexicalHandler lexicalHandler;
142
143 /** registered <code>DeclHandler</code> */
144 private final DeclHandler declHandler;
145
146 private final SAXLocator locator;
147
148 /**
149 * Whether to report attribute namespace declarations as xmlns
150 * attributes. Defaults to <code>false</code> as per SAX specifications.
151 *
152 * @see <a href="http://www.megginson.com/SAX/Java/namespaces.html"> SAX
153 * namespace specifications</a>
154 */
155 private final boolean declareNamespaces;
156
157 /**
158 * Whether to report DTD events to DeclHandlers and LexicalHandlers.
159 * Defaults to <code>true</code>.
160 */
161 private final boolean reportDtdEvents;
162
163 /**
164 * Create the collection of handlers for a SAXOutputProcessor
165 *
166 * @param contentHandler
167 * The ContentHandler
168 * @param errorHandler
169 * The ErrorHandler
170 * @param dtdHandler
171 * The DTDHandler
172 * @param entityResolver
173 * The EntityResolver
174 * @param lexicalHandler
175 * The LexicalHandler
176 * @param declHandler
177 * The DeclHandler
178 * @param declareNamespaces
179 * Whether to declare Namespaces
180 * @param reportDtdEvents
181 * Whether to report DTD Events
182 * @param publicID
183 * The public ID (null if none)
184 * @param systemID
185 * The System ID (null if none)
186 */
187 public SAXTarget(ContentHandler contentHandler,
188 ErrorHandler errorHandler, DTDHandler dtdHandler,
189 EntityResolver entityResolver, LexicalHandler lexicalHandler,
190 DeclHandler declHandler, boolean declareNamespaces,
191 boolean reportDtdEvents, String publicID, String systemID) {
192 super();
193 this.contentHandler = contentHandler;
194 this.errorHandler = errorHandler;
195 this.dtdHandler = dtdHandler;
196 this.entityResolver = entityResolver;
197 this.lexicalHandler = lexicalHandler;
198 this.declHandler = declHandler;
199 this.declareNamespaces = declareNamespaces;
200 this.reportDtdEvents = reportDtdEvents;
201 this.locator = new SAXLocator(publicID, systemID);
202
203 }
204
205 /**
206 * @return The target ContentHandler
207 */
208 public ContentHandler getContentHandler() {
209 return contentHandler;
210 }
211
212 /**
213 * @return The target ErrorHandler
214 */
215 public ErrorHandler getErrorHandler() {
216 return errorHandler;
217 }
218
219 /**
220 * @return The target DTDHandler
221 */
222 public DTDHandler getDTDHandler() {
223 return dtdHandler;
224 }
225
226 /**
227 * @return The target EntityResolver
228 */
229 public EntityResolver getEntityResolver() {
230 return entityResolver;
231 }
232
233 /**
234 * @return The target LexicalHandler
235 */
236 public LexicalHandler getLexicalHandler() {
237 return lexicalHandler;
238 }
239
240 /**
241 * @return The target DeclHandler
242 */
243 public DeclHandler getDeclHandler() {
244 return declHandler;
245 }
246
247 /**
248 * @return Whether to declare Namespaces
249 */
250 public boolean isDeclareNamespaces() {
251 return declareNamespaces;
252 }
253
254 /**
255 * @return Whether to report DTD Events
256 */
257 public boolean isReportDTDEvents() {
258 return reportDtdEvents;
259 }
260
261 /**
262 * @return the Locator used for this Output
263 */
264 public SAXLocator getLocator() {
265 return locator;
266 }
267
268 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.List;
57
58 import javax.xml.stream.XMLEventFactory;
59 import javax.xml.stream.util.XMLEventConsumer;
60 import javax.xml.stream.XMLStreamException;
61
62 import org.jdom.Attribute;
63 import org.jdom.CDATA;
64 import org.jdom.Comment;
65 import org.jdom.Content;
66 import org.jdom.DocType;
67 import org.jdom.Document;
68 import org.jdom.Element;
69 import org.jdom.EntityRef;
70 import org.jdom.ProcessingInstruction;
71 import org.jdom.Text;
72 import org.jdom.output.Format;
73 import org.jdom.output.XMLOutputter2;
74
75 /**
76 * This interface provides a base support for the {@link XMLOutputter2}.
77 * <p>
78 * People who want to create a custom XMLOutputProcessor for XMLOutputter are
79 * able to implement this interface with the following notes and restrictions:
80 * <ol>
81 * <li>The XMLOutputter will call one, and only one of the <code>process(XMLEventConsumer,Format,*)</code> methods each
82 * time the XMLOutputter is requested to output some JDOM content. It is thus
83 * safe to assume that a <code>process(XMLEventConsumer,Format,*)</code> method can set up any
84 * infrastructure needed to process the content, and that the XMLOutputter will
85 * not re-call that method, or some other <code>process(XMLEventConsumer,Format,*)</code> method for the same output
86 * sequence.
87 * <li>The process methods should be thread-safe and reentrant: The same
88 * <code>process(XMLEventConsumer,Format,*)</code> method may (will) be called concurrently from different threads.
89 * </ol>
90 * <p>
91 * The {@link AbstractXMLOutputProcessor} class is a full implementation of this
92 * interface and is fully customisable. People who want a custom XMLOutputter
93 * are encouraged to extend the AbstractXMLOutputProcessor rather than do a full
94 * re-implementation of this interface.
95 *
96 * @see XMLOutputter2
97 * @see AbstractXMLOutputProcessor
98 * @since JDOM2
99 * @author Rolf Lear
100 */
101 public interface StAXEventProcessor {
102
103 /**
104 * This will print the <code>{@link Document}</code> to the given XMLEventConsumer.
105 * <p>
106 * Warning: using your own XMLEventConsumer may cause the outputter's preferred
107 * character encoding to be ignored. If you use encodings other than UTF-8,
108 * we recommend using the method that takes an OutputStream instead.
109 * </p>
110 *
111 * @param out
112 * <code>XMLEventConsumer</code> to use.
113 * @param format
114 * <code>Format</code> instance specifying output style
115 * @param eventfactory
116 * <code>XMLEventFactory</code> for creating XMLEvent instances.
117 * @param doc
118 * <code>Document</code> to format.
119 * @throws XMLStreamException
120 * if there's any problem writing.
121 * @throws NullPointerException
122 * if the input content is null
123 */
124 public abstract void process(XMLEventConsumer out, Format format, XMLEventFactory eventfactory, Document doc) throws XMLStreamException;
125
126 /**
127 * Print out the <code>{@link DocType}</code>.
128 *
129 * @param out
130 * <code>XMLEventConsumer</code> to use.
131 * @param format
132 * <code>Format</code> instance specifying output style
133 * @param eventfactory
134 * <code>XMLEventFactory</code> for creating XMLEvent instances.
135 * @param doctype
136 * <code>DocType</code> to output.
137 * @throws XMLStreamException
138 * if there's any problem writing.
139 * @throws NullPointerException
140 * if the input content is null
141 */
142 public abstract void process(XMLEventConsumer out, Format format, XMLEventFactory eventfactory, DocType doctype) throws XMLStreamException;
143
144 /**
145 * Print out an <code>{@link Element}</code>, including its
146 * <code>{@link Attribute}</code>s, and all contained (child) elements, etc.
147 *
148 * @param out
149 * <code>XMLEventConsumer</code> to use.
150 * @param format
151 * <code>Format</code> instance specifying output style
152 * @param eventfactory
153 * <code>XMLEventFactory</code> for creating XMLEvent instances.
154 * @param element
155 * <code>Element</code> to output.
156 * @throws XMLStreamException
157 * if there's any problem writing.
158 * @throws NullPointerException
159 * if the input content is null
160 */
161 public abstract void process(XMLEventConsumer out, Format format, XMLEventFactory eventfactory, Element element) throws XMLStreamException;
162
163 /**
164 * This will handle printing out a list of nodes. This can be useful for
165 * printing the content of an element that contains HTML, like
166 * "&lt;description&gt;JDOM is &lt;b&gt;fun&gt;!&lt;/description&gt;".
167 *
168 * @param out
169 * <code>XMLEventConsumer</code> to use.
170 * @param format
171 * <code>Format</code> instance specifying output style
172 * @param eventfactory
173 * <code>XMLEventFactory</code> for creating XMLEvent instances.
174 * @param list
175 * <code>List</code> of nodes.
176 * @throws XMLStreamException
177 * if there's any problem writing.
178 * @throws NullPointerException
179 * if the input list is null or contains null members
180 * @throws ClassCastException
181 * if any of the list members are not {@link Content}
182 */
183 public abstract void process(XMLEventConsumer out, Format format, XMLEventFactory eventfactory, List<? extends Content> list)
184 throws XMLStreamException;
185
186 /**
187 * Print out a <code>{@link CDATA}</code> node.
188 *
189 * @param out
190 * <code>XMLEventConsumer</code> to use.
191 * @param format
192 * <code>Format</code> instance specifying output style
193 * @param eventfactpry
194 * <code>XMLEventFactory</code> for creating XMLEvent instances.
195 * @param cdata
196 * <code>CDATA</code> to output.
197 * @throws XMLStreamException
198 * if there's any problem writing.
199 * @throws NullPointerException
200 * if the input content is null
201 */
202 public abstract void process(XMLEventConsumer out, Format format, XMLEventFactory eventfactpry, CDATA cdata) throws XMLStreamException;
203
204 /**
205 * Print out a <code>{@link Text}</code> node. Performs the necessary entity
206 * escaping and whitespace stripping.
207 *
208 * @param out
209 * <code>XMLEventConsumer</code> to use.
210 * @param format
211 * <code>Format</code> instance specifying output style
212 * @param eventfactory
213 * <code>XMLEventFactory</code> for creating XMLEvent instances.
214 * @param text
215 * <code>Text</code> to output.
216 * @throws XMLStreamException
217 * if there's any problem writing.
218 * @throws NullPointerException
219 * if the input content is null
220 */
221 public abstract void process(XMLEventConsumer out, Format format, XMLEventFactory eventfactory, Text text) throws XMLStreamException;
222
223 /**
224 * Print out a <code>{@link Comment}</code>.
225 *
226 * @param out
227 * <code>XMLEventConsumer</code> to use.
228 * @param format
229 * <code>Format</code> instance specifying output style
230 * @param eventfactory
231 * <code>XMLEventFactory</code> for creating XMLEvent instances.
232 * @param comment
233 * <code>Comment</code> to output.
234 * @throws XMLStreamException
235 * if there's any problem writing.
236 * @throws NullPointerException
237 * if the input content is null
238 */
239 public abstract void process(XMLEventConsumer out, Format format, XMLEventFactory eventfactory, Comment comment) throws XMLStreamException;
240
241 /**
242 * Print out a <code>{@link ProcessingInstruction}</code>.
243 *
244 * @param out
245 * <code>XMLEventConsumer</code> to use.
246 * @param format
247 * <code>Format</code> instance specifying output style
248 * @param eventfactory
249 * <code>XMLEventFactory</code> for creating XMLEvent instances.
250 * @param pi
251 * <code>ProcessingInstruction</code> to output.
252 * @throws XMLStreamException
253 * if there's any problem writing.
254 * @throws NullPointerException
255 * if the input content is null
256 */
257 public abstract void process(XMLEventConsumer out, Format format, XMLEventFactory eventfactory, ProcessingInstruction pi)
258 throws XMLStreamException;
259
260 /**
261 * Print out a <code>{@link EntityRef}</code>.
262 *
263 * @param out
264 * <code>XMLEventConsumer</code> to use.
265 * @param format
266 * <code>Format</code> instance specifying output style
267 * @param eventfactory
268 * <code>XMLEventFactory</code> for creating XMLEvent instances.
269 * @param entity
270 * <code>EntityRef</code> to output.
271 * @throws XMLStreamException
272 * if there's any problem writing.
273 * @throws NullPointerException
274 * if the input content is null
275 */
276 public abstract void process(XMLEventConsumer out, Format format, XMLEventFactory eventfactory, EntityRef entity) throws XMLStreamException;
277
278 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.List;
57
58 import javax.xml.stream.XMLStreamException;
59 import javax.xml.stream.XMLStreamWriter;
60
61 import org.jdom.Attribute;
62 import org.jdom.CDATA;
63 import org.jdom.Comment;
64 import org.jdom.Content;
65 import org.jdom.DocType;
66 import org.jdom.Document;
67 import org.jdom.Element;
68 import org.jdom.EntityRef;
69 import org.jdom.ProcessingInstruction;
70 import org.jdom.Text;
71 import org.jdom.output.Format;
72 import org.jdom.output.XMLOutputter2;
73
74 /**
75 * This interface provides a base support for the {@link XMLOutputter2}.
76 * <p>
77 * People who want to create a custom XMLOutputProcessor for XMLOutputter are
78 * able to implement this interface with the following notes and restrictions:
79 * <ol>
80 * <li>The XMLOutputter will call one, and only one of the <code>process(XMLStreamWriter,Format,*)</code> methods each
81 * time the XMLOutputter is requested to output some JDOM content. It is thus
82 * safe to assume that a <code>process(XMLStreamWriter,Format,*)</code> method can set up any
83 * infrastructure needed to process the content, and that the XMLOutputter will
84 * not re-call that method, or some other <code>process(XMLStreamWriter,Format,*)</code> method for the same output
85 * sequence.
86 * <li>The process methods should be thread-safe and reentrant: The same
87 * <code>process(XMLStreamWriter,Format,*)</code> method may (will) be called concurrently from different threads.
88 * </ol>
89 * <p>
90 * The {@link AbstractXMLOutputProcessor} class is a full implementation of this
91 * interface and is fully customisable. People who want a custom XMLOutputter
92 * are encouraged to extend the AbstractXMLOutputProcessor rather than do a full
93 * re-implementation of this interface.
94 *
95 * @see XMLOutputter2
96 * @see AbstractXMLOutputProcessor
97 * @since JDOM2
98 * @author Rolf Lear
99 */
100 public interface StAXStreamProcessor {
101
102 /**
103 * This will print the <code>{@link Document}</code> to the given XMLStreamWriter.
104 * <p>
105 * Warning: using your own XMLStreamWriter may cause the outputter's preferred
106 * character encoding to be ignored. If you use encodings other than UTF-8,
107 * we recommend using the method that takes an OutputStream instead.
108 * </p>
109 *
110 * @param out
111 * <code>XMLStreamWriter</code> to use.
112 * @param format
113 * <code>Format</code> instance specifying output style
114 * @param doc
115 * <code>Document</code> to format.
116 * @throws XMLStreamException
117 * if there's any problem writing.
118 * @throws NullPointerException
119 * if the input content is null
120 */
121 public abstract void process(XMLStreamWriter out, Format format, Document doc) throws XMLStreamException;
122
123 /**
124 * Print out the <code>{@link DocType}</code>.
125 *
126 * @param out
127 * <code>XMLStreamWriter</code> to use.
128 * @param format
129 * <code>Format</code> instance specifying output style
130 * @param doctype
131 * <code>DocType</code> to output.
132 * @throws XMLStreamException
133 * if there's any problem writing.
134 * @throws NullPointerException
135 * if the input content is null
136 */
137 public abstract void process(XMLStreamWriter out, Format format, DocType doctype) throws XMLStreamException;
138
139 /**
140 * Print out an <code>{@link Element}</code>, including its
141 * <code>{@link Attribute}</code>s, and all contained (child) elements, etc.
142 *
143 * @param out
144 * <code>XMLStreamWriter</code> to use.
145 * @param format
146 * <code>Format</code> instance specifying output style
147 * @param element
148 * <code>Element</code> to output.
149 * @throws XMLStreamException
150 * if there's any problem writing.
151 * @throws NullPointerException
152 * if the input content is null
153 */
154 public abstract void process(XMLStreamWriter out, Format format, Element element) throws XMLStreamException;
155
156 /**
157 * This will handle printing out a list of nodes. This can be useful for
158 * printing the content of an element that contains HTML, like
159 * "&lt;description&gt;JDOM is &lt;b&gt;fun&gt;!&lt;/description&gt;".
160 *
161 * @param out
162 * <code>XMLStreamWriter</code> to use.
163 * @param format
164 * <code>Format</code> instance specifying output style
165 * @param list
166 * <code>List</code> of nodes.
167 * @throws XMLStreamException
168 * if there's any problem writing.
169 * @throws NullPointerException
170 * if the input list is null or contains null members
171 * @throws ClassCastException
172 * if any of the list members are not {@link Content}
173 */
174 public abstract void process(XMLStreamWriter out, Format format, List<? extends Content> list)
175 throws XMLStreamException;
176
177 /**
178 * Print out a <code>{@link CDATA}</code> node.
179 *
180 * @param out
181 * <code>XMLStreamWriter</code> to use.
182 * @param format
183 * <code>Format</code> instance specifying output style
184 * @param cdata
185 * <code>CDATA</code> to output.
186 * @throws XMLStreamException
187 * if there's any problem writing.
188 * @throws NullPointerException
189 * if the input content is null
190 */
191 public abstract void process(XMLStreamWriter out, Format format, CDATA cdata) throws XMLStreamException;
192
193 /**
194 * Print out a <code>{@link Text}</code> node. Perfoms the necessary entity
195 * escaping and whitespace stripping.
196 *
197 * @param out
198 * <code>XMLStreamWriter</code> to use.
199 * @param format
200 * <code>Format</code> instance specifying output style
201 * @param text
202 * <code>Text</code> to output.
203 * @throws XMLStreamException
204 * if there's any problem writing.
205 * @throws NullPointerException
206 * if the input content is null
207 */
208 public abstract void process(XMLStreamWriter out, Format format, Text text) throws XMLStreamException;
209
210 /**
211 * Print out a <code>{@link Comment}</code>.
212 *
213 * @param out
214 * <code>XMLStreamWriter</code> to use.
215 * @param format
216 * <code>Format</code> instance specifying output style
217 * @param comment
218 * <code>Comment</code> to output.
219 * @throws XMLStreamException
220 * if there's any problem writing.
221 * @throws NullPointerException
222 * if the input content is null
223 */
224 public abstract void process(XMLStreamWriter out, Format format, Comment comment) throws XMLStreamException;
225
226 /**
227 * Print out a <code>{@link ProcessingInstruction}</code>.
228 *
229 * @param out
230 * <code>XMLStreamWriter</code> to use.
231 * @param format
232 * <code>Format</code> instance specifying output style
233 * @param pi
234 * <code>ProcessingInstruction</code> to output.
235 * @throws XMLStreamException
236 * if there's any problem writing.
237 * @throws NullPointerException
238 * if the input content is null
239 */
240 public abstract void process(XMLStreamWriter out, Format format, ProcessingInstruction pi)
241 throws XMLStreamException;
242
243 /**
244 * Print out a <code>{@link EntityRef}</code>.
245 *
246 * @param out
247 * <code>XMLStreamWriter</code> to use.
248 * @param format
249 * <code>Format</code> instance specifying output style
250 * @param entity
251 * <code>EntityRef</code> to output.
252 * @throws XMLStreamException
253 * if there's any problem writing.
254 * @throws NullPointerException
255 * if the input content is null
256 */
257 public abstract void process(XMLStreamWriter out, Format format, EntityRef entity) throws XMLStreamException;
258
259 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.NoSuchElementException;
57
58 import org.jdom.CDATA;
59 import org.jdom.Content;
60 import org.jdom.EntityRef;
61 import org.jdom.Text;
62
63 /**
64 * A model for walking the (potentially formatted) content of an Element.
65 * <p>
66 * Implementations of this class restructure the content to a particular format
67 * and expose the restructured content in this 'Walker' which is a loose
68 * equivalent to an iterator.
69 * <p>
70 * The next() method will return a Content instance (perhaps null) if there
71 * is more content. If the returned content is null, then there will be some
72 * formatted characters available in the text() method. These characters may
73 * need to be represented as CDATA (check the isCDATA() method).
74 * <p>
75 * Not all CDATA and Text nodes need to be reformatted, and as a result they
76 * may be returned as their original CDATA or Text instances instead of using
77 * the formatted text() / isCDATA() mechanism.
78 * <p>
79 * The 'Rules' for the walkers are that no padding is done before the
80 * first content step, and no padding is done after the last content step (but
81 * the first/last content items may be trimmed to the correct format).
82 * Any required padding will be done in plain text (not CDATA) content.
83 * Consecutive CDATA sections may be separated by whitespace text for example.
84 *
85 * @author Rolf Lear
86 *
87 */
88 public interface Walker {
89
90 /**
91 * If all the content in this walker is empty, or if whatever content
92 * is available is Text-like.
93 * <p>
94 * Text-like content is considered to be {@link Text}, {@link CDATA},
95 * {@link EntityRef}, or any (potentially mixed) sequence of these types,
96 * but no other types.
97 *
98 * @return true if there is no content, or all content is Text
99 */
100 public abstract boolean isAllText();
101
102 /**
103 * If all the content is Text-like ({@link #isAllText()} returns true), and
104 * additionally that any content is either Text or CDATA, and that the
105 * values of these Text/CDATA members are all XML Whitespace.
106 * @return true
107 */
108 public abstract boolean isAllWhitespace();
109
110 /**
111 * Behaves similarly to to a regular Iterator
112 *
113 * @return true if there is more content to be processed
114 */
115 public abstract boolean hasNext();
116
117 /**
118 * Similar to an Iterator, but null return values need special treatment.
119 *
120 * @return the next content to be processed, perhaps null if the next
121 * content is re-formatted text of some sort (Text / CDATA).
122 * @throws NoSuchElementException if there is no further content.
123 */
124 public abstract Content next();
125
126 /**
127 * If the previous call to next() returned null, then this will return the
128 * required text to be processed. Check to see whether this text is CDATA
129 * by calling the isCDATA() method.
130 * @return The current text value (null if the previous invocation of next()
131 * returned a non-null value).
132 * @throws IllegalStateException if there was not previous call to next()
133 */
134 public abstract String text();
135
136 /**
137 * If the previous next() method returned null, then this will indicate
138 * whether the current text() value is CDATA or regular Text.
139 * @return true if the current text() is valid, and is CDATA.
140 * @throws IllegalStateException if there was not previous call to next()
141 */
142 public abstract boolean isCDATA();
143
144 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.List;
57
58 import org.jdom.Content;
59 import org.jdom.Verifier;
60
61 /**
62 * This Walker implementation will produce trimmed text content.
63 *
64 * @author Rolf Lear
65 *
66 */
67 public class WalkerNORMALIZE extends AbstractFormattedWalker {
68
69 /**
70 * Create the Trimmed walker instance.
71 * @param content The list of content to format
72 * @param fstack The current stack.
73 * @param escape Whether Text values should be escaped.
74 */
75 public WalkerNORMALIZE(final List<? extends Content> content,
76 final FormatStack fstack, final boolean escape) {
77 super(content, fstack, escape);
78 }
79
80 private boolean isSpaceFirst(String text) {
81 if (text.length() > 0) {
82 return Verifier.isXMLWhitespace(text.charAt(0));
83 }
84 return false;
85 }
86
87 private boolean isSpaceLast(String text) {
88 final int tlen = text.length();
89 if (tlen > 0 && Verifier.isXMLWhitespace(text.charAt(tlen - 1))) {
90 return true;
91 }
92 return false;
93 }
94
95 @Override
96 protected void analyzeMultiText(final MultiText mtext,
97 final int offset, final int len) {
98 boolean needspace = false;
99 boolean between = false;
100
101 String ttext = null;
102 for (int i = 0; i < len; i++) {
103 final Content c = get(offset + i);
104 switch (c.getCType()) {
105 case Text :
106 ttext = c.getValue();
107 if (Verifier.isAllXMLWhitespace(ttext)) {
108 if (between && ttext.length() > 0) {
109 needspace = true;
110 }
111 } else {
112 if (between && (needspace || isSpaceFirst(ttext))) {
113 mtext.appendText(Trim.NONE, " ");
114 }
115 mtext.appendText(Trim.COMPACT, ttext);
116 between = true;
117 needspace = isSpaceLast(ttext);
118 }
119 break;
120 case CDATA :
121 ttext = c.getValue();
122 if (Verifier.isAllXMLWhitespace(ttext)) {
123 if (between && ttext.length() > 0) {
124 needspace = true;
125 }
126 } else {
127 if (between && (needspace || isSpaceFirst(ttext))) {
128 mtext.appendText(Trim.NONE, " ");
129 }
130 mtext.appendCDATA(Trim.COMPACT, ttext);
131 between = true;
132 needspace = isSpaceLast(ttext);
133 }
134 break;
135 case EntityRef:
136 // treat like any other content.
137 // raw.
138 default:
139 ttext = null;
140 if (between && needspace) {
141 mtext.appendText(Trim.NONE, " ");
142 }
143 mtext.appendRaw(c);
144 between = true;
145 needspace = false;
146 break;
147 }
148 }
149 }
150
151 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.Iterator;
57 import java.util.List;
58 import java.util.NoSuchElementException;
59
60 import org.jdom.Content;
61
62 /**
63 * This Walker implementation walks a list of Content in it's original RAW
64 * format. There is no text manipulation, and all content will be returned as
65 * the input type. In other words, next() will never be null, and text() will
66 * always be null.
67 *
68 * @author Rolf Lear
69 *
70 */
71 public class WalkerPRESERVE implements Walker {
72
73 private static final Iterator<Content> EMPTYIT = new Iterator<Content>() {
74 @Override
75 public boolean hasNext() {
76 return false;
77 }
78
79 @Override
80 public Content next() {
81 throw new NoSuchElementException("Cannot call next() on an empty iterator.");
82 }
83
84 @Override
85 public void remove() {
86 throw new UnsupportedOperationException("Cannot remove from an empty iterator.");
87 }
88 };
89
90 private final Iterator<? extends Content> iter;
91 private final boolean alltext;
92
93 /**
94 * Create a Walker that preserves all content in its raw state.
95 * @param content the content to walk.
96 */
97 public WalkerPRESERVE(final List<? extends Content> content) {
98 super();
99 if (content.isEmpty()) {
100 alltext = true;
101 iter = EMPTYIT;
102 } else {
103 iter = content.iterator();
104 alltext = false;
105 // final int len = content.size();
106 // boolean at = true;
107 // for (int i = 0 ; i < len && at ; i++) {
108 // switch (content.get(i).getCType()) {
109 // case Text:
110 // case CDATA:
111 // case EntityRef:
112 // break;
113 // default :
114 // at = false;
115 // break;
116 // }
117 // }
118 // alltext = at;
119 }
120
121 }
122
123 @Override
124 public boolean isAllText() {
125 return alltext;
126 }
127
128 @Override
129 public boolean hasNext() {
130 return iter.hasNext();
131 }
132
133 @Override
134 public Content next() {
135 return iter.next();
136 }
137
138 @Override
139 public String text() {
140 return null;
141 }
142
143 @Override
144 public boolean isCDATA() {
145 return false;
146 }
147
148 @Override
149 public boolean isAllWhitespace() {
150 return alltext;
151 }
152
153 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.List;
57
58 import org.jdom.Content;
59 import org.jdom.Text;
60 import org.jdom.Verifier;
61
62 /**
63 * This Walker implementation will produce trimmed text content.
64 *
65 * @author Rolf Lear
66 *
67 */
68 public class WalkerTRIM extends AbstractFormattedWalker {
69
70 /**
71 * Create the Trimmed walker instance.
72 * @param content The list of content to format
73 * @param fstack The current stack.
74 * @param escape Whether Text values should be escaped.
75 */
76 public WalkerTRIM(final List<? extends Content> content,
77 final FormatStack fstack, final boolean escape) {
78 super(content, fstack, escape);
79 }
80
81 @Override
82 protected void analyzeMultiText(final MultiText mtext,
83 int offset, int len) {
84
85 while (len > 0) {
86 final Content c = get(offset);
87 if (c instanceof Text) {
88 // either Text or CDATA
89 if (!Verifier.isAllXMLWhitespace(c.getValue())) {
90 break;
91 }
92 } else {
93 break;
94 }
95 offset++;
96 len--;
97 }
98
99 while (len > 0) {
100 final Content c = get(offset + len - 1);
101 if (c instanceof Text) {
102 // either Text or CDATA
103 if (!Verifier.isAllXMLWhitespace(c.getValue())) {
104 break;
105 }
106 } else {
107 break;
108 }
109 len--;
110 }
111
112 for (int i = 0; i < len; i++) {
113 Trim trim = Trim.NONE;
114 if (i + 1 == len) {
115 trim = Trim.RIGHT;
116 }
117 if (i == 0) {
118 trim = Trim.LEFT;
119 }
120 if (len == 1) {
121 trim = Trim.BOTH;
122 }
123 final Content c = get(offset + i);
124 switch (c.getCType()) {
125 case Text :
126 mtext.appendText(trim, c.getValue());
127 break;
128 case CDATA :
129 mtext.appendCDATA(trim, c.getValue());
130 break;
131 case EntityRef:
132 // treat like any other content.
133 // raw.
134 default:
135 mtext.appendRaw(c);
136 break;
137 }
138 }
139
140 }
141 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.util.List;
57
58 import org.jdom.Content;
59 import org.jdom.Text;
60 import org.jdom.Verifier;
61
62 /**
63 * This Walker implementation will produce trimmed text content.
64 *
65 * @author Rolf Lear
66 *
67 */
68 public class WalkerTRIM_FULL_WHITE extends AbstractFormattedWalker {
69
70 /**
71 * Create the Trimmed walker instance.
72 * @param content The list of content to format
73 * @param fstack The current stack.
74 * @param escape Whether Text values should be escaped.
75 */
76 public WalkerTRIM_FULL_WHITE(final List<? extends Content> content,
77 final FormatStack fstack, final boolean escape) {
78 super(content, fstack, escape);
79 }
80
81 @Override
82 protected void analyzeMultiText(final MultiText mtext,
83 final int offset, final int len) {
84 int ln = len;
85 while (--ln >= 0) {
86 final Content c = get(offset + ln);
87 if (c instanceof Text) {
88 // either Text or CDATA
89 if (!Verifier.isAllXMLWhitespace(c.getValue())) {
90 break;
91 }
92 } else {
93 break;
94 }
95 }
96 if (ln < 0) {
97 // all whitespace.
98 return;
99 }
100
101 // some non-white, so return all, but merge the sequential Text items.
102 for (int i = 0; i < len; i++) {
103 final Content c = get(offset + i);
104 switch (c.getCType()) {
105 case Text :
106 mtext.appendText(Trim.NONE, c.getValue());
107 break;
108 case CDATA :
109 mtext.appendCDATA(Trim.NONE, c.getValue());
110 break;
111 case EntityRef:
112 // treat like any other content.
113 // raw.
114 default:
115 mtext.appendRaw(c);
116 break;
117 }
118 }
119
120 }
121 }
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.output.support;
55
56 import java.io.IOException;
57 import java.io.Writer;
58 import java.util.List;
59
60 import org.jdom.Attribute;
61 import org.jdom.CDATA;
62 import org.jdom.Comment;
63 import org.jdom.Content;
64 import org.jdom.DocType;
65 import org.jdom.Document;
66 import org.jdom.Element;
67 import org.jdom.EntityRef;
68 import org.jdom.ProcessingInstruction;
69 import org.jdom.Text;
70 import org.jdom.output.Format;
71 import org.jdom.output.XMLOutputter2;
72
73 /**
74 * This interface provides a base support for the {@link XMLOutputter2}.
75 * <p>
76 * People who want to create a custom XMLOutputProcessor for XMLOutputter are
77 * able to implement this interface with the following notes and restrictions:
78 * <ol>
79 * <li>The XMLOutputter will call one, and only one of the <code>process(Writer,Format,*)</code> methods each
80 * time the XMLOutputter is requested to output some JDOM content. It is thus
81 * safe to assume that a <code>process(Writer,Format,*)</code> method can set up any
82 * infrastructure needed to process the content, and that the XMLOutputter will
83 * not re-call that method, or some other <code>process(Writer,Format,*)</code> method for the same output
84 * sequence.
85 * <li>The process methods should be thread-safe and reentrant: The same
86 * <code>process(Writer,Format,*)</code> method may (will) be called concurrently from different threads.
87 * </ol>
88 * <p>
89 * The {@link AbstractXMLOutputProcessor} class is a full implementation of this
90 * interface and is fully customisable. People who want a custom XMLOutputter
91 * are encouraged to extend the AbstractXMLOutputProcessor rather than do a full
92 * re-implementation of this interface.
93 *
94 * @see XMLOutputter2
95 * @see AbstractXMLOutputProcessor
96 * @since JDOM2
97 * @author Rolf Lear
98 */
99 public interface XMLOutputProcessor {
100
101 /**
102 * This will print the <code>{@link Document}</code> to the given Writer.
103 * <p>
104 * Warning: using your own Writer may cause the outputter's preferred
105 * character encoding to be ignored. If you use encodings other than UTF-8,
106 * we recommend using the method that takes an OutputStream instead.
107 * </p>
108 *
109 * @param out
110 * <code>Writer</code> to use.
111 * @param format
112 * <code>Format</code> instance specifying output style
113 * @param doc
114 * <code>Document</code> to format.
115 * @throws IOException
116 * if there's any problem writing.
117 * @throws NullPointerException
118 * if the input content is null
119 */
120 public abstract void process(Writer out, Format format, Document doc) throws IOException;
121
122 /**
123 * Print out the <code>{@link DocType}</code>.
124 *
125 * @param out
126 * <code>Writer</code> to use.
127 * @param format
128 * <code>Format</code> instance specifying output style
129 * @param doctype
130 * <code>DocType</code> to output.
131 * @throws IOException
132 * if there's any problem writing.
133 * @throws NullPointerException
134 * if the input content is null
135 */
136 public abstract void process(Writer out, Format format, DocType doctype) throws IOException;
137
138 /**
139 * Print out an <code>{@link Element}</code>, including its
140 * <code>{@link Attribute}</code>s, and all contained (child) elements, etc.
141 *
142 * @param out
143 * <code>Writer</code> to use.
144 * @param format
145 * <code>Format</code> instance specifying output style
146 * @param element
147 * <code>Element</code> to output.
148 * @throws IOException
149 * if there's any problem writing.
150 * @throws NullPointerException
151 * if the input content is null
152 */
153 public abstract void process(Writer out, Format format, Element element) throws IOException;
154
155 /**
156 * This will handle printing out a list of nodes. This can be useful for
157 * printing the content of an element that contains HTML, like
158 * "&lt;description&gt;JDOM is &lt;b&gt;fun&gt;!&lt;/description&gt;".
159 *
160 * @param out
161 * <code>Writer</code> to use.
162 * @param format
163 * <code>Format</code> instance specifying output style
164 * @param list
165 * <code>List</code> of nodes.
166 * @throws IOException
167 * if there's any problem writing.
168 * @throws NullPointerException
169 * if the input list is null or contains null members
170 * @throws ClassCastException
171 * if any of the list members are not {@link Content}
172 */
173 public abstract void process(Writer out, Format format, List<? extends Content> list)
174 throws IOException;
175
176 /**
177 * Print out a <code>{@link CDATA}</code> node.
178 *
179 * @param out
180 * <code>Writer</code> to use.
181 * @param format
182 * <code>Format</code> instance specifying output style
183 * @param cdata
184 * <code>CDATA</code> to output.
185 * @throws IOException
186 * if there's any problem writing.
187 * @throws NullPointerException
188 * if the input content is null
189 */
190 public abstract void process(Writer out, Format format, CDATA cdata) throws IOException;
191
192 /**
193 * Print out a <code>{@link Text}</code> node. Perfoms the necessary entity
194 * escaping and whitespace stripping.
195 *
196 * @param out
197 * <code>Writer</code> to use.
198 * @param format
199 * <code>Format</code> instance specifying output style
200 * @param text
201 * <code>Text</code> to output.
202 * @throws IOException
203 * if there's any problem writing.
204 * @throws NullPointerException
205 * if the input content is null
206 */
207 public abstract void process(Writer out, Format format, Text text) throws IOException;
208
209 /**
210 * Print out a <code>{@link Comment}</code>.
211 *
212 * @param out
213 * <code>Writer</code> to use.
214 * @param format
215 * <code>Format</code> instance specifying output style
216 * @param comment
217 * <code>Comment</code> to output.
218 * @throws IOException
219 * if there's any problem writing.
220 * @throws NullPointerException
221 * if the input content is null
222 */
223 public abstract void process(Writer out, Format format, Comment comment) throws IOException;
224
225 /**
226 * Print out a <code>{@link ProcessingInstruction}</code>.
227 *
228 * @param out
229 * <code>Writer</code> to use.
230 * @param format
231 * <code>Format</code> instance specifying output style
232 * @param pi
233 * <code>ProcessingInstruction</code> to output.
234 * @throws IOException
235 * if there's any problem writing.
236 * @throws NullPointerException
237 * if the input content is null
238 */
239 public abstract void process(Writer out, Format format, ProcessingInstruction pi)
240 throws IOException;
241
242 /**
243 * Print out a <code>{@link EntityRef}</code>.
244 *
245 * @param out
246 * <code>Writer</code> to use.
247 * @param format
248 * <code>Format</code> instance specifying output style
249 * @param entity
250 * <code>EntityRef</code> to output.
251 * @throws IOException
252 * if there's any problem writing.
253 * @throws NullPointerException
254 * if the input content is null
255 */
256 public abstract void process(Writer out, Format format, EntityRef entity) throws IOException;
257
258 }
0 <body>
1 Classes used to implement output functionality that are not part of the
2 actual Output API, but rather part of the implementation.
3 </body>
0 <body>
1
2 Classes representing the components of an XML document.
3 <p>
4 In addition there are the Exceptions related to JDOM processing and some classes
5 useful for creating and accessing JDOM Content.
6 <p>
7 <h1>Core JDOM classes</h1>
8 All XML in JDOM is represented in the following classes:
9 <ul>
10 <li> Text - regular parsed XML character content (PCDATA).
11 <li> CDATA - unparsed XML text content (can contain &lt; &gt; and &amp;). Note: in JDOM, CDATA class exends Text.
12 <li> Comment - XML Comments
13 <li> EntityRef - Entity References (e.g. &amp;refeg; )
14 <li> ProcessingInstruction - As the name suggests
15 <li> DocType - The relevant details of any DOCTYPE Declaration.
16 <li> Element - An XML element
17 <li> Document - A representation of a complete XML document
18 </ul>
19 In addition to these 8 classes there are also the Attribute and Namespace
20 classes which are used to represent these respective XML structures in Element.
21 In the DOM model the 'Attr' (attribute) class is considered to be a DOM 'Node'.
22 In JDOM this is <strong>not</strong> the case - Attribute is not Content.
23 <p>
24 The XML Structure is embodied in the the concept of Parent JDOM classes and
25 regular JDOM Content. Parent is an interface, and Content is an abstract class.
26 The Document and Element classes are both Parent classes, Text, CDATA, Comment,
27 EntityRef, ProcessingInstruction, DocType and Element are all Content. Note that
28 Element is both Parent and Content.
29 <p>
30 To enforce XML well-formedness, Document is only allowed a restricted set of
31 child content: any number of ProcessingInstructions and Comments, one DocType,
32 and one Element (the 'root' element). Element is allowed any child content
33 except DocType.
34 <p>
35 The NamespaceAware interface identifies those JDOM constructs which are
36 sensitive to Namespaces, which is all 8 core types and also Attribute. In JDOM
37 NamespaceAware classes are able to identify and report the Namespace Context in
38 which they exist.
39 <p>
40
41 <h1>JDOM helper classes</h1>
42 <p>
43 The Verifier is a special class useful in ensuring well-formedness of documents.
44 It contains all the rules for ensuring the JDOM model always has well-formed
45 content.
46 <p>
47 JDOMConstants interface contains a number of constant values that JDOM users may
48 find useful when creating or manipulating JDOM structures. These are in
49 addition to (but some may duplicate) the constants found in the
50 javax.xml.XMLConstants class.
51 <p>
52 The JDOMFactory interface is primarily used when building JDOM documents from
53 some source (SAX, DOM, etc.) using one of the input Builders (SAXBuilder,
54 DOMBuilder, etc.). The default JDOMFactory is the DefaultJDOMFactory).
55 If you have custom JDOM classes or want special treatment for content as it is
56 being created you can supply you own JDOMFactory instance to the input Builder.
57 Typically you would extend the DefaultJDOMFactory for this purpose.
58 The DefaultJDOMFactory ensures all XML rules are followed correctly. The
59 UncheckedJDOMFactory may create JDOM content that does not follow XML
60 well-formedness rules. Use the UncheckedJDOMFactory in places where you are
61 certain the input is correct (perhaps the results of a document parsed by a
62 trusted third-party parser). The UncheckedJDOMParser is only marginally faster
63 than the DefaultJDOMParser.
64 <p>
65
66 </body>
0 /*--
1
2 Copyright (C) 2001-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.transform;
55
56 import java.util.*;
57
58 import javax.xml.transform.sax.*;
59
60 import org.jdom.*;
61 import org.jdom.input.sax.SAXHandler;
62
63 import org.xml.sax.*;
64 import org.xml.sax.ext.*;
65 import org.xml.sax.helpers.*;
66
67 /**
68 * A holder for an XSL Transformation result, generally a list of nodes
69 * although it can be a JDOM Document also. As stated by the XSLT 1.0
70 * specification, the result tree generated by an XSL transformation is not
71 * required to be a well-formed XML document. The result tree may have "any
72 * sequence of nodes as children that would be possible for an
73 * element node".
74 * <p>
75 * The following example shows how to apply an XSL Transformation
76 * to a JDOM document and get the transformation result in the form
77 * of a list of JDOM nodes:
78 * <pre><code>
79 * public static List transform(Document doc, String stylesheet)
80 * throws JDOMException {
81 * try {
82 * Transformer transformer = TransformerFactory.newInstance()
83 * .newTransformer(new StreamSource(stylesheet));
84 * JDOMSource in = new JDOMSource(doc);
85 * JDOMResult out = new JDOMResult();
86 * transformer.transform(in, out);
87 * return out.getResult();
88 * }
89 * catch (TransformerException e) {
90 * throw new JDOMException("XSLT Transformation failed", e);
91 * }
92 * }
93 * </code></pre>
94 *
95 * @see org.jdom.transform.JDOMSource
96 *
97 * @author Laurent Bihanic
98 * @author Jason Hunter
99 */
100 public class JDOMResult extends SAXResult {
101
102 /**
103 * If {@link javax.xml.transform.TransformerFactory#getFeature}
104 * returns <code>true</code> when passed this value as an
105 * argument, the Transformer natively supports JDOM.
106 * <p>
107 * <strong>Note</strong>: This implementation does not override
108 * the {@link SAXResult#FEATURE} value defined by its superclass
109 * to be considered as a SAXResult by Transformer implementations
110 * not natively supporting JDOM.</p>
111 */
112 public final static String JDOM_FEATURE =
113 JDOMConstants.JDOM2_FEATURE_JDOMRESULT;
114
115 /**
116 * The result of a transformation, as set by Transformer
117 * implementations that natively support JDOM, as a JDOM document
118 * or a list of JDOM nodes.
119 */
120 private List<Content> resultlist = null;
121
122 private Document resultdoc = null;
123
124 /**
125 * Whether the application queried the result (as a list or a
126 * document) since it was last set.
127 */
128 private boolean queried = false;
129
130 /**
131 * The custom JDOM factory to use when building the transformation
132 * result or <code>null</code> to use the default JDOM classes.
133 */
134 private JDOMFactory factory = null;
135
136 /**
137 * Public default constructor.
138 */
139 public JDOMResult() {
140 // Allocate custom builder object...
141 DocumentBuilder builder = new DocumentBuilder();
142
143 // And use it as ContentHandler and LexicalHandler.
144 super.setHandler(builder);
145 super.setLexicalHandler(builder);
146 }
147
148 /**
149 * Sets the object(s) produced as result of an XSL Transformation.
150 * <p>
151 * <strong>Note</strong>: This method shall be used by the
152 * {@link javax.xml.transform.Transformer} implementations that
153 * natively support JDOM to directly set the transformation
154 * result rather than considering this object as a
155 * {@link SAXResult}. Applications should <i>not</i> use this
156 * method.</p>
157 *
158 * @param result the result of a transformation as a
159 * {@link java.util.List list} of JDOM nodes
160 * (Elements, Texts, Comments, PIs...).
161 *
162 * @see #getResult
163 */
164 public void setResult(List<Content> result) {
165 this.resultlist = result;
166 this.queried = false;
167 }
168
169 /**
170 * Returns the result of an XSL Transformation as a list of JDOM
171 * nodes.
172 * <p>
173 * If the result of the transformation is a JDOM document,
174 * this method converts it into a list of JDOM nodes; any
175 * subsequent call to {@link #getDocument} will return
176 * <code>null</code>.</p>
177 *
178 * @return the transformation result as a (possibly empty) list of
179 * JDOM nodes (Elements, Texts, Comments, PIs...).
180 */
181 public List<Content> getResult() {
182 List<Content> nodes = Collections.emptyList();
183
184 // Retrieve result from the document builder if not set.
185 this.retrieveResult();
186
187 if (resultlist != null) {
188 nodes = resultlist;
189 }
190 else {
191 if (resultdoc != null && queried == false) {
192 List<Content> content = resultdoc.getContent();
193 nodes = new ArrayList<Content>(content.size());
194
195 while (content.size() != 0)
196 {
197 Content o = content.remove(0);
198 nodes.add(o);
199 }
200 resultlist = nodes;
201 resultdoc = null;
202 }
203 }
204 queried = true;
205
206 return (nodes);
207 }
208
209 /**
210 * Sets the document produced as result of an XSL Transformation.
211 * <p>
212 * <strong>Note</strong>: This method shall be used by the
213 * {@link javax.xml.transform.Transformer} implementations that
214 * natively support JDOM to directly set the transformation
215 * result rather than considering this object as a
216 * {@link SAXResult}. Applications should <i>not</i> use this
217 * method.</p>
218 *
219 * @param document the JDOM document result of a transformation.
220 *
221 * @see #setResult
222 * @see #getDocument
223 */
224 public void setDocument(Document document) {
225 this.resultdoc = document;
226 this.resultlist = null;
227 this.queried = false;
228 }
229
230 /**
231 * Returns the result of an XSL Transformation as a JDOM document.
232 * <p>
233 * If the result of the transformation is a list of nodes,
234 * this method attempts to convert it into a JDOM document. If
235 * successful, any subsequent call to {@link #getResult} will
236 * return an empty list.</p>
237 * <p>
238 * <strong>Warning</strong>: The XSLT 1.0 specification states that
239 * the output of an XSL transformation is not a well-formed XML
240 * document but a list of nodes. Applications should thus use
241 * {@link #getResult} instead of this method or at least expect
242 * <code>null</code> documents to be returned.
243 *
244 * @return the transformation result as a JDOM document or
245 * <code>null</code> if the result of the transformation
246 * can not be converted into a well-formed document.
247 *
248 * @see #getResult
249 */
250 public Document getDocument() {
251 Document doc = null;
252
253 // Retrieve result from the document builder if not set.
254 this.retrieveResult();
255
256 if (resultdoc != null) {
257 doc = resultdoc;
258 }
259 else {
260 if (resultlist != null && (queried == false)) {
261 // Try to create a document from the result nodes
262 try {
263 JDOMFactory f = this.getFactory();
264 if (f == null) { f = new DefaultJDOMFactory(); }
265
266 doc = f.document(null);
267 doc.setContent(resultlist);
268
269 resultdoc = doc;
270 resultlist = null;
271 }
272 catch (RuntimeException ex1) {
273 // Some of the result nodes are not valid children of a
274 // Document node. => return null.
275 return null;
276 }
277 }
278 }
279 queried = true;
280
281 return (doc);
282 }
283
284 /**
285 * Sets a custom JDOMFactory to use when building the
286 * transformation result. Use a custom factory to build the tree
287 * with your own subclasses of the JDOM classes.
288 *
289 * @param factory the custom <code>JDOMFactory</code> to use or
290 * <code>null</code> to use the default JDOM
291 * classes.
292 *
293 * @see #getFactory
294 */
295 public void setFactory(JDOMFactory factory) {
296 this.factory = factory;
297 }
298
299 /**
300 * Returns the custom JDOMFactory used to build the transformation
301 * result.
302 *
303 * @return the custom <code>JDOMFactory</code> used to build the
304 * transformation result or <code>null</code> if the
305 * default JDOM classes are being used.
306 *
307 * @see #setFactory
308 */
309 public JDOMFactory getFactory() {
310 return this.factory;
311 }
312
313 /**
314 * Checks whether a transformation result has been set and, if not,
315 * retrieves the result tree being built by the document builder.
316 */
317 private void retrieveResult() {
318 if (resultlist == null && resultdoc == null) {
319 this.setResult(((DocumentBuilder)this.getHandler()).getResult());
320 }
321 }
322
323 //-------------------------------------------------------------------------
324 // SAXResult overwritten methods
325 //-------------------------------------------------------------------------
326
327 /**
328 * Sets the target to be a SAX2 ContentHandler.
329 *
330 * @param handler Must be a non-null ContentHandler reference.
331 */
332 @Override
333 public void setHandler(ContentHandler handler) {
334 // Do Nothing
335 }
336
337 /**
338 * Sets the SAX2 LexicalHandler for the output.
339 * <p>
340 * This is needed to handle XML comments and the like. If the
341 * lexical handler is not set, an attempt should be made by the
342 * transformer to cast the ContentHandler to a LexicalHandler.</p>
343 *
344 * @param handler A non-null LexicalHandler for
345 * handling lexical parse events.
346 */
347 @Override
348 public void setLexicalHandler(LexicalHandler handler) {
349 // Ignore.
350 }
351
352
353 //=========================================================================
354 // FragmentHandler nested class
355 //=========================================================================
356
357 private static class FragmentHandler extends SAXHandler {
358 /**
359 * A dummy root element required by SAXHandler that can only
360 * cope with well-formed documents.
361 */
362 private Element dummyRoot = new Element("root", null, null);
363
364 /**
365 * Public constructor.
366 * @param factory The Factory to use to create content instances
367 */
368 public FragmentHandler(JDOMFactory factory) {
369 super(factory);
370
371 // Add a dummy root element to the being-built document as XSL
372 // transformation can output node lists instead of well-formed
373 // documents.
374 this.pushElement(dummyRoot);
375 }
376
377 /**
378 * Returns the result of an XSL Transformation.
379 *
380 * @return the transformation result as a (possibly empty) list of
381 * JDOM nodes (Elements, Texts, Comments, PIs...).
382 */
383 public List<Content> getResult() {
384 // Flush remaining text content in case the last text segment is
385 // outside an element.
386 try {
387 this.flushCharacters();
388 }
389 catch (SAXException e) { /* Ignore... */ }
390 return this.getDetachedContent(dummyRoot);
391 }
392
393 /**
394 * Returns the content of a JDOM Element detached from it.
395 *
396 * @param elt the element to get the content from.
397 *
398 * @return a (possibly empty) list of JDOM nodes, detached from
399 * their parent.
400 */
401 private List<Content> getDetachedContent(Element elt) {
402 List<Content> content = elt.getContent();
403 List<Content> nodes = new ArrayList<Content>(content.size());
404
405 while (content.size() != 0)
406 {
407 Content o = content.remove(0);
408 nodes.add(o);
409 }
410 return (nodes);
411 }
412 }
413
414 //=========================================================================
415 // DocumentBuilder inner class
416 //=========================================================================
417
418 private class DocumentBuilder extends XMLFilterImpl
419 implements LexicalHandler {
420 /**
421 * The actual JDOM document builder.
422 */
423 private FragmentHandler saxHandler = null;
424
425 /**
426 * Whether the startDocument event was received. Some XSLT
427 * processors such as Oracle's do not fire this event.
428 */
429 private boolean startDocumentReceived = false;
430
431 /**
432 * Public default constructor.
433 */
434 public DocumentBuilder() { }
435
436 /**
437 * Returns the result of an XSL Transformation.
438 *
439 * @return the transformation result as a (possibly empty) list of
440 * JDOM nodes (Elements, Texts, Comments, PIs...) or
441 * <code>null</code> if no new transformation occurred
442 * since the result of the previous one was returned.
443 */
444 public List<Content> getResult() {
445 List<Content> mresult = null;
446
447 if (this.saxHandler != null) {
448 // Retrieve result from SAX content handler.
449 mresult = this.saxHandler.getResult();
450
451 // Detach the (non-reusable) SAXHandler instance.
452 this.saxHandler = null;
453
454 // And get ready for the next transformation.
455 this.startDocumentReceived = false;
456 }
457 return mresult;
458 }
459
460 private void ensureInitialization() throws SAXException {
461 // Trigger document initialization if XSLT processor failed to
462 // fire the startDocument event.
463 if (this.startDocumentReceived == false) {
464 this.startDocument();
465 }
466 }
467
468 //-----------------------------------------------------------------------
469 // XMLFilterImpl overwritten methods
470 //-----------------------------------------------------------------------
471
472 /**
473 * <i>[SAX ContentHandler interface support]</i> Processes a
474 * start of document event.
475 * <p>
476 * This implementation creates a new JDOM document builder and
477 * marks the current result as "under construction".</p>
478 *
479 * @throws SAXException if any error occurred while creating
480 * the document builder.
481 */
482 @Override
483 public void startDocument() throws SAXException {
484 this.startDocumentReceived = true;
485
486 // Reset any previously set result.
487 setResult(null);
488
489 // Create the actual JDOM document builder and register it as
490 // ContentHandler on the superclass (XMLFilterImpl): this
491 // implementation will take care of propagating the LexicalHandler
492 // events.
493 this.saxHandler = new FragmentHandler(getFactory());
494 super.setContentHandler(this.saxHandler);
495
496 // And propagate event.
497 super.startDocument();
498 }
499
500 /**
501 * <i>[SAX ContentHandler interface support]</i> Receives
502 * notification of the beginning of an element.
503 * <p>
504 * This implementation ensures that startDocument() has been
505 * called prior processing an element.
506 *
507 * @param nsURI the Namespace URI, or the empty string if
508 * the element has no Namespace URI or if
509 * Namespace processing is not being performed.
510 * @param localName the local name (without prefix), or the
511 * empty string if Namespace processing is
512 * not being performed.
513 * @param qName the qualified name (with prefix), or the
514 * empty string if qualified names are not
515 * available.
516 * @param atts The attributes attached to the element. If
517 * there are no attributes, it shall be an
518 * empty Attributes object.
519 *
520 * @throws SAXException if any error occurred while creating
521 * the document builder.
522 */
523 @Override
524 public void startElement(String nsURI, String localName, String qName,
525 Attributes atts) throws SAXException
526 {
527 this.ensureInitialization();
528 super.startElement(nsURI, localName, qName, atts);
529 }
530
531 /**
532 * <i>[SAX ContentHandler interface support]</i> Begins the
533 * scope of a prefix-URI Namespace mapping.
534 */
535 @Override
536 public void startPrefixMapping(String prefix, String uri)
537 throws SAXException {
538 this.ensureInitialization();
539 super.startPrefixMapping(prefix, uri);
540 }
541
542 /**
543 * <i>[SAX ContentHandler interface support]</i> Receives
544 * notification of character data.
545 */
546 @Override
547 public void characters(char ch[], int start, int length)
548 throws SAXException {
549 this.ensureInitialization();
550 super.characters(ch, start, length);
551 }
552
553 /**
554 * <i>[SAX ContentHandler interface support]</i> Receives
555 * notification of ignorable whitespace in element content.
556 */
557 @Override
558 public void ignorableWhitespace(char ch[], int start, int length)
559 throws SAXException {
560 this.ensureInitialization();
561 super.ignorableWhitespace(ch, start, length);
562 }
563
564 /**
565 * <i>[SAX ContentHandler interface support]</i> Receives
566 * notification of a processing instruction.
567 */
568 @Override
569 public void processingInstruction(String target, String data)
570 throws SAXException {
571 this.ensureInitialization();
572 super.processingInstruction(target, data);
573 }
574
575 /**
576 * <i>[SAX ContentHandler interface support]</i> Receives
577 * notification of a skipped entity.
578 */
579 @Override
580 public void skippedEntity(String name) throws SAXException {
581 this.ensureInitialization();
582 super.skippedEntity(name);
583 }
584
585 //-----------------------------------------------------------------------
586 // LexicalHandler interface support
587 //-----------------------------------------------------------------------
588
589 /**
590 * <i>[SAX LexicalHandler interface support]</i> Reports the
591 * start of DTD declarations, if any.
592 *
593 * @param name the document type name.
594 * @param publicId the declared public identifier for the
595 * external DTD subset, or <code>null</code>
596 * if none was declared.
597 * @param systemId the declared system identifier for the
598 * external DTD subset, or <code>null</code>
599 * if none was declared.
600 *
601 * @throws SAXException The application may raise an exception.
602 */
603 @Override
604 public void startDTD(String name, String publicId, String systemId)
605 throws SAXException {
606 this.ensureInitialization();
607 this.saxHandler.startDTD(name, publicId, systemId);
608 }
609
610 /**
611 * <i>[SAX LexicalHandler interface support]</i> Reports the end
612 * of DTD declarations.
613 *
614 * @throws SAXException The application may raise an exception.
615 */
616 @Override
617 public void endDTD() throws SAXException {
618 this.saxHandler.endDTD();
619 }
620
621 /**
622 * <i>[SAX LexicalHandler interface support]</i> Reports the
623 * beginning of some internal and external XML entities.
624 *
625 * @param name the name of the entity. If it is a parameter
626 * entity, the name will begin with '%', and if it
627 * is the external DTD subset, it will be "[dtd]".
628 *
629 * @throws SAXException The application may raise an exception.
630 */
631 @Override
632 public void startEntity(String name) throws SAXException {
633 this.ensureInitialization();
634 this.saxHandler.startEntity(name);
635 }
636
637 /**
638 * <i>[SAX LexicalHandler interface support]</i> Reports the end
639 * of an entity.
640 *
641 * @param name the name of the entity that is ending.
642 *
643 * @throws SAXException The application may raise an exception.
644 */
645 @Override
646 public void endEntity(String name) throws SAXException {
647 this.saxHandler.endEntity(name);
648 }
649
650 /**
651 * <i>[SAX LexicalHandler interface support]</i> Reports the
652 * start of a CDATA section.
653 *
654 * @throws SAXException The application may raise an exception.
655 */
656 @Override
657 public void startCDATA() throws SAXException {
658 this.ensureInitialization();
659 this.saxHandler.startCDATA();
660 }
661
662 /**
663 * <i>[SAX LexicalHandler interface support]</i> Reports the end
664 * of a CDATA section.
665 *
666 * @throws SAXException The application may raise an exception.
667 */
668 @Override
669 public void endCDATA() throws SAXException {
670 this.saxHandler.endCDATA();
671 }
672
673 /**
674 * <i>[SAX LexicalHandler interface support]</i> Reports an XML
675 * comment anywhere in the document.
676 *
677 * @param ch an array holding the characters in the comment.
678 * @param start the starting position in the array.
679 * @param length the number of characters to use from the array.
680 *
681 * @throws SAXException The application may raise an exception.
682 */
683 @Override
684 public void comment(char ch[], int start, int length)
685 throws SAXException {
686 this.ensureInitialization();
687 this.saxHandler.comment(ch, start, length);
688 }
689 }
690 }
691
0 /*--
1
2 Copyright (C) 2001-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.transform;
55
56 import java.io.InputStream;
57 import java.io.Reader;
58 import java.io.StringReader;
59 import java.util.ArrayList;
60 import java.util.List;
61
62 import javax.xml.transform.sax.SAXSource;
63
64 import org.jdom.Content;
65 import org.jdom.Document;
66 import org.jdom.Element;
67 import org.jdom.JDOMConstants;
68 import org.jdom.JDOMException;
69 import org.jdom.output.SAXOutputter;
70 import org.jdom.output.XMLOutputter2;
71 import org.xml.sax.EntityResolver;
72 import org.xml.sax.InputSource;
73 import org.xml.sax.SAXException;
74 import org.xml.sax.SAXNotSupportedException;
75 import org.xml.sax.XMLFilter;
76 import org.xml.sax.XMLReader;
77
78 /**
79 * A holder for an XML Transformation source: a Document, Element, or list of
80 * nodes.
81 * <p>
82 * The is provides input to a
83 * {@link javax.xml.transform.Transformer JAXP TrAX Transformer}.
84 * <p>
85 * The following example shows how to apply an XSL Transformation
86 * to a JDOM document and get the transformation result in the form
87 * of a list of JDOM nodes:
88 * <pre><code>
89 * public static List transform(Document doc, String stylesheet)
90 * throws JDOMException {
91 * try {
92 * Transformer transformer = TransformerFactory.newInstance()
93 * .newTransformer(new StreamSource(stylesheet));
94 * JDOMSource in = new JDOMSource(doc);
95 * JDOMResult out = new JDOMResult();
96 * transformer.transform(in, out);
97 * return out.getResult();
98 * }
99 * catch (TransformerException e) {
100 * throw new JDOMException("XSLT Transformation failed", e);
101 * }
102 * }
103 * </code></pre>
104 *
105 * @see org.jdom.transform.JDOMResult
106 *
107 * @author Laurent Bihanic
108 * @author Jason Hunter
109 */
110 public class JDOMSource extends SAXSource {
111
112 /**
113 * If {@link javax.xml.transform.TransformerFactory#getFeature}
114 * returns <code>true</code> when passed this value as an
115 * argument, the Transformer natively supports JDOM.
116 * <p>
117 * <strong>Note</strong>: This implementation does not override
118 * the {@link SAXSource#FEATURE} value defined by its superclass
119 * to be considered as a SAXSource by Transformer implementations
120 * not natively supporting JDOM.
121 * </p>
122 */
123 public final static String JDOM_FEATURE = JDOMConstants.JDOM2_FEATURE_JDOMSOURCE;
124
125
126 /**
127 * The XMLReader object associated to this source or
128 * <code>null</code> if no XMLReader has yet been requested.
129 *
130 * @see #getXMLReader
131 */
132 private XMLReader xmlReader = null;
133
134 /**
135 * Optional entity resolver associated to the source of
136 * this document or <code>null</code> if no EntityResolver
137 * was supplied with this JDOMSource.
138 *
139 * @see #buildDocumentReader()
140 */
141 private EntityResolver resolver = null;
142
143 /**
144 * Creates a JDOM TrAX source wrapping a JDOM document.
145 *
146 * @param source the JDOM document to use as source for the
147 * transformations
148 *
149 * @throws IllegalArgumentException if <code>source</code> is
150 * <code>null</code>.
151 */
152 public JDOMSource(Document source) {
153 this(source, null);
154 }
155
156 /**
157 * Creates a JDOM TrAX source wrapping a list of JDOM nodes.
158 *
159 * @param source the JDOM nodes to use as source for the
160 * transformations
161 *
162 * @throws IllegalArgumentException if <code>source</code> is
163 * <code>null</code>.
164 */
165 public JDOMSource(List<? extends Content> source) {
166 setNodes(source);
167 }
168
169 /**
170 * Creates a JDOM TrAX source wrapping a JDOM element.
171 *
172 * @param source the JDOM element to use as source for the
173 * transformations
174 *
175 * @throws IllegalArgumentException if <code>source</code> is
176 * <code>null</code>.
177 */
178 public JDOMSource(Element source) {
179 List<Content> nodes = new ArrayList<Content>();
180 nodes.add(source);
181
182 setNodes(nodes);
183 }
184
185 /**
186 * Creates a JDOM TrAX source wrapping a JDOM element with an
187 * associated EntityResolver to resolve external entities.
188 *
189 * @param source The JDOM Element to use as source for the
190 * transformations
191 *
192 * @param resolver Entity resolver to use for the source
193 * transformation
194 *
195 * @throws IllegalArgumentException if<code>source</code> is
196 * <code>null</code>
197 */
198 public JDOMSource(Document source, EntityResolver resolver) {
199 setDocument(source);
200 this.resolver = resolver;
201 if (source != null && source.getBaseURI() != null) {
202 super.setSystemId(source.getBaseURI());
203 }
204 }
205
206 /**
207 * Sets the source document used by this TrAX source.
208 *
209 * @param source the JDOM document to use as source for the
210 * transformations
211 *
212 * @throws IllegalArgumentException if <code>source</code> is
213 * <code>null</code>.
214 *
215 * @see #getDocument
216 */
217 public void setDocument(Document source) {
218 super.setInputSource(new JDOMInputSource(source));
219 }
220
221 /**
222 * Returns the source document used by this TrAX source.
223 *
224 * @return the source document used by this TrAX source or
225 * <code>null</code> if the source is a node list.
226 *
227 * @see #setDocument
228 */
229 public Document getDocument() {
230 Object src = ((JDOMInputSource)getInputSource()).getSource();
231 Document doc = null;
232
233 if (src instanceof Document) {
234 doc = (Document)src;
235 }
236 return doc;
237 }
238
239 /**
240 * Sets the source node list used by this TrAX source.
241 *
242 * @param source the JDOM nodes to use as source for the
243 * transformations
244 *
245 * @throws IllegalArgumentException if <code>source</code> is
246 * <code>null</code>.
247 *
248 * @see #getNodes
249 */
250 public void setNodes(List<? extends Content> source) {
251 super.setInputSource(new JDOMInputSource(source));
252 }
253
254 /**
255 * Returns the source node list used by this TrAX source.
256 *
257 * @return the source node list used by this TrAX source or
258 * <code>null</code> if the source is a JDOM document.
259 *
260 * @see #setDocument
261 */
262 public List<? extends Content> getNodes() {
263 return ((JDOMInputSource)getInputSource()).getListSource();
264 }
265
266
267 //-------------------------------------------------------------------------
268 // SAXSource overwritten methods
269 //-------------------------------------------------------------------------
270
271 /**
272 * Sets the SAX InputSource to be used for the Source.
273 * <p>
274 * As this implementation only supports JDOM document as data
275 * source, this method always throws an
276 * {@link UnsupportedOperationException}.
277 * </p>
278 *
279 * @param inputSource a valid InputSource reference.
280 *
281 * @throws UnsupportedOperationException always!
282 */
283 @Override
284 public void setInputSource(InputSource inputSource)
285 throws UnsupportedOperationException {
286 throw new UnsupportedOperationException();
287 }
288
289 /**
290 * Set the XMLReader to be used for the Source.
291 * <p>
292 * As this implementation only supports JDOM document as data
293 * source, this method throws an
294 * {@link UnsupportedOperationException} if the provided reader
295 * object does not implement the SAX {@link XMLFilter}
296 * interface. Otherwise, the JDOM document reader will be
297 * attached as parent of the filter chain.</p>
298 *
299 * @param reader a valid XMLReader or XMLFilter reference.
300 *
301 * @throws UnsupportedOperationException if <code>reader</code>
302 * is not a SAX
303 * {@link XMLFilter}.
304 * @see #getXMLReader
305 */
306 @Override
307 public void setXMLReader(XMLReader reader)
308 throws UnsupportedOperationException {
309 if (reader instanceof XMLFilter) {
310 // Connect the filter chain to a document reader.
311 XMLFilter filter = (XMLFilter)reader;
312 while (filter.getParent() instanceof XMLFilter) {
313 filter = (XMLFilter)(filter.getParent());
314 }
315 filter.setParent(buildDocumentReader());
316
317 // Read XML data from filter chain.
318 this.xmlReader = reader;
319 }
320 else {
321 throw new UnsupportedOperationException();
322 }
323 }
324
325 /**
326 * Returns the XMLReader to be used for the Source.
327 * <p>
328 * This implementation returns a specific XMLReader reading
329 * the XML data from the source JDOM document.
330 * </p>
331 *
332 * @return an XMLReader reading the XML data from the source
333 * JDOM document.
334 */
335 @Override
336 public XMLReader getXMLReader() {
337 if (this.xmlReader == null) {
338 this.xmlReader = buildDocumentReader();
339 }
340 return this.xmlReader;
341 }
342
343 /**
344 * Build an XMLReader to be used for the source. This will
345 * create a new instance of DocumentReader with an
346 * EntityResolver instance if available.
347 *
348 * @return XMLReader reading the XML data from the source
349 * JDOM document with an optional EntityResolver
350 */
351 private XMLReader buildDocumentReader() {
352 DocumentReader reader = new DocumentReader();
353 if (resolver != null)
354 reader.setEntityResolver(resolver);
355 return reader;
356 }
357
358 //=========================================================================
359 // JDOMInputSource nested class
360 //=========================================================================
361
362 /**
363 * A subclass of the SAX InputSource interface that wraps a JDOM
364 * Document.
365 * <p>
366 * This class is nested in JDOMSource as it is not intented to
367 * be used independently of its friend: DocumentReader.
368 * </p>
369 *
370 * @see org.jdom.Document
371 */
372 private static class JDOMInputSource extends InputSource {
373 /**
374 * The source as a JDOM document or a list of JDOM nodes.
375 */
376 private Document docsource = null;
377
378 /**
379 * The source as a JDOM document or a list of JDOM nodes.
380 */
381 private List<? extends Content> listsource = null;
382 /**
383 * Builds a InputSource wrapping the specified JDOM Document.
384 *
385 * @param document the source document.
386 */
387 public JDOMInputSource(Document document) {
388 this.docsource = document;
389 }
390
391 /**
392 * Builds a InputSource wrapping a list of JDOM nodes.
393 *
394 * @param nodes the source JDOM nodes.
395 */
396 public JDOMInputSource(List<? extends Content> nodes) {
397 this.listsource = nodes;
398 }
399
400 /**
401 * Returns the source.
402 *
403 * @return the source as a JDOM document or a list of JDOM nodes.
404 */
405 public Object getSource() {
406 return docsource == null ? listsource : docsource;
407 }
408
409 //-------------------------------------------------------------------------
410 // InputSource overwritten methods
411 //-------------------------------------------------------------------------
412
413 /**
414 * Sets the character stream for this input source.
415 * <p>
416 * This implementation always throws an
417 * {@link UnsupportedOperationException} as the only source
418 * stream supported is the source JDOM document.
419 * </p>
420 *
421 * @param characterStream a character stream containing
422 * an XML document.
423 *
424 * @throws UnsupportedOperationException always!
425 */
426 @Override
427 public void setCharacterStream(Reader characterStream)
428 throws UnsupportedOperationException {
429 throw new UnsupportedOperationException();
430 }
431
432 /**
433 * Gets the character stream for this input source.
434 * <p>
435 * Note that this method is only provided to make this
436 * InputSource implementation acceptable by any XML
437 * parser. As it generates an in-memory string representation
438 * of the JDOM document, it is quite inefficient from both
439 * speed and memory consumption points of view.
440 * </p>
441 *
442 * @return a Reader to a string representation of the
443 * source JDOM document.
444 */
445 @Override
446 public Reader getCharacterStream() {
447 Reader reader = null;
448
449 if (docsource != null) {
450 // Get an in-memory string representation of the document
451 // and return a reader on it.
452 reader = new StringReader(
453 new XMLOutputter2().outputString(docsource));
454 }
455 else if (listsource != null) {
456 reader = new StringReader(
457 new XMLOutputter2().outputString(listsource));
458 }
459 // Else: No source, no reader!
460 return reader;
461 }
462 /**
463 * Sets the byte stream for this input source.
464 * <p>
465 * This implementation always throws an
466 * {@link UnsupportedOperationException} as the only source
467 * stream supported is the source JDOM document.
468 * </p>
469 *
470 * @param byteStream a byte stream containing
471 * an XML document.
472 *
473 * @throws UnsupportedOperationException always!
474 */
475 @Override
476 public void setByteStream(InputStream byteStream)
477 throws UnsupportedOperationException {
478 throw new UnsupportedOperationException();
479 }
480
481 public Document getDocumentSource() {
482 return docsource;
483 }
484
485 public List<? extends Content> getListSource() {
486 // TODO Auto-generated method stub
487 return listsource;
488 }
489
490 }
491
492 //=========================================================================
493 // DocumentReader nested class
494 //=========================================================================
495
496 /**
497 * An implementation of the SAX2 XMLReader interface that presents
498 * a SAX view of a JDOM Document. The actual generation of the
499 * SAX events is delegated to JDOM's SAXOutputter.
500 *
501 * @see org.jdom.Document
502 * @see org.jdom.output.SAXOutputter
503 */
504 private static class DocumentReader extends SAXOutputter
505 implements XMLReader {
506 /**
507 * Public default constructor.
508 */
509 public DocumentReader() {
510 super();
511 }
512
513 //----------------------------------------------------------------------
514 // SAX XMLReader interface support
515 //----------------------------------------------------------------------
516
517 /**
518 * Parses an XML document from a system identifier (URI).
519 * <p>
520 * This implementation does not support reading XML data from
521 * system identifiers, only from JDOM documents. Hence,
522 * this method always throws a {@link SAXNotSupportedException}.
523 * </p>
524 *
525 * @param systemId the system identifier (URI).
526 *
527 * @throws SAXNotSupportedException always!
528 */
529 @Override
530 public void parse(String systemId) throws SAXNotSupportedException {
531 throw new SAXNotSupportedException(
532 "Only JDOM Documents are supported as input");
533 }
534
535 /**
536 * Parses an XML document.
537 * <p>
538 * The methods accepts only <code>JDOMInputSource</code>s
539 * instances as input sources.
540 * </p>
541 *
542 * @param input the input source for the top-level of the
543 * XML document.
544 *
545 * @throws SAXException any SAX exception,
546 * possibly wrapping
547 * another exception.
548 * @throws SAXNotSupportedException if the input source does
549 * not wrap a JDOM document.
550 */
551 @Override
552 public void parse(InputSource input) throws SAXException {
553 if (input instanceof JDOMInputSource) {
554 try {
555 Document docsource = ((JDOMInputSource)input).getDocumentSource();
556 if (docsource != null) {
557 this.output(docsource);
558 }
559 else {
560 this.output(((JDOMInputSource)input).getListSource());
561 }
562 }
563 catch (JDOMException e) {
564 throw new SAXException(e.getMessage(), e);
565 }
566 }
567 else {
568 throw new SAXNotSupportedException(
569 "Only JDOM Documents are supported as input");
570 }
571 }
572 }
573 }
574
0 /*--
1
2 Copyright (C) 2003-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.transform;
55
56 import org.jdom.JDOMException;
57
58 /**
59 * Thrown when an XSL stylesheet fails to compile or an XSL transform fails
60 *
61 * @author Jason Hunter
62 */
63 public class XSLTransformException extends JDOMException {
64
65 /**
66 * Standard JDOM2 Exception Serialization. Default.
67 */
68 private static final long serialVersionUID = 200L;
69
70 /**
71 * A new and default XSLTransformException
72 */
73 public XSLTransformException() {
74 }
75
76 /**
77 * A new XSLTransformException with the specified message
78 * @param message The message for the exception
79 */
80 public XSLTransformException(String message) {
81 super(message);
82 }
83
84 /**
85 * A new XSLTransformException with the specified message and cause
86 * @param message The message for the exception
87 * @param cause This exception's cause.
88 */
89 public XSLTransformException(String message, Exception cause) {
90 super(message, cause);
91 }
92 }
0 /*--
1
2 Copyright (C) 2001-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.transform;
55
56 import java.util.*;
57 import java.io.*;
58 import javax.xml.transform.*;
59 import javax.xml.transform.stream.StreamSource;
60 import org.jdom.*;
61 import org.xml.sax.EntityResolver;
62
63 /**
64 * A convenience class to handle simple transformations. The JAXP TrAX classes
65 * have more bells and whistles and can be used with {@link JDOMSource} and
66 * {@link JDOMResult} for advanced uses. This class handles the common case and
67 * presents a simple interface. XSLTransformer is thread safe and may be
68 * used from multiple threads.
69 *
70 * <pre><code>
71 * XSLTransformer transformer = new XSLTransformer("file.xsl");
72 *
73 * Document x2 = transformer.transform(x); // x is a Document
74 * Document y2 = transformer.transform(y); // y is a Document
75 * </code></pre>
76 *
77 * JDOM relies on TrAX to perform the transformation.
78 * The <code>javax.xml.transform.TransformerFactory</code> Java system property
79 * determines which XSLT engine TrAX uses. Its value should be
80 * the fully qualified name of the implementation of the abstract
81 * <code>javax.xml.transform.TransformerFactory</code> class.
82 * Values of this property for popular XSLT processors include:
83 * </p>
84 * <ul><li>Saxon 6.x: <code>com.icl.saxon.TransformerFactoryImpl</code></li>
85 * <li>Saxon 7.x: <code>net.sf.saxon.TransformerFactoryImpl</code></li>
86 * <li>Xalan: <code>org.apache.xalan.processor.TransformerFactoryImpl</code></li>
87 * <li>jd.xslt: <code>jd.xml.xslt.trax.TransformerFactoryImpl</code></li>
88 * <li>Oracle: <code>oracle.xml.jaxp.JXSAXTransformerFactory</code></li>
89 * </ul>
90 * <p>
91 * This property can be set in all the usual ways a Java system property
92 * can be set. TrAX picks from them in this order:</p>
93 * <ol>
94 * <li> Invoking <code>System.setProperty( "javax.xml.transform.TransformerFactory",
95 * "<i><code>classname</code></i>")</code></li>
96 * <li>The value specified at the command line using the
97 * <tt>-Djavax.xml.transform.TransformerFactory=<i><code>classname</code></i></tt>
98 * option to the <b>java</b> interpreter</li>
99 * <li>The class named in the <code>lib/jaxp.properties</code> properties file
100 * in the JRE directory, in a line like this one:
101 * <pre>javax.xml.parsers.DocumentBuilderFactory=<i><code>classname</code></i></pre></li>
102 * <li>The class named in the
103 * <code>META-INF/services/javax.xml.transform.TransformerFactory</code> file
104 * in the JAR archives available to the runtime</li>
105 * <li>Finally, if all of the above options fail,
106 * a default implementation is chosen. In Sun's JDK 1.4, this is
107 * Xalan 2.2d10. </li>
108 * </ol>
109
110 * @author Jason Hunter
111 * @author Elliotte Rusty Harold
112 */
113 public class XSLTransformer {
114
115 private Templates templates;
116
117 /**
118 * The custom JDOM factory to use when building the transformation
119 * result or <code>null</code> to use the default JDOM classes.
120 */
121 private JDOMFactory factory = null;
122
123 // Internal constructor to support the other constructors
124 private XSLTransformer(Source stylesheet) throws XSLTransformException {
125 try {
126 templates = TransformerFactory.newInstance()
127 .newTemplates(stylesheet);
128 }
129 catch (TransformerException e) {
130 throw new XSLTransformException("Could not construct XSLTransformer", e);
131 }
132 }
133
134 /**
135 * Creates a transformer for a given stylesheet system id.
136 *
137 * @param stylesheetSystemId source stylesheet as a Source object
138 * @throws XSLTransformException if there's a problem in the TrAX back-end
139 */
140 public XSLTransformer(String stylesheetSystemId) throws XSLTransformException {
141 this(new StreamSource(stylesheetSystemId));
142 }
143
144 /**
145 * <p>
146 * This will create a new <code>XSLTransformer</code> by
147 * reading the stylesheet from the specified
148 * <code>InputStream</code>.
149 * </p>
150 *
151 * @param stylesheet <code>InputStream</code> from which the stylesheet is read.
152 * @throws XSLTransformException when an IOException, format error, or
153 * something else prevents the stylesheet from being compiled
154 */
155 public XSLTransformer(InputStream stylesheet) throws XSLTransformException {
156 this(new StreamSource(stylesheet));
157 }
158
159 /**
160 * <p>
161 * This will create a new <code>XSLTransformer</code> by
162 * reading the stylesheet from the specified
163 * <code>Reader</code>.
164 * </p>
165 *
166 * @param stylesheet <code>Reader</code> from which the stylesheet is read.
167 * @throws XSLTransformException when an IOException, format error, or
168 * something else prevents the stylesheet from being compiled
169 */
170 public XSLTransformer(Reader stylesheet) throws XSLTransformException {
171 this(new StreamSource(stylesheet));
172 }
173
174 /**
175 * <p>
176 * This will create a new <code>XSLTransformer</code> by
177 * reading the stylesheet from the specified
178 * <code>File</code>.
179 * </p>
180 *
181 * @param stylesheet <code>File</code> from which the stylesheet is read.
182 * @throws XSLTransformException when an IOException, format error, or
183 * something else prevents the stylesheet from being compiled
184 */
185 public XSLTransformer(File stylesheet) throws XSLTransformException {
186 this(new StreamSource(stylesheet));
187 }
188
189 /**
190 * <p>
191 * This will create a new <code>XSLTransformer</code> by
192 * reading the stylesheet from the specified
193 * <code>Document</code>.
194 * </p>
195 *
196 * @param stylesheet <code>Document</code> containing the stylesheet.
197 * @throws XSLTransformException when the supplied <code>Document</code>
198 * is not syntactically correct XSLT
199 */
200 public XSLTransformer(Document stylesheet) throws XSLTransformException {
201 this(new JDOMSource(stylesheet));
202 }
203
204 /**
205 * Transforms the given input nodes to a list of output nodes.
206 *
207 * @param inputNodes input nodes
208 * @return transformed output nodes
209 * @throws XSLTransformException if there's a problem in the transformation
210 */
211 public List<Content> transform(List<Content> inputNodes) throws XSLTransformException {
212 JDOMSource source = new JDOMSource(inputNodes);
213 JDOMResult result = new JDOMResult();
214 result.setFactory(factory); // null ok
215 try {
216 templates.newTransformer().transform(source, result);
217 return result.getResult();
218 }
219 catch (TransformerException e) {
220 throw new XSLTransformException("Could not perform transformation", e);
221 }
222 }
223
224 /**
225 * Transforms the given document to an output document.
226 *
227 * @param inputDoc input document
228 * @return transformed output document
229 * @throws XSLTransformException if there's a problem in the transformation
230 */
231 public Document transform(Document inputDoc) throws XSLTransformException {
232 return transform(inputDoc, null);
233 }
234
235 /**
236 * Transforms the given document to an output document.
237 *
238 * @param inputDoc input document
239 * @param resolver entity resolver for the input document
240 * @return transformed output document
241 * @throws XSLTransformException if there's a problem in the transformation
242 */
243 public Document transform(Document inputDoc, EntityResolver resolver) throws XSLTransformException {
244 JDOMSource source = new JDOMSource(inputDoc, resolver);
245 JDOMResult result = new JDOMResult();
246 result.setFactory(factory); // null ok
247 try {
248 templates.newTransformer().transform(source, result);
249 return result.getDocument();
250 }
251 catch (TransformerException e) {
252 throw new XSLTransformException("Could not perform transformation", e);
253 }
254 }
255
256 /**
257 * Sets a custom JDOMFactory to use when building the
258 * transformation result. Use a custom factory to build the tree
259 * with your own subclasses of the JDOM classes.
260 *
261 * @param factory the custom <code>JDOMFactory</code> to use or
262 * <code>null</code> to use the default JDOM
263 * classes.
264 *
265 * @see #getFactory
266 */
267 public void setFactory(JDOMFactory factory) {
268 this.factory = factory;
269 }
270
271 /**
272 * Returns the custom JDOMFactory used to build the transformation
273 * result.
274 *
275 * @return the custom <code>JDOMFactory</code> used to build the
276 * transformation result or <code>null</code> if the
277 * default JDOM classes are being used.
278 *
279 * @see #setFactory
280 */
281 public JDOMFactory getFactory() {
282 return this.factory;
283 }
284 }
0 <body>
1
2 Classes to help with transformations, based on the JAXP TrAX classes.
3 JDOMTransformer supports simple transformations with one line of code.
4 Advanced features are available with the JDOMSource and JDOMResult classes
5 that interface with TrAX.
6
7 </body>
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.util;
55
56 import java.util.Iterator;
57
58 /**
59 * An interface that represents both a <code>java.util.Iterator</code>
60 * and a <code>java.lang.Iterable</code>.
61 * <p>
62 * JDOM 1.x has a number of methods that return an Iterator. These methods
63 * would (in some conditions) be better represented as an Iterable. To maintain
64 * compatibility, and to extend the functionality of these methods in JDOM2,
65 * they have been altered to return an instance of this interface.
66 *
67 * @author Rolf Lear
68 *
69 * @param <T> The generic type of the values returned by this interface
70 */
71 public interface IteratorIterable<T> extends Iterable<T>, Iterator<T> {
72 // There is no functionality added by this interface other than
73 // to combine the Iterator and Iterable interfaces.
74 }
0 /*--
1
2 Copyright (C) 2011 - 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.util;
55
56 import java.util.ArrayList;
57 import java.util.Arrays;
58 import java.util.Comparator;
59 import java.util.Iterator;
60 import java.util.List;
61 import java.util.NoSuchElementException;
62
63 import org.jdom.Attribute;
64 import org.jdom.Element;
65 import org.jdom.Namespace;
66 import org.jdom.internal.ArrayCopy;
67
68
69 /**
70 * A high-performance stack for processing those Namespaces that are introduced
71 * or are in-scope at a point in an Element hierarchy.
72 * <p>
73 * This stack implements the 'Namespace Rules' which XML uses, where a Namespace
74 * 'redefines' an existing Namespace if they share the same prefix. This class
75 * is intended to provide a high-performance mechanism for calculating the
76 * Namespace scope for an Element, and identifying what Namespaces an Element
77 * introduces in to the scope. This is not a validation tool.
78 * <p>
79 * This class implements Iterable which means it can be used in the context
80 * of a for-each type loop:
81 * <br>
82 * <code><pre>
83 * NamespaceStack namespacestack = new NamespaceStack();
84 * for (Namespace ns : namespacestack) {
85 * ...
86 * }
87 * </pre></code>
88 * The Iteration in the above example will return those Namespaces which are
89 * in-scope for the current level of the stack. The Namespace order will follow
90 * the JDOM 'standard'. The first namespace will be the Element's Namespace. The
91 * subsequent Namespaces will be the other in-scope namespaces in alphabetical
92 * order by the Namespace prefix.
93 * <p>
94 * NamespaceStack does not validate the push()/pop() cycles. It does not ensure
95 * that the pop() is for the same element that was previously pushed. Further,
96 * it does not check to make sure that the pushed() Element is the natural child
97 * of the previously pushed() Element.
98 *
99 * @author Rolf Lear
100 *
101 */
102 public final class NamespaceStack implements Iterable<Namespace> {
103
104 /**
105 * Simple read-only iterator that walks an array of Namespace.
106 *
107 * @author rolf
108 *
109 */
110 private static final class ForwardWalker implements Iterator<Namespace> {
111 private final Namespace[] namespaces;
112 int cursor = 0;
113
114 public ForwardWalker(Namespace[] namespaces) {
115 this.namespaces = namespaces;
116 }
117
118 @Override
119 public boolean hasNext() {
120 return cursor < namespaces.length;
121 }
122
123 @Override
124 public Namespace next() {
125 if (cursor >= namespaces.length) {
126 throw new NoSuchElementException("Cannot over-iterate...");
127 }
128 return namespaces[cursor++];
129 }
130
131 @Override
132 public void remove() {
133 throw new UnsupportedOperationException(
134 "Cannot remove Namespaces from iterator");
135
136 }
137
138 }
139
140 /**
141 * Simple read-only iterator that walks an array of Namespace in reverse.
142 *
143 * @author rolf
144 *
145 */
146 private static final class BackwardWalker implements Iterator<Namespace> {
147 private final Namespace[] namespaces;
148 int cursor = -1;
149
150 public BackwardWalker(Namespace[] namespaces) {
151 this.namespaces = namespaces;
152 cursor = namespaces.length - 1;
153 }
154
155 @Override
156 public boolean hasNext() {
157 return cursor >= 0;
158 }
159
160 @Override
161 public Namespace next() {
162 if (cursor < 0) {
163 throw new NoSuchElementException("Cannot over-iterate...");
164 }
165 return namespaces[cursor--];
166 }
167
168 @Override
169 public void remove() {
170 throw new UnsupportedOperationException(
171 "Cannot remove Namespaces from iterator");
172 }
173
174 }
175
176 /**
177 * Simple Iterable instance that produces either Forward or Backward
178 * read-only iterators of the Namespaces
179 *
180 * @author rolf
181 *
182 */
183 private static final class NamespaceIterable implements Iterable<Namespace> {
184 private final boolean forward;
185 private final Namespace[] namespaces;
186 public NamespaceIterable(Namespace[] data, boolean forward) {
187 this.forward = forward;
188 this.namespaces = data;
189 }
190 @Override
191 public Iterator<Namespace> iterator() {
192 return forward ? new ForwardWalker(namespaces)
193 : new BackwardWalker(namespaces);
194 }
195 }
196
197 /**
198 * Convenience class that makes very fast work for an empty Namespace array.
199 * It doubles up as both Iterator and Interable.
200 * @author rolf
201 */
202 private static final class EmptyIterable
203 implements Iterable<Namespace>, Iterator<Namespace> {
204 @Override
205 public Iterator<Namespace> iterator() {
206 return this;
207 }
208
209 @Override
210 public boolean hasNext() {
211 return false;
212 }
213
214 @Override
215 public Namespace next() {
216 throw new NoSuchElementException(
217 "Can not call next() on an empty Iterator.");
218 }
219
220 @Override
221 public void remove() {
222 throw new UnsupportedOperationException(
223 "Cannot remove Namespaces from iterator");
224 }
225 }
226
227 /** A simple empty Namespace Array to avoid redundant empty instances */
228 private static final Namespace[] EMPTY = new Namespace[0];
229 /** A simple Iterable instance that is always empty. Saves some memory */
230 private static final Iterable<Namespace> EMPTYITER = new EmptyIterable();
231
232 /** A comparator that sorts Namespaces by their prefix. */
233 private static final Comparator<Namespace> NSCOMP = new Comparator<Namespace>() {
234 @Override
235 public int compare(Namespace ns1, Namespace ns2) {
236 return ns1.getPrefix().compareTo(ns2.getPrefix());
237 }
238 };
239 private static final Namespace[] DEFAULTSEED = new Namespace[] {
240 Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE};
241
242 /**
243 * Lots of reasons for having our own binarySearch.
244 * <ul>
245 * <li> We can make it specific for Namespaces (using == search).
246 * <li> There is a bug in IBM's AIX JVM in all Java's prior to (including):
247 * IBM J9 VM (build 2.4, J2RE 1.6.0 IBM J9 2.4 AIX ppc-32
248 * jvmap3260-20081105_25433 (JIT enabled, AOT enabled))
249 * where it returns '-1' for all instances where 'from == to' instead
250 * of returning '-from -1'. See
251 * <a href="http://www.ibm.com/developerworks/forums/thread.jspa?threadID=351575&tstart=0">
252 * this description</a> for how it is broken, and pre-checking to make
253 * sure that <code>left &lt; right</code> for each test is a pain.
254 * <li> Ahh, actually, we will never encounter the bug, because we always
255 * have a larger-than-1 scope array.... see comment inside code...
256 * <li> It's not that complicated, really.
257 * </ul>
258 * @param data The Namespaces to search.
259 * @param left The left side of the range to search <b>INCLUSIVE</b>
260 * @param right The right side of the range to search <b>EXCLUSIVE</b>
261 * @param key The Namespace to search for.
262 * @return the 'insertion point' - This return value follows the same convention
263 * as the standard Java BinarySearch methods (see the JavaDoc for Arrays.binarySearch().
264 * In summary, if the value exists then the return value is the index of the existing value.
265 * If the value was not found, then the return value will be negative, and the
266 * place where the missing value should be inserted, can be determined by
267 * adding 1, and converting back to positive (or converting to positive, and subtracting 1).
268 * </i>
269 */
270 private static final int binarySearch(final Namespace[] data,
271 int left, int right, final Namespace key) {
272 // assume all input is valid. No need to waste time checking.
273
274 // Because we are always searching inside of the scope array, and
275 // because there's always at least two scope members, we will always have
276 // a minimum value of 2 for 'right', and a maximum value of 1 for 'left'
277 // thus the following check is never needed.
278 //
279 // if (left >= right) {
280 // // we are searching in nothing, return the correct value
281 // // ... this is where IBM's JDK is broken - it just returns -1
282 // return -left - 1;
283 // }
284 // make the right-side 'inclusive' instead of 'exclusive'
285 right--;
286
287 while (left <= right) {
288 // get the mid-point. See the notes on the binary-search bug...
289 // ... not that we'll ever have that many Namspaces.... ;-)
290 // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
291 final int mid = (left + right) >>> 1;
292 if (data[mid] == key) {
293 // exact namespace match.
294 return mid;
295 }
296 final int cmp = NSCOMP.compare(data[mid], key);
297
298 if (cmp < 0) {
299 left = mid + 1;
300 } else if (cmp > 0) {
301 right = mid - 1;
302 } else {
303 // Namespace prefix match.
304 return mid;
305 }
306 }
307 return -left - 1;
308 }
309
310 /** The namespaces added to the scope at each depth */
311 private Namespace[][] added = new Namespace[10][];
312 /** The entire scope at each depth */
313 private Namespace[][] scope = new Namespace[10][];
314 /** The current depth */
315 private int depth = -1;
316
317 /**
318 * Create a NamespaceWalker ready to use as a stack.
319 * <br>
320 * @see #push(Element) for comprehensive notes.
321 */
322 public NamespaceStack() {
323 this(DEFAULTSEED);
324 }
325
326 /**
327 * Create a NamespaceWalker ready to use as a stack.
328 * <br>
329 * @see #push(Element) for comprehensive notes.
330 * @param seed The namespaces to set as the top level of the stack.
331 */
332 public NamespaceStack(Namespace[] seed) {
333 depth++;
334 added[depth] = seed;
335
336 scope[depth] = added[depth];
337 }
338
339 /**
340 * Inspect the <i>scope</i> array to see whether the <i>namespace</i>
341 * Namespace is 'new' or not. If it is 'new' then it is added to the
342 * <i>store</i> List.
343 * @param store Where to add the <i>namespace</i> if it is 'new'
344 * @param namespace The Namespace to check
345 * @param scope The array of Namespaces that are currently in-scope.
346 * @return The revised version of 'in-scope' if the scope has changed. If
347 * there is no modification then the same input scope will be returned.
348 */
349 private static final Namespace[] checkNamespace(List<Namespace> store,
350 Namespace namespace, Namespace[] scope) {
351 // Scope is always sorted as the primary namespace first, then the
352 // rest are in prefix order.
353 // We can guarantee that the prefixes are all unique too.
354 // There is always going to be at least two namespaces in scope with
355 // the prefixes : "" and "xml"
356 // As a result we can use the 0th index with impunity.
357 if (namespace == scope[0]) {
358 // we are already in scope.
359 return scope;
360 }
361 if (namespace.getPrefix().equals(scope[0].getPrefix())) {
362 // the prefix is the previous scope's primary prefix. This means
363 // that we know for sure that the input namespace is new-to-scope.
364 store.add(namespace);
365 final Namespace[] nscope = ArrayCopy.copyOf(scope, scope.length);
366 nscope[0] = namespace;
367 return nscope;
368 }
369 // will return +ve number if the prefix matches too.
370 int ip = binarySearch(scope, 1, scope.length, namespace);
371 if (ip >= 0 && namespace == scope[ip]) {
372 // the namespace is already in scope.
373 return scope;
374 }
375 store.add(namespace);
376 if (ip >= 0) {
377 // a different namespace with the same prefix as us is in-scope.
378 // replace it....
379 final Namespace[] nscope = ArrayCopy.copyOf(scope, scope.length);
380 nscope[ip] = namespace;
381 return nscope;
382 }
383 // We are a new prefix in-scope.
384 final Namespace[] nscope = ArrayCopy.copyOf(scope, scope.length + 1);
385 ip = - ip - 1;
386 System.arraycopy(nscope, ip, nscope, ip + 1, nscope.length - ip - 1);
387 nscope[ip] = namespace;
388 return nscope;
389 }
390
391 /**
392 * Create a new in-scope level for the Stack based on an Element.
393 * <br>
394 * The Namespaces associated with the input Element are used to modify the
395 * 'in-scope' Namespaces in this NamespaceStack.
396 * <br>
397 * The following 'rules' will be applied:
398 * <ul>
399 * <li>Namespaces used in the input Element that were not part of the previous
400 * scope will be added to the new scope level in the stack.
401 * <li>If a new Namespace is added to the scope, but the previous scope
402 * already had a namespace with the same prefix, then that previous
403 * namespace is removed from the new scope (the new Namespace replaces
404 * the previous namespace with the same prefix).
405 * <li>The order of the in-scope Namespaces will always be: first the
406 * Namespace of the input Element followed by all other in-scope
407 * Namespaces sorted alphabetically by prefix.
408 * <li>The new in-scope Namespace values will be available in this class's
409 * iterator() method (which is available as part of this class's
410 * <i>Iterable</i> implementation.
411 * <li>The namespaces added to the scope by the input Element will be
412 * available in the {@link #addedForward()} Iterable. The order of
413 * the added Namespaces follows the same rules as above: first the
414 * Element Namespace (only if that Namespace is actually added) followed
415 * by the other added namespaces in alphabetical-by-prefix order.
416 * <li>The same added namespaces are also available in reverse order in
417 * the {@link #addedReverse()} Iterable.
418 * </ul>
419 * @param element The element at the new level of the stack.
420 */
421 public void push(Element element) {
422
423 // how many times do you add more than 8 namespaces in one go...
424 // we can add more if we need to...
425 final List<Namespace> toadd = new ArrayList<Namespace>(8);
426 final Namespace mns = element.getNamespace();
427 // check to see whether the Namespace is new-to-scope.
428 Namespace[] newscope = checkNamespace(toadd, mns, scope[depth]);
429 if (element.hasAdditionalNamespaces()) {
430 for (final Namespace ns : element.getAdditionalNamespaces()) {
431 if (ns == mns) {
432 continue;
433 }
434 // check to see whether the Namespace is new-to-scope.
435 newscope = checkNamespace(toadd, ns, newscope);
436 }
437 }
438 if (element.hasAttributes()) {
439 for (final Attribute a : element.getAttributes()) {
440 final Namespace ns = a.getNamespace();
441 if (ns == Namespace.NO_NAMESPACE) {
442 // Attributes are allowed to be in the NO_NAMESPACE without
443 // changing the in-scope set of the Element.... special-case
444 continue;
445 }
446 if (ns == mns) {
447 continue;
448 }
449 // check to see whether the Namespace is new-to-scope.
450 newscope = checkNamespace(toadd, ns, newscope);
451 }
452 }
453
454 pushStack(mns, newscope, toadd);
455
456 }
457
458 /**
459 * Create a new in-scope level for the Stack based on an Attribute.
460 *
461 * @param att The attribute to contribute to the namespace scope.
462 */
463 public void push(Attribute att) {
464 final List<Namespace> toadd = new ArrayList<Namespace>(1);
465 final Namespace mns = att.getNamespace();
466 // check to see whether the Namespace is new-to-scope.
467 Namespace[] newscope = checkNamespace(toadd, mns, scope[depth]);
468
469 pushStack(mns, newscope, toadd);
470 }
471
472 private final void pushStack(final Namespace mns, Namespace[] newscope,
473 final List<Namespace> toadd) {
474 // OK, we've checked the namespaces in the Element, and 'toadd' contains
475 // all namespaces that are not already in scope.
476 depth++;
477
478 if (depth >= scope.length) {
479 // we need more space on the stack.
480 scope = ArrayCopy.copyOf(scope, scope.length * 2);
481 added = ArrayCopy.copyOf(added, scope.length);
482 }
483
484 // Sort out the added namespaces.
485 if (toadd.isEmpty()) {
486 // nothing changed in the scope.
487 added[depth] = EMPTY;
488 } else {
489 added[depth] = toadd.toArray(new Namespace[toadd.size()]);
490 if (added[depth][0] == mns) {
491 Arrays.sort(added[depth], 1, added[depth].length, NSCOMP);
492 } else {
493 Arrays.sort(added[depth], NSCOMP);
494 }
495 }
496
497 if (mns != newscope[0]) {
498 if (toadd.isEmpty()) {
499 // we need to make newscope a copy of the previous level's
500 // scope, because it is not yet a copy.
501 newscope = ArrayCopy.copyOf(newscope, newscope.length);
502 }
503 // we need to take the Namespace at position 0, and insert it
504 // in it's place later in the array.
505 // we need to take the mns from later in the array, and move it
506 // to the front.
507 final Namespace tmp = newscope[0];
508 int ip = - binarySearch(newscope, 1, newscope.length, tmp) - 1;
509 // we can be sure that (- ip - 1 ) is >= 1
510 // we also know that we want to move the data before the ip
511 // backwards one spot, so the math is slightly different....
512 ip--;
513 System.arraycopy(newscope, 1, newscope, 0, ip);
514 newscope[ip] = tmp;
515
516 ip = binarySearch(newscope, 0, newscope.length, mns);
517 // we can be sure that ip is >= 0
518 System.arraycopy(newscope, 0, newscope, 1, ip);
519 newscope[0] = mns;
520 }
521
522 scope[depth] = newscope;
523 }
524
525 /**
526 * Restore stack to the level prior to the current one. The various Iterator
527 * methods will thus return the data at the previous level.
528 */
529 public void pop() {
530 if (depth <= 0) {
531 throw new IllegalStateException("Cannot over-pop the stack.");
532 }
533 scope[depth] = null;
534 added[depth] = null;
535 depth--;
536 }
537
538 /**
539 * Return an Iterable containing all the Namespaces introduced to the
540 * current-level's scope.
541 * @see #push(Element) for the details on the data order.
542 * @return A read-only Iterable containing added Namespaces (may be empty);
543 */
544 public Iterable<Namespace> addedForward() {
545 if (added[depth].length == 0) {
546 return EMPTYITER;
547 }
548 return new NamespaceIterable(added[depth], true);
549 }
550
551 /**
552 * Return an Iterable containing all the Namespaces introduced to the
553 * current-level's scope but in reverse order to {@link #addedForward()}.
554 * @see #push(Element) for the details on the data order.
555 * @return A read-only Iterable containing added Namespaces (may be empty);
556 */
557 public Iterable<Namespace> addedReverse() {
558 if (added[depth].length == 0) {
559 return EMPTYITER;
560 }
561 return new NamespaceIterable(added[depth], false);
562 }
563
564 /**
565 * Get all the Namespaces in-scope at the current level of the stack.
566 * @see #push(Element) for the details on the data order.
567 * @return A read-only Iterator containing added Namespaces (may be empty);
568 */
569 @Override
570 public Iterator<Namespace> iterator() {
571 return new ForwardWalker(scope[depth]);
572 }
573
574 /**
575 * Return a new array instance representing the current scope.
576 * Modifying the returned array will not affect this scope.
577 * @return a copy of the current scope.
578 */
579 public Namespace[] getScope() {
580 return ArrayCopy.copyOf(scope[depth], scope[depth].length);
581 }
582
583 /**
584 * Inspect the current scope and return true if the specified namespace is
585 * in scope.
586 * @param ns The Namespace to check
587 * @return true if the current scope contains that Namespace.
588 */
589 public boolean isInScope(Namespace ns) {
590 if (ns == scope[depth][0]) {
591 return true;
592 }
593 final int ip = binarySearch(scope[depth], 1, scope[depth].length, ns);
594 if (ip >= 0) {
595 // we have the same prefix.
596 return ns == scope[depth][ip];
597 }
598 return false;
599 }
600
601 }
0 <body>
1 Classes that implement useful functionality, but are not easy to categorise.
2 </body>
0 /*--
1
2 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath;
55
56
57 import java.io.*;
58 import java.lang.reflect.*;
59 import java.util.*;
60
61 import org.jdom.*;
62 import org.jdom.internal.SystemProperty;
63
64
65 /**
66 * A utility class for performing XPath calls on JDOM nodes, with a factory
67 * interface for obtaining a first XPath instance. Users operate against this
68 * class while XPath vendors can plug-in implementations underneath. Users
69 * can choose an implementation using either {@link #setXPathClass} or
70 * the system property "org.jdom.xpath.class".
71 *
72 * @author Laurent Bihanic
73 * @deprecated Use XPathFactory/XPathExpression/XPathBuilder instead.
74 */
75 @Deprecated
76 public abstract class XPath implements Serializable {
77
78 /**
79 * Standard JDOM2 Serialization. Default mechanism.
80 */
81 private static final long serialVersionUID = 200L;
82
83 /**
84 * The name of the system property from which to retrieve the
85 * name of the implementation class to use.
86 * <p>
87 * The property name is:
88 * "<code>org.jdom.xpath.class</code>".</p>
89 */
90 private final static String XPATH_CLASS_PROPERTY = "org.jdom.xpath.class";
91
92 /**
93 * The default implementation class to use if none was configured.
94 */
95 private final static String DEFAULT_XPATH_CLASS =
96 "org.jdom.xpath.jaxen.JDOMXPath";
97
98 /**
99 * The string passable to the JAXP 1.3 XPathFactory isObjectModelSupported()
100 * method to query an XPath engine regarding its support for JDOM. Defined
101 * to be the well-known URI "http://jdom.org/jaxp/xpath/jdom".
102 */
103 public final static String JDOM_OBJECT_MODEL_URI =
104 "http://jdom.org/jaxp/xpath/jdom";
105
106 /**
107 * The constructor to instanciate a new XPath concrete
108 * implementation.
109 *
110 * @see #newInstance
111 */
112 private static Constructor<? extends XPath> constructor = null;
113
114 /**
115 * Creates a new XPath wrapper object, compiling the specified
116 * XPath expression.
117 *
118 * @param path the XPath expression to wrap.
119 * @return an XPath instance representing the input path
120 *
121 * @throws JDOMException if the XPath expression is invalid.
122 */
123 public static XPath newInstance(String path) throws JDOMException {
124 try {
125 if (constructor == null) {
126 // First call => Determine implementation.
127 String className;
128 try {
129 className = SystemProperty.get(XPATH_CLASS_PROPERTY,
130 DEFAULT_XPATH_CLASS);
131 }
132 catch (SecurityException ex1) {
133 // Access to system property denied. => Use default impl.
134 className = DEFAULT_XPATH_CLASS;
135 }
136 @SuppressWarnings("unchecked")
137 Class<? extends XPath> useclass = (Class<? extends XPath>) Class.forName(className);
138 if (!XPath.class.isAssignableFrom(useclass)) {
139 throw new JDOMException("Unable to create a JDOMXPath from class '" + className + "'.");
140 }
141 setXPathClass(useclass);
142 }
143 // Allocate and return new implementation instance.
144 return constructor.newInstance(path);
145 }
146 catch (JDOMException ex1) {
147 throw ex1;
148 }
149 catch (InvocationTargetException ex2) {
150 // Constructor threw an error on invocation.
151 Throwable t = ex2.getTargetException();
152
153 throw (t instanceof JDOMException)? (JDOMException)t:
154 new JDOMException(t.toString(), t);
155 }
156 catch (Exception ex3) {
157 // Any reflection error (probably due to a configuration mistake).
158 throw new JDOMException(ex3.toString(), ex3);
159 }
160 }
161
162 /**
163 * Sets the concrete XPath subclass to use when allocating XPath
164 * instances.
165 *
166 * @param aClass the concrete subclass of XPath.
167 *
168 * @throws IllegalArgumentException if <code>aClass</code> is
169 * <code>null</code>.
170 * @throws JDOMException if <code>aClass</code> is
171 * not a concrete subclass
172 * of XPath.
173 */
174 public static void setXPathClass(Class<? extends XPath> aClass) throws JDOMException {
175 if (aClass == null) {
176 throw new IllegalArgumentException("aClass");
177 }
178
179 try {
180 if ((XPath.class.isAssignableFrom(aClass)) &&
181 (Modifier.isAbstract(aClass.getModifiers()) == false)) {
182 // Concrete subclass of XPath => Get constructor
183 constructor = aClass.getConstructor(String.class);
184 }
185 else {
186 throw new JDOMException(aClass.getName() +
187 " is not a concrete JDOM XPath implementation");
188 }
189 }
190 catch (JDOMException ex1) {
191 throw ex1;
192 }
193 catch (Exception ex2) {
194 // Any reflection error (probably due to a configuration mistake).
195 throw new JDOMException(ex2.toString(), ex2);
196 }
197 }
198
199 /**
200 * Evaluates the wrapped XPath expression and returns the list
201 * of selected items.
202 *
203 * @param context the node to use as context for evaluating
204 * the XPath expression.
205 *
206 * @return the list of selected items, which may be of types: {@link Element},
207 * {@link Attribute}, {@link Text}, {@link CDATA},
208 * {@link Comment}, {@link ProcessingInstruction}, Boolean,
209 * Double, or String.
210 *
211 * @throws JDOMException if the evaluation of the XPath
212 * expression on the specified context
213 * failed.
214 */
215 abstract public List selectNodes(Object context) throws JDOMException;
216
217 /**
218 * Evaluates the wrapped XPath expression and returns the first
219 * entry in the list of selected nodes (or atomics).
220 *
221 * @param context the node to use as context for evaluating
222 * the XPath expression.
223 *
224 * @return the first selected item, which may be of types: {@link Element},
225 * {@link Attribute}, {@link Text}, {@link CDATA},
226 * {@link Comment}, {@link ProcessingInstruction}, Boolean,
227 * Double, String, or <code>null</code> if no item was selected.
228 *
229 * @throws JDOMException if the evaluation of the XPath
230 * expression on the specified context
231 * failed.
232 */
233 abstract public Object selectSingleNode(Object context) throws JDOMException;
234
235 /**
236 * Returns the string value of the first node selected by applying
237 * the wrapped XPath expression to the given context.
238 *
239 * @param context the element to use as context for evaluating
240 * the XPath expression.
241 *
242 * @return the string value of the first node selected by applying
243 * the wrapped XPath expression to the given context.
244 *
245 * @throws JDOMException if the XPath expression is invalid or
246 * its evaluation on the specified context
247 * failed.
248 */
249 abstract public String valueOf(Object context) throws JDOMException;
250
251 /**
252 * Returns the number value of the first node selected by applying
253 * the wrapped XPath expression to the given context.
254 *
255 * @param context the element to use as context for evaluating
256 * the XPath expression.
257 *
258 * @return the number value of the first node selected by applying
259 * the wrapped XPath expression to the given context,
260 * <code>null</code> if no node was selected or the
261 * special value {@link java.lang.Double#NaN}
262 * (Not-a-Number) if the selected value can not be
263 * converted into a number value.
264 *
265 * @throws JDOMException if the XPath expression is invalid or
266 * its evaluation on the specified context
267 * failed.
268 */
269 abstract public Number numberValueOf(Object context) throws JDOMException;
270
271 /**
272 * Defines an XPath variable and sets its value.
273 *
274 * @param name the variable name.
275 * @param value the variable value.
276 *
277 * @throws IllegalArgumentException if <code>name</code> is not
278 * a valid XPath variable name
279 * or if the value type is not
280 * supported by the underlying
281 * implementation
282 */
283 abstract public void setVariable(String name, Object value);
284
285 /**
286 * Adds a namespace definition to the list of namespaces known of
287 * this XPath expression.
288 * <p>
289 * <strong>Note</strong>: In XPath, there is no such thing as a
290 * 'default namespace'. The empty prefix <b>always</b> resolves
291 * to the empty namespace URI.</p>
292 *
293 * @param namespace the namespace.
294 */
295 abstract public void addNamespace(Namespace namespace);
296
297 /**
298 * Adds a namespace definition (prefix and URI) to the list of
299 * namespaces known of this XPath expression.
300 * <p>
301 * <strong>Note</strong>: In XPath, there is no such thing as a
302 * 'default namespace'. The empty prefix <b>always</b> resolves
303 * to the empty namespace URI.</p>
304 *
305 * @param prefix the namespace prefix.
306 * @param uri the namespace URI.
307 *
308 * @throws IllegalNameException if the prefix or uri are null or
309 * empty strings or if they contain
310 * illegal characters.
311 */
312 public void addNamespace(String prefix, String uri) {
313 addNamespace(Namespace.getNamespace(prefix, uri));
314 }
315
316 /**
317 * Returns the wrapped XPath expression as a string.
318 *
319 * @return the wrapped XPath expression as a string.
320 */
321 abstract public String getXPath();
322
323
324 /**
325 * Evaluates an XPath expression and returns the list of selected
326 * items.
327 * <p>
328 * <strong>Note</strong>: This method should not be used when the
329 * same XPath expression needs to be applied several times (on the
330 * same or different contexts) as it requires the expression to be
331 * compiled before being evaluated. In such cases,
332 * {@link #newInstance allocating} an XPath wrapper instance and
333 * {@link #selectNodes(java.lang.Object) evaluating} it several
334 * times is way more efficient.
335 * </p>
336 *
337 * @param context the node to use as context for evaluating
338 * the XPath expression.
339 * @param path the XPath expression to evaluate.
340 *
341 * @return the list of selected items, which may be of types: {@link Element},
342 * {@link Attribute}, {@link Text}, {@link CDATA},
343 * {@link Comment}, {@link ProcessingInstruction}, Boolean,
344 * Double, or String.
345 *
346 * @throws JDOMException if the XPath expression is invalid or
347 * its evaluation on the specified context
348 * failed.
349 */
350 public static List selectNodes(Object context, String path)
351 throws JDOMException {
352 return newInstance(path).selectNodes(context);
353 }
354
355 /**
356 * Evaluates the wrapped XPath expression and returns the first
357 * entry in the list of selected nodes (or atomics).
358 * <p>
359 * <strong>Note</strong>: This method should not be used when the
360 * same XPath expression needs to be applied several times (on the
361 * same or different contexts) as it requires the expression to be
362 * compiled before being evaluated. In such cases,
363 * {@link #newInstance allocating} an XPath wrapper instance and
364 * {@link #selectSingleNode(java.lang.Object) evaluating} it
365 * several times is way more efficient.
366 * </p>
367 *
368 * @param context the element to use as context for evaluating
369 * the XPath expression.
370 * @param path the XPath expression to evaluate.
371 *
372 * @return the first selected item, which may be of types: {@link Element},
373 * {@link Attribute}, {@link Text}, {@link CDATA},
374 * {@link Comment}, {@link ProcessingInstruction}, Boolean,
375 * Double, String, or <code>null</code> if no item was selected.
376 *
377 * @throws JDOMException if the XPath expression is invalid or
378 * its evaluation on the specified context
379 * failed.
380 */
381 public static Object selectSingleNode(Object context, String path)
382 throws JDOMException {
383 return newInstance(path).selectSingleNode(context);
384 }
385
386
387 //-------------------------------------------------------------------------
388 // Serialization support
389 //-------------------------------------------------------------------------
390
391 /**
392 * <i>[Serialization support]</i> Returns the alternative object
393 * to write to the stream when serializing this object. This
394 * method returns an instance of a dedicated nested class to
395 * serialize XPath expressions independently of the concrete
396 * implementation being used.
397 * <p>
398 * <strong>Note</strong>: Subclasses are not allowed to override
399 * this method to ensure valid serialization of all
400 * implementations.</p>
401 *
402 * @return an XPathString instance configured with the wrapped
403 * XPath expression.
404 *
405 * @throws ObjectStreamException never.
406 */
407 protected final Object writeReplace() throws ObjectStreamException {
408 return new XPathString(this.getXPath());
409 }
410
411 /**
412 * The XPathString is dedicated to serialize instances of
413 * XPath subclasses in a implementation-independent manner.
414 * <p>
415 * XPathString ensures that only string data are serialized. Upon
416 * deserialization, XPathString relies on XPath factory method to
417 * to create instances of the concrete XPath wrapper currently
418 * configured.</p>
419 */
420 private final static class XPathString implements Serializable {
421 /**
422 * Standard JDOM2 Serialization. Default mechanism.
423 */
424 private static final long serialVersionUID = 200L;
425
426 /**
427 * The XPath expression as a string.
428 */
429 private String xPath = null;
430
431 /**
432 * Creates a new XPathString instance from the specified
433 * XPath expression.
434 *
435 * @param xpath the XPath expression.
436 */
437 public XPathString(String xpath) {
438 super();
439
440 this.xPath = xpath;
441 }
442
443 /**
444 * <i>[Serialization support]</i> Resolves the read XPathString
445 * objects into XPath implementations.
446 *
447 * @return an instance of a concrete implementation of
448 * XPath.
449 *
450 * @throws ObjectStreamException if no XPath could be built
451 * from the read object.
452 */
453 private Object readResolve() throws ObjectStreamException {
454 try {
455 return XPath.newInstance(this.xPath);
456 }
457 catch (JDOMException ex1) {
458 throw new InvalidObjectException(
459 "Can't create XPath object for expression \"" +
460 this.xPath + "\": " + ex1.toString());
461 }
462 }
463 }
464 }
465
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath;
55
56 import java.util.Collection;
57 import java.util.HashMap;
58 import java.util.Map;
59
60 import org.jdom.Namespace;
61 import org.jdom.filter2.Filter;
62
63 /**
64 * A helper class for creating {@link XPathExpression} instances without having
65 * to manage your own Namespace and Variable contexts.
66 *
67 * @author Rolf Lear
68 * @param <T>
69 * The generic type of the returned results.
70 */
71 public class XPathBuilder<T> {
72 private final Filter<T> filter;
73 private final String expression;
74 private Map<String, Object> variables;
75 private Map<String, Namespace> namespaces;
76
77 /**
78 * Create a skeleton XPathBuilder with the given expression and result
79 * filter.
80 *
81 * @param expression
82 * The XPath expression.
83 * @param filter
84 * The Filter to perform the coercion with.
85 */
86 public XPathBuilder(String expression, Filter<T> filter) {
87 if (expression == null) {
88 throw new NullPointerException("Null expression");
89 }
90 if (filter == null) {
91 throw new NullPointerException("Null filter");
92 }
93 this.filter = filter;
94 this.expression = expression;
95 }
96
97 /**
98 * Define or redefine an XPath expression variable value. In XPath, variable
99 * names can be in a namespace, and thus the variable name is in a QName
100 * form: prefix:name
101 * <p>
102 * Variables without a prefix are in the "" Namespace.
103 * <p>
104 * Variables can have a null value. The {@link XPathExpression} can change
105 * the variable value before the expression is evaluated, and, some XPath
106 * libraries support a null variable value. See
107 * {@link XPathExpression#setVariable(String, Namespace, Object)}.
108 * <p>
109 * In order to validate that a Variable is unique you have to know the
110 * namespace associated with the prefix. This class is designed to make it
111 * possible to make the namespace associations after the variables have been
112 * added. As a result it is not possible to validate the uniqueness of a
113 * variable name until the {@link #compileWith(XPathFactory)} method is
114 * called.
115 * <p>
116 * As a consequence of the above, this class assumes that each unique prefix
117 * is for a unique Namespace URI (thus calling this method with different
118 * QNames is assumed to be setting different variables). This may lead to an
119 * IllegalArgumentException when the {@link #compileWith(XPathFactory)}
120 * method is called.
121 * <p>
122 * This method does not validate the format of the variable name either, it
123 * instead postpones the validation until the expression is compiled. As a
124 * result you may encounter IllegalArgumentExceptions at compile time if the
125 * variable names are not valid XPath QNames ("name" or "prefix:name").
126 *
127 * @param qname
128 * The variable name to define.
129 * @param value
130 * The variable value to set.
131 * @return true if this variable was defined, false if it was previously
132 * defined and has now been redefined.
133 * @throws NullPointerException
134 * if the name is null.
135 */
136 public boolean setVariable(String qname, Object value) {
137 if (qname == null) {
138 throw new NullPointerException("Null variable name");
139 }
140 if (variables == null) {
141 variables = new HashMap<String, Object>();
142 }
143 return variables.put(qname, value) == null;
144 }
145
146 /**
147 * Define a Namespace to be available for the XPath expression. If a
148 * Namespace with the same prefix was previously defined then the prefix
149 * will be re-defined.
150 *
151 * @param prefix
152 * The namespace prefix to define.
153 * @param uri
154 * The namespace URI to define.
155 * @return true if the Namespace prefix was newly defined, false if the
156 * prefix was previously defined and has now been redefined.
157 */
158 public boolean setNamespace(String prefix, String uri) {
159 if (prefix == null) {
160 throw new NullPointerException("Null prefix");
161 }
162 if (uri == null) {
163 throw new NullPointerException("Null URI");
164 }
165 return setNamespace(Namespace.getNamespace(prefix, uri));
166 }
167
168 /**
169 * Define a Namespace to be available for the XPath expression.
170 *
171 * @param namespace
172 * The namespace to define.
173 * @return true if this Namespace prefix was newly defined, false if the
174 * prefix was previously defined and has now been redefined.
175 * @throws NullPointerException
176 * if the namespace is null.
177 */
178 public boolean setNamespace(Namespace namespace) {
179 if (namespace == null) {
180 throw new NullPointerException("Null Namespace");
181 }
182 if ("".equals(namespace.getPrefix())) {
183 if (Namespace.NO_NAMESPACE != namespace) {
184 throw new IllegalArgumentException(
185 "Cannot set a Namespace URI in XPath for the \"\" prefix.");
186 }
187 // NO_NAMESPACE is always defined...
188 return false;
189 }
190
191 if (namespaces == null) {
192 namespaces = new HashMap<String, Namespace>();
193 }
194 return namespaces.put(namespace.getPrefix(), namespace) == null;
195 }
196
197 /**
198 * Add a number of namespaces to this XPathBuilder
199 *
200 * @param namespaces
201 * The namespaces to set.
202 * @return true if any of the Namespace prefixes are new to the XPathBuilder
203 * @throws NullPointerException
204 * if the namespace collection, or any of its members are null.
205 */
206 public boolean setNamespaces(Collection<Namespace> namespaces) {
207 if (namespaces == null) {
208 throw new NullPointerException("Null namespaces Collection");
209 }
210 boolean ret = false;
211 for (Namespace ns : namespaces) {
212 if (setNamespace(ns)) {
213 ret = true;
214 }
215 }
216 return ret;
217 }
218
219 /**
220 * Get the variable value associated with the given name. See
221 * {@link #setVariable(String, Object)} for notes on how the Namespaces need
222 * to be established before an authoritative reference to a variable can be
223 * made. As a result, this method uses the simple variable QName name to
224 * reference the variable.
225 *
226 * @param qname
227 * The variable name to get the vaiable value for.
228 * @return the variable value, or null if the variable was not defined.
229 * @throws NullPointerException
230 * if the qname is null.
231 */
232 public Object getVariable(String qname) {
233 if (qname == null) {
234 throw new NullPointerException("Null qname");
235 }
236 if (variables == null) {
237 return null;
238 }
239 return variables.get(qname);
240 }
241
242 /**
243 * Get the Namespace associated with the given prefix.
244 *
245 * @param prefix
246 * The Namespace prefix to get the Namespace for.
247 * @return the Namespace with that prefix, or null if that prefix was never
248 * defined.
249 */
250 public Namespace getNamespace(String prefix) {
251 if (prefix == null) {
252 throw new NullPointerException("Null prefix");
253 }
254 if ("".equals(prefix)) {
255 return Namespace.NO_NAMESPACE;
256 }
257 if (namespaces == null) {
258 return null;
259 }
260 return namespaces.get(prefix);
261 }
262
263 /**
264 * Get the Filter instance used for coercion.
265 *
266 * @return the coercion Filter.
267 */
268 public Filter<T> getFilter() {
269 return filter;
270 }
271
272 /**
273 * Get the XPath expression.
274 *
275 * @return the XPath expression.
276 */
277 public String getExpression() {
278 return expression;
279 }
280
281 /**
282 * Compile an XPathExpression using the details currently stored in the
283 * XPathBuilder.
284 *
285 * @param factory
286 * The XPath factory to use for compiling.
287 * @return The compiled XPath expression
288 * @throws IllegalArgumentException
289 * if the expression cannot be compiled.
290 */
291 public XPathExpression<T> compileWith(XPathFactory factory) {
292 if (namespaces == null) {
293 return factory.compile(expression, filter, variables);
294 }
295 return factory.compile(expression, filter, variables, namespaces
296 .values().toArray(new Namespace[namespaces.size()]));
297 }
298
299 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath;
55
56 import java.util.List;
57
58 /**
59 * Class representing the results of an XPath query allowing JDOM users to trace
60 * whether an item returned from an XPath query is subsequently filtered by the
61 * coercion filter attached to the {@link XPathExpression};
62 *
63 * @author Rolf Lear
64 * @param <T>
65 * The generic type of the results retruend by the expression.
66 */
67 public interface XPathDiagnostic<T> {
68 /**
69 * @return The context object against which the XPath query was evaluated.
70 */
71 public Object getContext();
72
73 /**
74 * @return the {@link XPathExpression} instance that generated this
75 * diagnostic.
76 */
77 public XPathExpression<T> getXPathExpression();
78
79 /**
80 * Returns the results as they would be returned by the regular evaluate
81 * process (read-only).
82 *
83 * @return the regular evaluated results.
84 */
85 public List<T> getResult();
86
87 /**
88 * Returns the XPath results which are not returned by the regular evaluate
89 * process.
90 *
91 * @return those results which were returned by the XPath query but were
92 * filtered out by the JDOM Filter.
93 */
94 public List<Object> getFilteredResults();
95
96 /**
97 * Returns the XPath results before any were filtered.
98 *
99 * @return those results which were returned by the XPath query before any
100 * filtering.
101 */
102 public List<Object> getRawResults();
103
104 /**
105 * Indicate whether the query was evaluated as a first-only evaluation.
106 * XPath libraries are allowed to stop processing the results after the
107 * first result is retrieved if first-only processing is set.
108 *
109 * @return true if the evaluation was a first-only evaluation.
110 */
111 public boolean isFirstOnly();
112
113 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath;
55
56 import java.util.List;
57
58 import org.jdom.Namespace;
59 import org.jdom.filter2.Filter;
60
61 /**
62 * XPathExpression is a representation of a compiled XPath query and any
63 * Namespace or variable references the query may require.
64 * <p>
65 * Once an XPathExpression is created, the values associated with variable names
66 * can be changed. But new variables may not be added.
67 * <p>
68 * <p>
69 * XPathExpression is not thread-safe. XPath libraries allow variable values to
70 * change between calls to their query routines, but require that the variable
71 * value is constant for the duration of any particular evaluation. It is easier
72 * to simply have separate XPathExpression instances in each thread than it is
73 * to manage the synchronization of a single instance. XPathExpression thus
74 * supports Cloneable to easily create another XPathExpression instance. It is
75 * the responsibility of the JDOM caller to ensure appropriate synchronisation
76 * of the XPathExpression if it is accessed from multiple threads.
77 *
78 * @author Rolf Lear
79 * @param <T>
80 * The generic type of the results of the XPath query after being
81 * processed by the JDOM {@code Filter<T>}
82 */
83 public interface XPathExpression<T> extends Cloneable {
84
85 /**
86 * Create a new instance of this XPathExpression that duplicates this
87 * instance.
88 * <p>
89 * The 'cloned' instance will have the same XPath query, namespace
90 * declarations, and variables. Changing a value associated with a variable
91 * on the cloned instance will not change this instance's values, and it is
92 * safe to run the evaluate methods on the cloned copy at the same time as
93 * this copy.
94 *
95 * @return a new XPathExpression instance that shares the same core details
96 * as this.
97 */
98 public XPathExpression<T> clone();
99
100 /**
101 * Get the XPath expression
102 *
103 * @return the string representation of the XPath expression
104 */
105 public String getExpression();
106
107 /**
108 * Get the Namespace associated with a given prefix.
109 *
110 * @param prefix
111 * The prefix to select the Namespace URI for.
112 * @return the URI of the specified Namespace prefix
113 * @throws IllegalArgumentException
114 * if that prefix is not defined.
115 */
116 public Namespace getNamespace(String prefix);
117
118 /**
119 * Get the Namespaces that were used to compile this XPathExpression.
120 *
121 * @return a potentially empty array of Namespaces (never null).
122 */
123 public Namespace[] getNamespaces();
124
125 /**
126 * Change the defined value for a variable to some new value. You may not
127 * use this method to add new variables to the compiled XPath, you can only
128 * change existing variable values.
129 * <p>
130 * The value of the variable may be null. Some XPath libraries support a
131 * null value, and if the library that this expression is for does not
132 * support a null value it should be translated to something meaningful for
133 * that library, typically the empty string.
134 *
135 * @param localname
136 * The variable localname to change.
137 * @param uri
138 * the Namespace in which the variable name is declared.
139 * @param value
140 * The new value to set.
141 * @return The value of the variable prior to this change.
142 * @throws NullPointerException
143 * if name or uri is null
144 * @throws IllegalArgumentException
145 * if name is not already a variable.
146 */
147 public Object setVariable(String localname, Namespace uri, Object value);
148
149 /**
150 * Change the defined value for a variable to some new value. You may not
151 * use this method to add new variables to the compiled XPath, you can only
152 * change existing variable values.
153 * <p>
154 * The value of the variable may be null. Some XPath libraries support a
155 * null value, and if the library that this expression is for does not
156 * support a null value it should be translated to something meaningful for
157 * that library, typically the empty string.
158 * <p>
159 * qname must consist of an optional namespace prefix and colon, followed
160 * by a mandatory variable localname. If the prefix is not specified, then
161 * the Namespace is assumed to be the {@link Namespace#NO_NAMESPACE}. If
162 * the prefix is specified, it must match with one of the declared
163 * Namespaces for this XPathExpression
164 *
165 * @param qname
166 * The variable qname to change.
167 * @param value
168 * The new value to set.
169 * @return The value of the variable prior to this change.
170 * @throws NullPointerException
171 * if qname is null
172 * @throws IllegalArgumentException
173 * if name is not already a variable.
174 */
175 public Object setVariable(String qname, Object value);
176
177 /**
178 * Get the variable value associated to the given variable name.
179 *
180 * @param localname
181 * the variable localname to retrieve the value for.
182 * @param uri
183 * the Namespace in which the variable name was declared.
184 * @return the value associated to a Variable name.
185 * @throws NullPointerException
186 * if name or uri is null
187 * @throws IllegalArgumentException
188 * if that variable name is not defined.
189 */
190 public Object getVariable(String localname, Namespace uri);
191
192 /**
193 * Get the variable value associated to the given variable qname.
194 * <p>
195 * qname must consist of an optional namespace prefix and colon, followed
196 * by a mandatory variable localname. If the prefix is not specified, then
197 * the Namespace is assumed to be the {@link Namespace#NO_NAMESPACE}. If
198 * the prefix is specified, it must match with one of the declared
199 * Namespaces for this XPathExpression
200 *
201 * @param qname
202 * the variable qname to retrieve the value for.
203 * @return the value associated to a Variable name.
204 * @throws NullPointerException
205 * if qname is null
206 * @throws IllegalArgumentException
207 * if that variable name is not defined.
208 */
209 public Object getVariable(String qname);
210
211 /**
212 * Get the {@code Filter<T>} used to coerce the raw XPath results in to
213 * the correct Generic type.
214 * @return the {@code Filter<T>} used to coerce the raw XPath results in to
215 * the correct Generic type.
216 */
217 public Filter<T> getFilter();
218
219 /**
220 * Process the compiled XPathExpression against the specified context.
221 * <p>
222 * In the JDOM2 XPath API the results of the raw XPath query are processed
223 * by the attached {@code Filter<T>} instance to coerce the results in to
224 * the correct generic type for this XPathExpression. The Filter process may
225 * cause some XPath results to be removed from the final results. You may
226 * instead want to call the {@link #diagnose(Object, boolean)} method to
227 * have access to both the raw XPath results as well as the filtered and
228 * generically typed results.
229 *
230 * @param context
231 * The context against which to process the query.
232 * @return a list of the XPath results.
233 * @throws NullPointerException
234 * if the context is null
235 * @throws IllegalStateException
236 * if the expression is not runnable or if the context node is not
237 * appropriate for the expression.
238 */
239 public List<T> evaluate(Object context);
240
241 /**
242 * Return the first value in the XPath query result set type-cast to the
243 * return type of this XPathExpression.
244 * <p>
245 * The concept of the 'first' result is applied before any JDOM Filter is
246 * applied. Thus, if the underlying XPath query has some results, the first
247 * result is sent through the filter. If it matches it is returned, if it
248 * does not match, then null is returned (even if some subsequent result
249 * underlying XPath result would pass the filter).
250 * <p>
251 * This allows the XPath implementation to optimise the evaluateFirst method
252 * by potentially using 'short-circuit' conditions in the evaluation.
253 * <p>
254 *
255 * @param context
256 * The context against which to evaluate the expression. This will
257 * typically be a Document, Element, or some other JDOM object.
258 * @return The first XPath result (if there is any) coerced to the generic
259 * type of this XPathExpression, or null if it cannot be coerced.
260 * @throws NullPointerException
261 * if the context is null
262 * @throws IllegalStateException
263 * if the expression is not runnable or if the context node is not
264 * appropriate for the expression.
265 */
266 public T evaluateFirst(Object context);
267
268 /**
269 * Evaluate the XPath query against the supplied context, but return
270 * additional data which may be useful for diagnosing problems with XPath
271 * queries.
272 *
273 * @param context
274 * The context against which to run the query.
275 * @param firstonly
276 * Indicate whether the XPath expression can be terminated after the
277 * first successful result value.
278 * @return an {@link XPathDiagnostic} instance.
279 * @throws NullPointerException
280 * if the context is null
281 * @throws IllegalStateException
282 * if the expression is not runnable or if the context node is not
283 * appropriate for the expression.
284 */
285 public XPathDiagnostic<T> diagnose(Object context, boolean firstonly);
286 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath;
55
56 import java.util.Collection;
57 import java.util.Map;
58 import java.util.concurrent.atomic.AtomicReference;
59
60 import org.jdom.JDOMConstants;
61 import org.jdom.Namespace;
62 import org.jdom.filter2.Filter;
63 import org.jdom.filter2.Filters;
64 import org.jdom.internal.ReflectionConstructor;
65 import org.jdom.internal.SystemProperty;
66 import org.jdom.xpath.jaxen.JaxenXPathFactory;
67
68 /**
69 * XPathFactory allows JDOM users to configure which XPath implementation to use
70 * when evaluating XPath expressions.
71 * <p>
72 * JDOM does not extend the core Java XPath API (javax.xml.xpath.XPath). Instead
73 * it creates a new API that is more JDOM and Java friendly leading to neater
74 * and more understandable code (in a JDOM context).
75 * <p>
76 * A JDOM XPathFactory instance is able to create JDOM XPathExpression instances
77 * that can be used to evaluate XPath expressions against JDOM Content.
78 * <p>
79 * The XPathFactory allows either default or custom XPathFactory instances to be
80 * created. If you use the {@link #newInstance(String)} method then an
81 * XPathFactory of that specific type will be created. If you use the
82 * {@link #instance()} method then a default XPathFactory instance will be
83 * returned.
84 * <p>
85 * Instances of XPathFactory are specified to be thread-safe. You can reuse an
86 * XPathFactory in multiple threads. Instances of XPathExpression are
87 * <strong>NOT</strong> thread-safe.
88 *
89 * @since JDOM2
90 * @author Rolf Lear
91 */
92 public abstract class XPathFactory {
93
94 private static final Namespace[] EMPTYNS = new Namespace[0];
95
96 /**
97 * An atomic reference storing an instance of the default XPathFactory.
98 */
99 private static final AtomicReference<XPathFactory> defaultreference = new AtomicReference<XPathFactory>();
100
101 private static final String DEFAULTFACTORY = SystemProperty.get(
102 JDOMConstants.JDOM2_PROPERTY_XPATH_FACTORY, null);
103
104 /**
105 * Obtain an instance of an XPathFactory using the default mechanisms to
106 * determine what XPathFactory implementation to use.
107 * <p>
108 * The exact same XPathFactory instance will be returned from each call.
109 * <p>
110 * The default mechanism will inspect the system property (only once)
111 * {@link JDOMConstants#JDOM2_PROPERTY_XPATH_FACTORY} to determine what
112 * class should be used for the XPathFactory. If that property is not set
113 * then JDOM will use the {@link JaxenXPathFactory}.
114 *
115 * @return the default XPathFactory instance
116 */
117 public static final XPathFactory instance() {
118 final XPathFactory ret = defaultreference.get();
119 if (ret != null) {
120 return ret;
121 }
122 XPathFactory fac = DEFAULTFACTORY == null ? new JaxenXPathFactory()
123 : newInstance(DEFAULTFACTORY);
124 if (defaultreference.compareAndSet(null, fac)) {
125 return fac;
126 }
127 // someone else installed a different instance before we added ours.
128 // return that other instance.
129 return defaultreference.get();
130 }
131
132 /**
133 * Create a new instance of an explicit XPathFactory. A new instance of the
134 * specified XPathFactory is created each time. The target XPathFactory
135 * needs to have a no-argument default constructor.
136 * <p>
137 * This method is a convenience mechanism only, and JDOM users are free to
138 * create a custom XPathFactory instance and use a simple: <br>
139 * <code> XPathFactory fac = new MyXPathFactory(arg1, arg2, ...)</code>
140 *
141 * @param factoryclass
142 * The name of the XPathFactory class to create.
143 * @return An XPathFactory of the specified class.
144 */
145 public static final XPathFactory newInstance(String factoryclass) {
146 return ReflectionConstructor
147 .construct(factoryclass, XPathFactory.class);
148 }
149
150 /**
151 * Create a Compiled XPathExpression&lt;&gt; instance from this factory. This
152 * is the only abstract method on this class. All other compile and evaluate
153 * methods prepare the data in some way to call this compile method.
154 * <p>
155 * XPathFactory implementations override this method to implement support
156 * for the JDOM/XPath API.
157 * <p>
158 * A Filter is used to coerce resulting XPath data in to a suitable JDOM generic
159 * type. Note that the {@link Filters} class has a number of predefined, useful
160 * filters.
161 * <p>
162 * <h2>Namespace</h2> XPath expressions are always namespace aware, and
163 * expect to be able to resolve prefixes to namespace URIs. In XPath
164 * expressions the prefix "" always resolves to the empty Namespace URI "".
165 * A prefix in an XPath query is expected to resolve to exactly one URI.
166 * Multiple different prefixes in the expression may resolve to the same
167 * URI.
168 * <p>
169 * This compile method ensures that these XPath/Namespace rules are followed
170 * and thus this method will throw IllegalArgumentException if:
171 * <ul>
172 * <li>a namespace has the empty-string prefix but has a non-empty URI.
173 * <li>more than one Namespace has any one prefix.
174 * </ul>
175 * <p>
176 * <h2>Variables</h2>
177 * <p>
178 * Variables are referenced from XPath expressions using a
179 * <code>$varname</code> syntax. The variable name may be a Namespace
180 * qualified variable name of the form <code>$pfx:localname</code>.
181 * Variables <code>$pa:var</code> and <code>$pb:var</code> are the identical
182 * variables if the namespace URI for prefix 'pa' is the same URI as for
183 * prefix 'pb'.
184 * <p>
185 * This compile method expects all variable names to be expressed in a
186 * prefix-qualified format, where all prefixes have to be available in one
187 * of the specified Namespace instances.
188 * <p>
189 * e.g. if you specify a variable name "ns:var" with value "value", you also
190 * need to have some namespace provided with the prefix "ns" such as
191 * <code>Namespace.getNamespace("ns", "http://example.com/nsuri");</code>
192 * <p>
193 * Some XPath libraries allow null variable values (Jaxen), some do not
194 * (native Java). This compile method will silently convert any null
195 * Variable value to an empty string <code>""</code>.
196 * <p>
197 * Variables are provided in the form of a Map where the key is the variable
198 * name and the mapped value is the variable value. If the entire map is
199 * null then the compile Method assumes there are no variables.
200 * <p>
201 * In light of the above, this compile method will throw an
202 * IllegalArgumentException if:
203 * <ul>
204 * <li>a variable name is not a valid XML QName.
205 * <li>The prefix associated with a variable name is not available as a
206 * Namespace.
207 * </ul>
208 * A NullPointerException will be thrown if the map contains a null variable
209 * name
210 *
211 * @param <T>
212 * The generic type of the results that the XPathExpression will
213 * produce.
214 * @param expression
215 * The XPath expression.
216 * @param filter
217 * The Filter that is used to coerce the XPath result data in to the
218 * generic-typed results.
219 * Note that the {@link Filters} class has a number of predefined, useful
220 * filters.
221 * @param variables
222 * Any variable values that may be referenced from the query. A null
223 * value indicates that there are no variables.
224 * @param namespaces
225 * Any namespaces that may be referenced from the query
226 * @return an XPathExpression&lt;&gt; instance.
227 * @throws NullPointerException
228 * if the query, filter, any namespace, any variable name or any
229 * variable value is null (although the entire variables value may
230 * be null).
231 * @throws IllegalArgumentException
232 * if any two Namespace values share the same prefix, or if there is
233 * any other reason that the XPath query cannot be compiled.
234 * @see org.jdom.filter2.Filters
235 */
236 public abstract <T> XPathExpression<T> compile(String expression,
237 Filter<T> filter, Map<String, Object> variables,
238 Namespace... namespaces);
239
240 /**
241 * Create a XPathExpression&lt;&gt; instance from this factory.
242 *
243 * @param <T>
244 * The generic type of the results that the XPathExpression will
245 * produce.
246 * @param expression
247 * The XPath expression.
248 * @param filter
249 * The Filter that is used to coerce the xpath result data in to the
250 * generic-typed results.
251 * Note that the {@link Filters} class has a number of predefined, useful
252 * filters.
253 * @param variables
254 * Any variable values that may be referenced from the query. A null
255 * value indicates that there are no variables.
256 * @param namespaces
257 * List of all namespaces that may be referenced from the query
258 * @return an XPathExpression&lt;T&gt; instance.
259 * @throws NullPointerException
260 * if the query, filter, namespaces, any variable name or any
261 * variable value is null (although the entire variables value may
262 * be null).
263 * @throws IllegalArgumentException
264 * if any two Namespace values share the same prefix, or if there is
265 * any other reason that the XPath query cannot be compiled.
266 */
267 public <T> XPathExpression<T> compile(String expression, Filter<T> filter,
268 Map<String, Object> variables, Collection<Namespace> namespaces) {
269 return compile(expression, filter, variables, namespaces.toArray(EMPTYNS));
270 }
271
272 /**
273 * Create a XPathExpression&lt;T&gt; instance from this factory.
274 *
275 * @param <T>
276 * The generic type of the results that the XPathExpression will
277 * produce.
278 * @param expression
279 * The XPath expression.
280 * @param filter
281 * The Filter that is used to coerce the xpath result data in to the
282 * generic-typed results.
283 * Note that the {@link Filters} class has a number of predefined, useful
284 * filters.
285 * @return an XPathExpression&lt;T&gt; instance.
286 * @throws NullPointerException
287 * if the query or filter is null
288 * @throws IllegalArgumentException
289 * if there is any reason that the XPath query cannot be compiled.
290 */
291 public <T> XPathExpression<T> compile(String expression, Filter<T> filter) {
292 return compile(expression, filter, null, EMPTYNS);
293 }
294
295 /**
296 * Create a XPathExpression&lt;Object&gt; instance from this factory.
297 *
298 * @param expression
299 * The XPath expression.
300 * @return an XPathExpression&lt;Object&gt; instance.
301 * @throws NullPointerException
302 * if the query or filter is null
303 * @throws IllegalArgumentException
304 * if there is any reason that the XPath query cannot be compiled.
305 */
306 public XPathExpression<Object> compile(String expression) {
307 return compile(expression, Filters.fpassthrough(), null, EMPTYNS);
308 }
309
310 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath;
55
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.Iterator;
59 import java.util.List;
60
61 import org.jdom.Attribute;
62 import org.jdom.Comment;
63 import org.jdom.Content;
64 import org.jdom.Element;
65 import org.jdom.Namespace;
66 import org.jdom.NamespaceAware;
67 import org.jdom.Parent;
68 import org.jdom.ProcessingInstruction;
69 import org.jdom.Text;
70 import org.jdom.filter2.AbstractFilter;
71 import org.jdom.filter2.Filters;
72
73 /**
74 * Provides a set of utility methods to generate XPath expressions to select a
75 * given node in a document. You can generate absolute XPath expressions to the
76 * target node, or relative expressions from a specified start point. If you
77 * request a relative expression, the start and target nodes must share some
78 * common ancestry.
79 * <p>
80 * XPaths are required to be namespace-aware. Typically this is done by using
81 * a namespace-prefixed query, with the actual namespace URI being set in the
82 * context of the XPath expression. This is not possible to express using a
83 * simple String return value. As a work-around, this method uses a potentially
84 * slower, but more reliable, mechanism for ensuring the correct namespace
85 * context is selected. The mechanism will appear like (for Elements):
86 * <br>
87 * <code> .../*[local-name() = 'tag' and namespace-uri() = 'uri']</code>
88 * <br>
89 * Similarly, Attributes will have a syntax similar to:
90 * <br>
91 * <code> .../@*[local-name() = 'attname' and namespace-uri() = 'uri'] </code>
92 * <br>
93 * This mechanism makes it possible to have a simple namespace context, and a
94 * simple String value returned from the methods on this class.
95 * <p>
96 * This class does not provide ways to access document-level content. Nor does
97 * it provide ways to access data relative to the Document level. Use absolute
98 * methods to access data from the Document level.
99 * <p>
100 * The methods on this class assume that the Document is above the top-most
101 * Element in the XML tree. The top-most Element is the one that does not have
102 * a parent Element (although it may have a parent Document). As a result, you
103 * can use Element data that is not attached to a JDOM Document.
104 * <p>
105 * Detatched Attributes, and detached non-Element content are not treated the
106 * same. If you try to get an Absolute path to a detached Attribute or
107 * non-Element Content you will get an IllegalArgumentException. On the other
108 * hand it is legal to get the relative XPath for a detached node to itself (
109 * but to some other node will cause an IllegalArgumentException because the
110 * nodes do not share a common ancestor).
111 * <p>
112 * <strong>Note</strong>: As this class has no knowledge of the document
113 * content, the generated XPath expression rely on the document structure. Hence
114 * any modification of the structure of the document may invalidate the
115 * generated XPaths.
116 * </p>
117 *
118 * @author Laurent Bihanic
119 * @author Rolf Lear
120 */
121 public final class XPathHelper {
122
123 /**
124 * Private constructor.
125 */
126 private XPathHelper () {
127 // make constructor inaccessible.
128 }
129
130 /**
131 * Appends the specified path token to the provided buffer followed by the
132 * position specification of the target node in its siblings list (if
133 * needed).
134 *
135 * @param node
136 * the target node for the XPath expression.
137 * @param siblings
138 * the siblings of the target node.
139 * @param pathToken
140 * the path token identifying the target node.
141 * @param buffer
142 * the buffer to which appending the XPath sub-expression or
143 * <code>null</code> if the method shall allocate a new buffer.
144 * @return the XPath sub-expression to select the target node among its
145 * siblings.
146 */
147 private static StringBuilder getPositionPath(Object node, List<?> siblings,
148 String pathToken, StringBuilder buffer) {
149
150 buffer.append(pathToken);
151
152 if (siblings != null) {
153 int position = 0;
154 final Iterator<?> i = siblings.iterator();
155 while (i.hasNext()) {
156 position++;
157 if (i.next() == node)
158 break;
159 }
160 if (position > 1 || i.hasNext()) {
161 // the item is not at the first location, ot there are more
162 // locations. in other words, indexing is required.
163 buffer.append('[').append(position).append(']');
164 }
165 }
166 return buffer;
167 }
168
169 /**
170 * Calculate a single stage of an XPath query.
171 *
172 * @param nsa
173 * The token to get the relative-to-parent XPath for
174 * @param buffer
175 * The buffer to append the relative stage to
176 * @return The same buffer as was input.
177 */
178 private static final StringBuilder getSingleStep(final NamespaceAware nsa,
179 final StringBuilder buffer) {
180 if (nsa instanceof Content) {
181
182 final Content content = (Content) nsa;
183
184 final Parent pnt = content.getParent();
185
186 if (content instanceof Text) { // OR CDATA!
187
188 final List<?> sibs = pnt == null ? null :
189 pnt.getContent(AbstractFilter.toFilter(Filters.text())); // CDATA
190 return getPositionPath(content, sibs, "text()", buffer);
191
192 } else if (content instanceof Comment) {
193
194 final List<?> sibs = pnt == null ? null :
195 pnt.getContent(AbstractFilter.toFilter(Filters.comment()));
196 return getPositionPath(content, sibs, "comment()", buffer);
197
198 } else if (content instanceof ProcessingInstruction) {
199
200 final List<?> sibs = pnt == null ? null :
201 pnt.getContent(AbstractFilter.toFilter(Filters.processinginstruction()));
202 return getPositionPath(content, sibs,
203 "processing-instruction()", buffer);
204
205 } else if (content instanceof Element &&
206 ((Element) content).getNamespace() == Namespace.NO_NAMESPACE) {
207
208 // simple XPath to a no-namespace Element.
209
210 final String ename = ((Element) content).getName();
211 final List<?> sibs = (pnt instanceof Element) ? ((Element)pnt)
212 .getChildren(ename) : null;
213 return getPositionPath(content, sibs, ename, buffer);
214
215 } else if (content instanceof Element) {
216
217 // complex XPath to an Element with Namespace...
218 // we do not want to have to prefix namespaces because that is
219 // essentially impossible to get right with the new JDOM2 API.
220 final Element emt = (Element)content;
221
222 // Note, the getChildren compares only the URI (not the prefix)
223 // so the results are the same as an XPath would be.
224 final List<?> sibs = (pnt instanceof Element) ?
225 ((Element)pnt).getChildren(emt.getName(), emt.getNamespace()) : null;
226 String xps = "*[local-name() = '" + emt.getName() +
227 "' and namespace-uri() = '" +
228 emt.getNamespaceURI() + "']";
229 return getPositionPath(content, sibs, xps, buffer);
230
231 } else {
232 final List<?> sibs = pnt == null ? Collections
233 .singletonList(nsa) : pnt.getContent();
234 return getPositionPath(content, sibs, "node()", buffer);
235
236 }
237 } else if (nsa instanceof Attribute) {
238 Attribute att = (Attribute) nsa;
239 if (att.getNamespace() == Namespace.NO_NAMESPACE) {
240 buffer.append("@").append(att.getName());
241 } else {
242 buffer.append("@*[local-name() = '").append(att.getName());
243 buffer.append("' and namespace-uri() = '");
244 buffer.append(att.getNamespaceURI()).append("']");
245 }
246 }
247
248 // do nothing...
249 return buffer;
250 }
251
252 /**
253 * Returns the path to the specified <code>to</code>Element from the
254 * specified <code>from</code> Element. The from Element must have a common
255 * ancestor Element with the to Element.
256 * <p>
257 *
258 * @param from
259 * the Element the generated path shall select relative to.
260 * @param to
261 * the Content the generated path shall select.
262 * @param sb
263 * the StringBuilder to append the path to.
264 * @return an XPath expression to select the specified node.
265 * @throws IllegalArgumentException
266 * if the from and to Elements have no common ancestor.
267 */
268 private static StringBuilder getRelativeElementPath(final Element from,
269 final Parent to, final StringBuilder sb) {
270 if (from == to) {
271 sb.append(".");
272 return sb;
273 }
274
275 // ToStack will be a chain of Elements from the to element to the
276 // root element, but will be 'short' if it encounters the from Element
277 // itself.
278 final ArrayList<Parent> tostack = new ArrayList<Parent>();
279 Parent p = to;
280 while (p != null && p != from) {
281 tostack.add(p);
282 p = p.getParent();
283 }
284
285 // the number of steps we will have in the resulting path (potentially)
286 int pos = tostack.size();
287
288 if (p != from) {
289 // the from is not a direct ancestor of the to.
290 // we need to find where the common ancestor is between from and to
291 // we use the 'pos' variable to locate the common ancestor.
292 // pos is a pointer in to the tostack.
293 Parent f = from;
294 int fcnt = 0;
295 // note that we search for 'pos' here... it will be set.
296 while (f != null && (pos = locate(f, tostack)) < 0) {
297 // go up the from ELement's ancestry until we intersect with the
298 // to Element's Ancestry.
299 fcnt++;
300 f = f.getParent();
301 }
302 if (f == null) {
303 throw new IllegalArgumentException(
304 "The 'from' and 'to' Element have no common ancestor.");
305 }
306 // OK, we have counted how far up the ancestry we need to go, so
307 // add the steps to the XPath.
308 while (--fcnt >= 0) {
309 sb.append("../");
310 }
311 }
312 // we have the common point in the ancestry, indicated by 'pos'.
313 // we walk down the 'to' side of the tree until we get to the target.
314 while (--pos >= 0) {
315 getSingleStep(tostack.get(pos), sb);
316 sb.append("/");
317 }
318 // we automatically append '/' in the loop, so we remove the last '/'
319 sb.setLength(sb.length() - 1);
320 return sb;
321 }
322
323 /**
324 * Do an identity search in an array for a specific value.
325 *
326 * @param f
327 * The Element to search for.
328 * @param tostack
329 * The list to search in.
330 * @return the position of the f value in the tostack.
331 */
332 private static int locate(final Parent f, final List<Parent> tostack) {
333 // a somewhat naive search... ArrayList it is fast enough though.
334 int ret = tostack.size();
335 while (--ret >= 0) {
336 if (f == tostack.get(ret)) {
337 return ret;
338 }
339 }
340 return -1;
341 }
342
343 /**
344 * Returns the relative path from the given from Content to the specified to
345 * Content as an XPath expression.
346 *
347 * @param from
348 * the Content from which the the generated path shall be applied.
349 * @param to
350 * the Content the generated path shall select.
351 * @return an XPath expression to select the specified node.
352 * @throws IllegalArgumentException
353 * if <code>to</code> and <code>from</code> are not part of the same
354 * XML tree
355 */
356 public static String getRelativePath(final Content from, final Content to) {
357 if (from == null) {
358 throw new NullPointerException(
359 "Cannot create a path from a null target");
360 }
361 if (to == null) {
362 throw new NullPointerException(
363 "Cannot create a path to a null target");
364 }
365 StringBuilder sb = new StringBuilder();
366 if (from == to) {
367 return ".";
368 }
369 final Element efrom = (from instanceof Element) ? (Element) from : from
370 .getParentElement();
371 if (from != efrom) {
372 sb.append("../");
373 }
374 if (to instanceof Element) {
375 getRelativeElementPath(efrom, (Element) to, sb);
376 } else {
377 final Parent telement = to.getParent();
378 if (telement == null) {
379 throw new IllegalArgumentException(
380 "Cannot get a relative XPath to detached content.");
381 }
382 getRelativeElementPath(efrom, telement, sb);
383 sb.append("/");
384 getSingleStep(to, sb);
385 }
386 return sb.toString();
387 }
388
389 /**
390 * Returns the relative path from the given from Content to the specified to
391 * Attribute as an XPath expression.
392 *
393 * @param from
394 * the Content from which the the generated path shall be applied.
395 * @param to
396 * the Attribute the generated path shall select.
397 * @return an XPath expression to select the specified node.
398 * @throws IllegalArgumentException
399 * if <code>to</code> and <code>from</code> are not part of the same
400 * XML tree
401 */
402 public static String getRelativePath(final Content from, final Attribute to) {
403 if (from == null) {
404 throw new NullPointerException(
405 "Cannot create a path from a null Content");
406 }
407 if (to == null) {
408 throw new NullPointerException(
409 "Cannot create a path to a null Attribute");
410 }
411 final Element t = to.getParent();
412 if (t == null) {
413 throw new IllegalArgumentException(
414 "Cannot create a path to detached Attribute");
415 }
416 StringBuilder sb = new StringBuilder(getRelativePath(from, t));
417 sb.append("/");
418 getSingleStep(to, sb);
419 return sb.toString();
420 }
421
422 /**
423 * Returns the relative path from the given from Attribute to the specified
424 * to Attribute as an XPath expression.
425 *
426 * @param from
427 * the Attribute from which the the generated path shall be applied.
428 * @param to
429 * the Attribute the generated path shall select.
430 * @return an XPath expression to select the specified node.
431 * @throws IllegalArgumentException
432 * if <code>to</code> and <code>from</code> are not part of the same
433 * XML tree
434 */
435 public static String getRelativePath(final Attribute from,
436 final Attribute to) {
437 if (from == null) {
438 throw new NullPointerException(
439 "Cannot create a path from a null 'from'");
440 }
441 if (to == null) {
442 throw new NullPointerException(
443 "Cannot create a path to a null target");
444 }
445 if (from == to) {
446 return ".";
447 }
448
449 final Element f = from.getParent();
450 if (f == null) {
451 throw new IllegalArgumentException(
452 "Cannot create a path from a detached attrbibute");
453 }
454
455 return "../" + getRelativePath(f, to);
456 }
457
458 /**
459 * Returns the relative path from the given from Attribute to the specified
460 * to Content as an XPath expression.
461 *
462 * @param from
463 * the Attribute from which the the generated path shall be applied.
464 * @param to
465 * the Content the generated path shall select.
466 * @return an XPath expression to select the specified node.
467 * @throws IllegalArgumentException
468 * if <code>to</code> and <code>from</code> are not part of the same
469 * XML tree
470 */
471 public static String getRelativePath(final Attribute from, final Content to) {
472 if (from == null) {
473 throw new NullPointerException(
474 "Cannot create a path from a null 'from'");
475 }
476 if (to == null) {
477 throw new NullPointerException(
478 "Cannot create a path to a null target");
479 }
480 final Element f = from.getParent();
481 if (f == null) {
482 throw new IllegalArgumentException(
483 "Cannot create a path from a detached attrbibute");
484 }
485 if (f == to) {
486 return "..";
487 }
488 return "../" + getRelativePath(f, to);
489 }
490
491 /**
492 * Returns the absolute path to the specified to Content.
493 *
494 * @param to
495 * the Content the generated path shall select.
496 * @return an XPath expression to select the specified node.
497 * @throws IllegalArgumentException
498 * if <code>to</code> is not an Element and it is detached.
499 */
500 public static String getAbsolutePath(final Content to) {
501 if (to == null) {
502 throw new NullPointerException(
503 "Cannot create a path to a null target");
504 }
505
506 final StringBuilder sb = new StringBuilder();
507
508 final Element t = (to instanceof Element) ? (Element) to : to
509 .getParentElement();
510 if (t == null) {
511 if (to.getParent() == null) {
512 throw new IllegalArgumentException(
513 "Cannot create a path to detached target");
514 }
515 // otherwise it must be at the document level.
516 sb.append("/");
517 getSingleStep(to, sb);
518 return sb.toString();
519 }
520 Element r = t;
521 while (r.getParentElement() != null) {
522 r = r.getParentElement();
523 }
524 sb.append("/");
525 getSingleStep(r, sb);
526 if (r != t) {
527 sb.append("/");
528 getRelativeElementPath(r, t, sb);
529 }
530 if (t != to) {
531 sb.append("/");
532 getSingleStep(to, sb);
533 }
534 return sb.toString();
535 }
536
537 /**
538 * Returns the absolute path to the specified to Content.
539 *
540 * @param to
541 * the Content the generated path shall select.
542 * @return an XPath expression to select the specified node.
543 * @throws IllegalArgumentException
544 * if <code>to</code> is detached.
545 */
546 public static String getAbsolutePath(final Attribute to) {
547 if (to == null) {
548 throw new NullPointerException(
549 "Cannot create a path to a null target");
550 }
551
552 final Element t = to.getParent();
553 if (t == null) {
554 throw new IllegalArgumentException(
555 "Cannot create a path to detached target");
556 }
557 Element r = t;
558 while (r.getParentElement() != null) {
559 r = r.getParentElement();
560 }
561 final StringBuilder sb = new StringBuilder();
562
563 sb.append("/");
564 getSingleStep(r, sb);
565 if (t != r) {
566 sb.append("/");
567 getRelativeElementPath(r, t, sb);
568 }
569 sb.append("/");
570 getSingleStep(to, sb);
571 return sb.toString();
572 }
573
574 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath.jaxen;
55
56 /**
57 * Simply extend the core Navigator to make it all final.
58 *
59 * @author Rolf Lear
60 *
61 */
62 final class JDOM2Navigator extends JDOMCoreNavigator {
63
64 // just make the class final.
65
66 /**
67 * Standard JDOM2 Serialization. Default mechanism.
68 */
69 private static final long serialVersionUID = 200L;
70
71 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath.jaxen;
55
56 import java.io.IOException;
57 import java.util.Arrays;
58 import java.util.IdentityHashMap;
59 import java.util.Iterator;
60 import java.util.List;
61
62 import org.jaxen.BaseXPath;
63 import org.jaxen.DefaultNavigator;
64 import org.jaxen.FunctionCallException;
65 import org.jaxen.JaxenConstants;
66 import org.jaxen.UnsupportedAxisException;
67 import org.jaxen.XPath;
68 import org.jaxen.saxpath.SAXPathException;
69 import org.jaxen.util.SingleObjectIterator;
70
71 import org.jdom.Attribute;
72 import org.jdom.Comment;
73 import org.jdom.Content;
74 import org.jdom.Document;
75 import org.jdom.Element;
76 import org.jdom.JDOMException;
77 import org.jdom.Namespace;
78 import org.jdom.Parent;
79 import org.jdom.ProcessingInstruction;
80 import org.jdom.Text;
81 import org.jdom.input.SAXBuilder;
82
83 class JDOMCoreNavigator extends DefaultNavigator {
84
85 /**
86 * Standard JDOM2 Serialization. Default mechanism.
87 */
88 private static final long serialVersionUID = 200L;
89
90 private transient IdentityHashMap<Element, NamespaceContainer[]> emtnsmap
91 = new IdentityHashMap<Element, NamespaceContainer[]>();
92
93 void reset() {
94 emtnsmap.clear();
95 }
96
97
98 @Override
99 public final XPath parseXPath(String path) throws SAXPathException {
100 return new BaseXPath(path, this);
101 }
102
103 @Override
104 public final Object getDocument(String url) throws FunctionCallException {
105 SAXBuilder sb = new SAXBuilder();
106 try {
107 return sb.build(url);
108 } catch (JDOMException e) {
109 throw new FunctionCallException("Failed to parse " + url, e);
110 } catch (IOException e) {
111 throw new FunctionCallException("Failed to access " + url, e);
112 }
113 }
114
115 @Override
116 public final boolean isText(Object isit) {
117 return isit instanceof Text;
118 }
119
120 @Override
121 public final boolean isProcessingInstruction(Object isit) {
122 return isit instanceof ProcessingInstruction;
123 }
124
125 @Override
126 public final boolean isNamespace(Object isit) {
127 return (isit instanceof NamespaceContainer);
128 }
129
130 @Override
131 public final boolean isElement(Object isit) {
132 return isit instanceof Element;
133 }
134
135 @Override
136 public final boolean isDocument(Object isit) {
137 return isit instanceof Document;
138 }
139
140 @Override
141 public final boolean isComment(Object isit) {
142 return isit instanceof Comment;
143 }
144
145 @Override
146 public final boolean isAttribute(Object isit) {
147 return isit instanceof Attribute;
148 }
149
150 @Override
151 public final String getTextStringValue(Object text) {
152 // CDATA is a subclass of Text
153 return ((Text)text).getText();
154 }
155
156 @Override
157 public final String getNamespaceStringValue(Object namespace) {
158 return ((NamespaceContainer)namespace).getNamespace().getURI();
159 }
160
161 @Override
162 public final String getNamespacePrefix(Object namespace) {
163 return ((NamespaceContainer)namespace).getNamespace().getPrefix();
164 }
165
166 private final void recurseElementText(Element element, StringBuilder sb) {
167 for (Iterator<?> it = element.getContent().iterator(); it.hasNext(); ) {
168 Content c = (Content)it.next();
169 if (c instanceof Element) {
170 recurseElementText((Element)c, sb);
171 } else if (c instanceof Text) {
172 sb.append(((Text)c).getText());
173 }
174 }
175 }
176
177 @Override
178 public final String getElementStringValue(Object element) {
179 StringBuilder sb = new StringBuilder();
180 recurseElementText((Element)element, sb);
181 return sb.toString();
182 }
183
184 @Override
185 public final String getElementQName(Object element) {
186 Element e = (Element)element;
187 if (e.getNamespace().getPrefix().length() == 0) {
188 return e.getName();
189 }
190 return e.getNamespacePrefix() + ":" + e.getName();
191 }
192
193 @Override
194 public final String getElementNamespaceUri(Object element) {
195 return ((Element)element).getNamespaceURI();
196 }
197
198 @Override
199 public final String getElementName(Object element) {
200 return ((Element)element).getName();
201 }
202
203 @Override
204 public final String getCommentStringValue(Object comment) {
205 return ((Comment)comment).getValue();
206 }
207
208 @Override
209 public final String getAttributeStringValue(Object attribute) {
210 return ((Attribute)attribute).getValue();
211 }
212
213 @Override
214 public final String getAttributeQName(Object att) {
215 Attribute attribute = (Attribute)att;
216 if (attribute.getNamespacePrefix().length() == 0) {
217 return attribute.getName();
218 }
219 return attribute.getNamespacePrefix() + ":" + attribute.getName();
220 }
221
222 @Override
223 public final String getAttributeNamespaceUri(Object attribute) {
224 return ((Attribute)attribute).getNamespaceURI();
225 }
226
227 @Override
228 public final String getAttributeName(Object attribute) {
229 return ((Attribute)attribute).getName();
230 }
231
232 @Override
233 public final String getProcessingInstructionTarget(Object pi) {
234 return ((ProcessingInstruction)pi).getTarget();
235 }
236
237 @Override
238 public final String getProcessingInstructionData(Object pi) {
239 return ((ProcessingInstruction)pi).getData();
240 }
241
242 @Override
243 public final Object getDocumentNode(Object contextNode) {
244 if (contextNode instanceof Document) {
245 return contextNode;
246 }
247 if (contextNode instanceof NamespaceContainer) {
248 return ((NamespaceContainer)contextNode).getParentElement().getDocument();
249 }
250 if (contextNode instanceof Attribute) {
251 return ((Attribute)contextNode).getDocument();
252 }
253 return ((Content)contextNode).getDocument();
254 }
255
256 @Override
257 public final Object getParentNode(Object contextNode) throws UnsupportedAxisException {
258 if (contextNode instanceof Document) {
259 return null;
260 }
261 if (contextNode instanceof NamespaceContainer) {
262 return ((NamespaceContainer)contextNode).getParentElement();
263 }
264 if (contextNode instanceof Content) {
265 return ((Content)contextNode).getParent();
266 }
267 if (contextNode instanceof Attribute) {
268 return ((Attribute)contextNode).getParent();
269 }
270 return null;
271 }
272
273 @Override
274 public final Iterator<?> getAttributeAxisIterator(Object contextNode) throws UnsupportedAxisException {
275 if (isElement(contextNode) && ((Element)contextNode).hasAttributes()) {
276 return ((Element)contextNode).getAttributes().iterator();
277 }
278 return JaxenConstants.EMPTY_ITERATOR;
279 }
280
281 @Override
282 public final Iterator<?> getChildAxisIterator(Object contextNode) throws UnsupportedAxisException {
283 if (contextNode instanceof Parent) {
284 return ((Parent)contextNode).getContent().iterator();
285 }
286 return JaxenConstants.EMPTY_ITERATOR;
287 }
288
289 @Override
290 public final Iterator<?> getNamespaceAxisIterator(final Object contextNode) throws UnsupportedAxisException {
291 //The namespace axis applies to Elements only in XPath.
292 if ( !isElement(contextNode) ) {
293 return JaxenConstants.EMPTY_ITERATOR;
294 }
295 NamespaceContainer[] ret = emtnsmap.get(contextNode);
296 if (ret == null) {
297 List<Namespace> nsl = ((Element)contextNode).getNamespacesInScope();
298 ret = new NamespaceContainer[nsl.size()];
299 int i = 0;
300 for (Namespace ns : nsl) {
301 ret[i++] = new NamespaceContainer(ns, (Element)contextNode);
302 }
303 emtnsmap.put((Element)contextNode, ret);
304 }
305
306 return Arrays.asList(ret).iterator();
307
308 }
309
310 @Override
311 public final Iterator<?> getParentAxisIterator(Object contextNode) throws UnsupportedAxisException {
312
313 Parent p = null;
314 if (contextNode instanceof Content) {
315 p = ((Content)contextNode).getParent();
316 } else if (contextNode instanceof NamespaceContainer) {
317 p = ((NamespaceContainer)contextNode).getParentElement();
318 } else if (contextNode instanceof Attribute) {
319 p = ((Attribute)contextNode).getParent();
320 }
321 if (p != null) {
322 return new SingleObjectIterator(p);
323 }
324 return JaxenConstants.EMPTY_ITERATOR;
325 }
326
327 private void readObject(java.io.ObjectInputStream in)
328 throws IOException, ClassNotFoundException {
329 in.defaultReadObject();
330 emtnsmap = new IdentityHashMap<Element, NamespaceContainer[]>();
331 }
332
333 private void writeObject(java.io.ObjectOutputStream out)
334 throws IOException {
335 out.defaultWriteObject();
336 }
337
338 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath.jaxen;
55
56 import java.util.HashMap;
57 import java.util.List;
58
59 import org.jaxen.NamespaceContext;
60
61 import org.jdom.Namespace;
62 import org.jdom.NamespaceAware;
63
64 final class JDOMNavigator extends JDOMCoreNavigator implements NamespaceContext {
65
66 /**
67 * Standard JDOM2 Serialization. Default mechanism.
68 */
69 private static final long serialVersionUID = 200L;
70
71 private final HashMap<String, String> nsFromContext = new HashMap<String, String>();
72 private final HashMap<String, String> nsFromUser = new HashMap<String, String>();
73
74 @Override
75 void reset() {
76 super.reset();
77 nsFromContext.clear();
78 }
79
80 void setContext(Object node) {
81 nsFromContext.clear();
82
83 List<Namespace> nsl = null;
84 if (node instanceof NamespaceAware) {
85 nsl = ((NamespaceAware)node).getNamespacesInScope();
86 } else if (node instanceof NamespaceContainer) {
87 nsl = ((NamespaceContainer)node).getParentElement().getNamespacesInScope();
88 }
89 if (nsl != null) {
90 for (Namespace ns : nsl) {
91 nsFromContext.put(ns.getPrefix(), ns.getURI());
92 }
93 }
94 }
95
96 void includeNamespace(Namespace namespace) {
97 nsFromUser.put(namespace.getPrefix(), namespace.getURI());
98 }
99
100 @Override
101 public String translateNamespacePrefixToUri(String prefix) {
102 if (prefix == null) {
103 return null;
104 }
105 String uri = nsFromUser.get(prefix);
106 if (uri != null) {
107 return uri;
108 }
109 return nsFromContext.get(prefix);
110 }
111
112 }
0 /*--
1
2 Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath.jaxen;
55
56 import java.util.ArrayList;
57 import java.util.Iterator;
58 import java.util.List;
59
60 import org.jaxen.BaseXPath;
61 import org.jaxen.JaxenException;
62 import org.jaxen.SimpleVariableContext;
63 import org.jaxen.XPath;
64
65 import org.jdom.Attribute;
66 import org.jdom.CDATA;
67 import org.jdom.Comment;
68 import org.jdom.Element;
69 import org.jdom.JDOMException;
70 import org.jdom.Namespace;
71 import org.jdom.ProcessingInstruction;
72 import org.jdom.Text;
73
74 /**
75 * A concrete XPath implementation for Jaxen. This class must be public because
76 * the main JDOM XPath class needs to access the class, and the constructor.
77 *
78 * The generic type of the returned values from this XPath instance.
79 * @author Laurent Bihanic
80 * @deprecated replaced by compiled version.
81 */
82 @Deprecated
83 public class JDOMXPath extends org.jdom.xpath.XPath {
84
85 /**
86 * Default mechanism.
87 * The serialization for this class is broken. It is only included here for
88 * compatibility with JDOM 1.x
89 */
90 private static final long serialVersionUID = 200L;
91
92
93 /**
94 * The compiled XPath object to select nodes. This attribute cannot be made
95 * final as it needs to be set upon object deserialization.
96 */
97 private transient XPath xPath;
98
99 /**
100 * The current context for XPath expression evaluation. The navigator is
101 * responsible for exposing JDOM content to Jaxen, including the wrapping of
102 * Namespace instances in NamespaceContainer
103 * <p>
104 * Because of the need to wrap Namespace, we also need to unwrap namespace.
105 * Further, we can't re-use the details from one 'selectNodes' to another
106 * because the Document tree may have been modified between, and also, we do
107 * not want to be holding on to memory.
108 * <p>
109 * Finally, we want to pre-load the NamespaceContext with the namespaces
110 * that are in scope for the contextNode being searched.
111 * <p>
112 * So, we need to reset the Navigator before and after each use. try{}
113 * finally {} to the rescue.
114 */
115 private final JDOMNavigator navigator = new JDOMNavigator();
116
117 /**
118 * Same story, need to be able to strip NamespaceContainer instances from
119 * Namespace content.
120 *
121 * @param o
122 * A result object which could potentially be a NamespaceContainer
123 * @return The input parameter unless it is a NamespaceContainer in which
124 * case return the wrapped Namespace
125 */
126 private static final Object unWrapNS(Object o) {
127 if (o instanceof NamespaceContainer) {
128 return ((NamespaceContainer) o).getNamespace();
129 }
130 return o;
131 }
132
133 /**
134 * Same story, need to be able to replace NamespaceContainer instances with
135 * Namespace content.
136 *
137 * @param results
138 * A list potentially containing NamespaceContainer instances
139 * @return The parameter list with NamespaceContainer instances replaced by
140 * the wrapped Namespace instances.
141 */
142 private static final List<Object> unWrap(List<?> results) {
143 final ArrayList<Object> ret = new ArrayList<Object>(results.size());
144 for (Iterator<?> it = results.iterator(); it.hasNext();) {
145 ret.add(unWrapNS(it.next()));
146 }
147 return ret;
148 }
149
150 /**
151 * Creates a new XPath wrapper object, compiling the specified XPath
152 * expression.
153 *
154 * @param expr
155 * the XPath expression to wrap.
156 * @throws JDOMException
157 * if the XPath expression is invalid.
158 */
159 public JDOMXPath(String expr)
160 throws JDOMException {
161 setXPath(expr);
162 }
163
164 /**
165 * Evaluates the wrapped XPath expression and returns the list of selected
166 * items.
167 *
168 * @param context
169 * the node to use as context for evaluating the XPath expression.
170 * @return the list of selected items, which may be of types: {@link Element}
171 * , {@link Attribute}, {@link Text}, {@link CDATA}, {@link Comment}
172 * , {@link ProcessingInstruction}, Boolean, Double, or String.
173 * @throws JDOMException
174 * if the evaluation of the XPath expression on the specified
175 * context failed.
176 */
177 @Override
178 public List<?> selectNodes(Object context)
179 throws JDOMException {
180 try {
181 navigator.setContext(context);
182
183 return unWrap(xPath.selectNodes(context));
184 } catch (JaxenException ex1) {
185 throw new JDOMException(
186 "XPath error while evaluating \"" + xPath.toString()
187 + "\": " + ex1.getMessage(), ex1);
188 } finally {
189 navigator.reset();
190 }
191 }
192
193 /**
194 * Evaluates the wrapped XPath expression and returns the first entry in the
195 * list of selected nodes (or atomics).
196 *
197 * @param context
198 * the node to use as context for evaluating the XPath expression.
199 * @return the first selected item, which may be of types: {@link Element},
200 * {@link Attribute}, {@link Text}, {@link CDATA}, {@link Comment},
201 * {@link ProcessingInstruction}, Boolean, Double, String, or
202 * <code>null</code> if no item was selected.
203 * @throws JDOMException
204 * if the evaluation of the XPath expression on the specified
205 * context failed.
206 */
207 @Override
208 public Object selectSingleNode(Object context)
209 throws JDOMException {
210 try {
211 navigator.setContext(context);
212
213 return unWrapNS(xPath.selectSingleNode(context));
214 } catch (JaxenException ex1) {
215 throw new JDOMException(
216 "XPath error while evaluating \"" + xPath.toString()
217 + "\": " + ex1.getMessage(), ex1);
218 } finally {
219 navigator.reset();
220 }
221 }
222
223 /**
224 * Returns the string value of the first node selected by applying the
225 * wrapped XPath expression to the given context.
226 *
227 * @param context
228 * the element to use as context for evaluating the XPath expression.
229 * @return the string value of the first node selected by applying the
230 * wrapped XPath expression to the given context.
231 * @throws JDOMException
232 * if the XPath expression is invalid or its evaluation on the
233 * specified context failed.
234 */
235 @Override
236 public String valueOf(Object context) throws JDOMException {
237 try {
238 navigator.setContext(context);
239
240 return xPath.stringValueOf(context);
241 } catch (JaxenException ex1) {
242 throw new JDOMException(
243 "XPath error while evaluating \"" + xPath.toString()
244 + "\": " + ex1.getMessage(), ex1);
245 } finally {
246 navigator.reset();
247 }
248 }
249
250 /**
251 * Returns the number value of the first item selected by applying the
252 * wrapped XPath expression to the given context.
253 *
254 * @param context
255 * the element to use as context for evaluating the XPath expression.
256 * @return the number value of the first item selected by applying the
257 * wrapped XPath expression to the given context, <code>null</code>
258 * if no node was selected or the special value
259 * {@link java.lang.Double#NaN} (Not-a-Number) if the selected value
260 * can not be converted into a number value.
261 * @throws JDOMException
262 * if the XPath expression is invalid or its evaluation on the
263 * specified context failed.
264 */
265 @Override
266 public Number numberValueOf(Object context) throws JDOMException {
267 try {
268 navigator.setContext(context);
269
270 return xPath.numberValueOf(context);
271 } catch (JaxenException ex1) {
272 throw new JDOMException(
273 "XPath error while evaluating \"" + xPath.toString()
274 + "\": " + ex1.getMessage(), ex1);
275 } finally {
276 navigator.reset();
277 }
278 }
279
280 /**
281 * Defines an XPath variable and sets its value.
282 *
283 * @param name
284 * the variable name.
285 * @param value
286 * the variable value.
287 * @throws IllegalArgumentException
288 * if <code>name</code> is not a valid XPath variable name or if the
289 * value type is not supported by the underlying implementation
290 */
291 @Override
292 public void setVariable(String name, Object value)
293 throws IllegalArgumentException {
294 Object o = xPath.getVariableContext();
295 if (o instanceof SimpleVariableContext) {
296 ((SimpleVariableContext) o).setVariableValue(null, name, value);
297 }
298 }
299
300 /**
301 * Adds a namespace definition to the list of namespaces known of this XPath
302 * expression.
303 * <p>
304 * <strong>Note</strong>: In XPath, there is no such thing as a 'default
305 * namespace'. The empty prefix <b>always</b> resolves to the empty
306 * namespace URI.
307 * </p>
308 *
309 * @param namespace
310 * the namespace.
311 */
312 @Override
313 public void addNamespace(Namespace namespace) {
314 navigator.includeNamespace(namespace);
315 }
316
317 /**
318 * Returns the wrapped XPath expression as a string.
319 *
320 * @return the wrapped XPath expression as a string.
321 */
322 @Override
323 public String getXPath() {
324 return (xPath.toString());
325 }
326
327 /**
328 * Compiles and sets the XPath expression wrapped by this object.
329 *
330 * @param expr
331 * the XPath expression to wrap.
332 * @throws JDOMException
333 * if the XPath expression is invalid.
334 */
335 private void setXPath(String expr) throws JDOMException {
336 try {
337 xPath = new BaseXPath(expr, navigator);
338 xPath.setNamespaceContext(navigator);
339 } catch (Exception ex1) {
340 throw new JDOMException("Invalid XPath expression: \""
341 + expr + "\"", ex1);
342 }
343 }
344
345 @Override
346 public String toString() {
347 return (String.format("[XPath: %s]", xPath.toString()));
348 }
349
350 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath.jaxen;
55
56 import java.util.ArrayList;
57 import java.util.Iterator;
58 import java.util.List;
59 import java.util.Map;
60
61 import org.jaxen.BaseXPath;
62 import org.jaxen.JaxenException;
63 import org.jaxen.NamespaceContext;
64 import org.jaxen.UnresolvableException;
65 import org.jaxen.VariableContext;
66 import org.jaxen.XPath;
67
68 import org.jdom.Namespace;
69 import org.jdom.filter2.Filter;
70 import org.jdom.xpath.util.AbstractXPathCompiled;
71
72 /**
73 * Jaxen specific code for XPath management.
74 *
75 * @author Rolf Lear
76 * @param <T>
77 * The generic type of returned data.
78 */
79 class JaxenCompiled<T> extends AbstractXPathCompiled<T> implements
80 NamespaceContext, VariableContext {
81
82 /**
83 * Same story, need to be able to strip NamespaceContainer instances from
84 * Namespace content.
85 *
86 * @param o
87 * A result object which could potentially be a NamespaceContainer
88 * @return The input parameter unless it is a NamespaceContainer in which
89 * case return the wrapped Namespace
90 */
91 private static final Object unWrapNS(Object o) {
92 if (o instanceof NamespaceContainer) {
93 return ((NamespaceContainer) o).getNamespace();
94 }
95 return o;
96 }
97
98 /**
99 * Same story, need to be able to replace NamespaceContainer instances with
100 * Namespace content.
101 *
102 * @param results
103 * A list potentially containing NamespaceContainer instances
104 * @return The parameter list with NamespaceContainer instances replaced by
105 * the wrapped Namespace instances.
106 */
107 private static final List<Object> unWrap(List<?> results) {
108 final ArrayList<Object> ret = new ArrayList<Object>(results.size());
109 for (Iterator<?> it = results.iterator(); it.hasNext();) {
110 ret.add(unWrapNS(it.next()));
111 }
112 return ret;
113 }
114
115 /**
116 * The compiled XPath object to select nodes. This attribute can not be made
117 * final as it needs to be set upon object deserialization.
118 */
119 private final XPath xPath;
120
121 /**
122 * The current context for XPath expression evaluation. The navigator is
123 * responsible for exposing JDOM content to Jaxen, including the wrapping of
124 * Namespace instances in NamespaceContainer
125 * <p>
126 * Because of the need to wrap Namespace, we also need to unwrap namespace.
127 * Further, we can't re-use the details from one 'selectNodes' to another
128 * because the Document tree may have been modfied between, and also, we do
129 * not want to be holding on to memory.
130 * <p>
131 * Finally, we want to pre-load the NamespaceContext with the namespaces
132 * that are in scope for the contextNode being searched.
133 * <p>
134 * So, we need to reset the Navigator before and after each use. try{}
135 * finally {} to the rescue.
136 */
137 private final JDOM2Navigator navigator = new JDOM2Navigator();
138
139 /**
140 * @param expression The XPath expression
141 * @param filter The coercion filter
142 * @param variables The XPath variable context
143 * @param namespaces The XPath namespace context
144 */
145 public JaxenCompiled(String expression, Filter<T> filter,
146 Map<String, Object> variables, Namespace[] namespaces) {
147 super(expression, filter, variables, namespaces);
148 try {
149 xPath = new BaseXPath(expression, navigator);
150 } catch (JaxenException e) {
151 throw new IllegalArgumentException("Unable to compile '" + expression
152 + "'. See Cause.", e);
153 }
154 xPath.setNamespaceContext(this);
155 xPath.setVariableContext(this);
156 }
157
158 /**
159 * Make a copy-constructor available to the clone() method.
160 * This is simpler than trying to do a deep clone anyway.
161 *
162 * @param toclone The JaxenCompiled instance to clone
163 */
164 private JaxenCompiled(JaxenCompiled<T> toclone) {
165 this(toclone.getExpression(), toclone.getFilter(), toclone.getVariables(), toclone.getNamespaces());
166 }
167
168 @Override
169 public String translateNamespacePrefixToUri(String prefix) {
170 return getNamespace(prefix).getURI();
171 }
172
173 @Override
174 public Object getVariableValue(String namespaceURI, String prefix,
175 String localName) throws UnresolvableException {
176 if (namespaceURI == null) {
177 namespaceURI = "";
178 }
179 if (prefix == null) {
180 prefix = "";
181 }
182 try {
183 if ("".equals(namespaceURI)) {
184 namespaceURI = getNamespace(prefix).getURI();
185 }
186 return getVariable(localName, Namespace.getNamespace(namespaceURI));
187 } catch (IllegalArgumentException e) {
188 throw new UnresolvableException("Unable to resolve variable " +
189 localName + " in namespace '" + namespaceURI +
190 "' to a vaulue.");
191 }
192 }
193
194 @Override
195 protected List<?> evaluateRawAll(Object context) {
196 try {
197 return unWrap(xPath.selectNodes(context));
198 } catch (JaxenException e) {
199 throw new IllegalStateException(
200 "Unable to evaluate expression. See cause", e);
201 }
202 }
203
204 @Override
205 protected Object evaluateRawFirst(Object context) {
206 try {
207 return unWrapNS(xPath.selectSingleNode(context));
208 } catch (JaxenException e) {
209 throw new IllegalStateException(
210 "Unable to evaluate expression. See cause", e);
211 }
212 }
213
214 @Override
215 public JaxenCompiled<T> clone() {
216 // Use a copy-constructor instead of a deep clone.
217 // we have a couple of final variables on this class that we cannot share
218 // between instances, and the Jaxen xpath variable is pretty complicated to reconstruct
219 // anyway. Easier to just reconstruct it.
220 return new JaxenCompiled<T>(this);
221 }
222
223 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath.jaxen;
55
56 import java.util.Map;
57
58 import org.jdom.Namespace;
59 import org.jdom.filter2.Filter;
60 import org.jdom.xpath.XPathExpression;
61 import org.jdom.xpath.XPathFactory;
62
63 /**
64 * This simple Factory creates XPath instances tailored to the Jaxen library.
65 *
66 * @author Rolf Lear
67 *
68 */
69 public class JaxenXPathFactory extends XPathFactory {
70
71 /**
72 * The public default constructor used by the XPathFactory.
73 */
74 public JaxenXPathFactory() {
75 // do nothing.
76 }
77
78 @Override
79 public <T> XPathExpression<T> compile(String expression, Filter<T> filter,
80 Map<String, Object> variables, Namespace... namespaces) {
81 return new JaxenCompiled<T>(expression, filter, variables, namespaces);
82 }
83
84 }
0 /*--
1
2 Copyright (C) 2011-2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath.jaxen;
55
56 import org.jdom.Element;
57 import org.jdom.Namespace;
58
59 /**
60 * XPath requires that the namespace nodes are linked to an Element.
61 * JDOM does not have such a relationship, so we improvise.
62 * Jaxen uses the identity equals ( == ) when comparing
63 * one 'node' to another, so we have to make sure that within the context of
64 * Jaxen we always return the same instances of NamespaceContainer each time.
65 * Further, for jaxen the instance of a Namespace for one Node cannot be the
66 * same instance of the same Namespace on a different Node...
67 * <p>
68 * This all also means that all Jaxen interaction is done with NamespaceContainer
69 * and not the JDOM Namespace, which in turn means that when Jaxen returns
70 * a NamespaceContainer node, it has to be unwrapped to a simple Namespace.
71 *
72 * @author rolf
73 *
74 */
75 final class NamespaceContainer {
76
77 private final Namespace ns;
78 private final Element emt;
79
80 public NamespaceContainer(Namespace ns, Element emt) {
81 this.ns = ns;
82 this.emt = emt;
83 }
84
85 public Namespace getNamespace() {
86 return ns;
87 }
88
89 public Element getParentElement() {
90 return emt;
91 }
92
93 @Override
94 public String toString() {
95 return ns.getPrefix() + "=" + ns.getURI();
96 }
97 }
0 <body>
1 Support for the <a href="http://jaxen.codehaus.org/">Jaxen XPath Library</a>.
2 </body>
0 <body>
1
2 Support for XPath from within JDOM. XPath provides a common interface
3 with a pluggable back-end. The default back end is Jaxen.
4 <p>The JDOM 1.x API uses the XPath class as the entire API
5 interface. This has been deprecated, and replaced with XPathFactory,
6 XPathCompiled, and XPathBuilder.
7 <p>
8 Please see the web page for the details on the
9 <a href="https://github.com/hunterhacker/jdom/wiki/JDOM2-Feature-XPath-Upgrade">
10 JDOM2 XPath API change</a>.
11 <p>
12 The XPathHelper class provides static methods to create XPath queries
13 that identify specific JDOM nodes.
14 </body>
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath.util;
55
56 import java.util.Arrays;
57 import java.util.Collections;
58 import java.util.Comparator;
59 import java.util.HashMap;
60 import java.util.List;
61 import java.util.Map;
62
63 import org.jdom.Namespace;
64 import org.jdom.Verifier;
65 import org.jdom.filter2.Filter;
66 import org.jdom.xpath.XPathExpression;
67 import org.jdom.xpath.XPathDiagnostic;
68
69 /**
70 * A mostly-implemented XPathExpression that only needs two methods to be
71 * implemented in order to satisfy the complete API. Subclasses of this
72 * <strong>MUST</strong> correctly override the clone() method which in turn
73 * should call <code>super.clone();</code>
74 *
75 * @param <T>
76 * The generic type of the returned values.
77 * @author Rolf Lear
78 */
79 public abstract class AbstractXPathCompiled<T> implements XPathExpression<T> {
80
81 private static final class NamespaceComparator implements Comparator<Namespace> {
82 @Override
83 public int compare(Namespace ns1, Namespace ns2) {
84 return ns1.getPrefix().compareTo(ns2.getPrefix());
85 }
86 }
87
88 private static final NamespaceComparator NSSORT = new NamespaceComparator();
89
90 /**
91 * Utility method to find a Namespace that has a given URI, and return the prefix.
92 * @param uri the URI to search for
93 * @param nsa the array of namespaces to search through
94 * @return the prefix of the namespace
95 */
96 private static final String getPrefixForURI(final String uri, final Namespace[] nsa) {
97 for (final Namespace ns : nsa) {
98 if (ns.getURI().equals(uri)) {
99 return ns.getPrefix();
100 }
101 }
102 throw new IllegalStateException("No namespace defined with URI " + uri);
103 }
104
105 private final Map<String, Namespace> xnamespaces = new HashMap<String, Namespace>();
106 // Not final to support cloning.
107 private Map<String, Map<String, Object>> xvariables = new HashMap<String, Map<String, Object>>();
108 private final String xquery;
109 private final Filter<T> xfilter;
110
111 /**
112 * Construct an XPathExpression.
113 *
114 * @see XPathExpression for conditions which throw
115 * {@link NullPointerException} or {@link IllegalArgumentException}.
116 * @param query
117 * The XPath query
118 * @param filter
119 * The coercion filter.
120 * @param variables
121 * A map of variables.
122 * @param namespaces
123 * The namespaces referenced from the query.
124 */
125 public AbstractXPathCompiled(final String query, final Filter<T> filter,
126 final Map<String, Object> variables, final Namespace[] namespaces) {
127 if (query == null) {
128 throw new NullPointerException("Null query");
129 }
130 if (filter == null) {
131 throw new NullPointerException("Null filter");
132 }
133 xnamespaces.put(Namespace.NO_NAMESPACE.getPrefix(),
134 Namespace.NO_NAMESPACE);
135 if (namespaces != null) {
136 for (Namespace ns : namespaces) {
137 if (ns == null) {
138 throw new NullPointerException("Null namespace");
139 }
140 final Namespace oldns = xnamespaces.put(ns.getPrefix(), ns);
141 if (oldns != null && oldns != ns) {
142 if (oldns == Namespace.NO_NAMESPACE) {
143 throw new IllegalArgumentException(
144 "The default (no prefix) Namespace URI for XPath queries is always" +
145 " '' and it cannot be redefined to '" + ns.getURI() + "'.");
146 }
147 throw new IllegalArgumentException(
148 "A Namespace with the prefix '" + ns.getPrefix()
149 + "' has already been declared.");
150 }
151 }
152 }
153
154 if (variables != null) {
155 for (Map.Entry<String, Object> me : variables.entrySet()) {
156 final String qname = me.getKey();
157 if (qname == null) {
158 throw new NullPointerException("Variable with a null name");
159 }
160 final int p = qname.indexOf(':');
161 final String pfx = p < 0 ? "" : qname.substring(0, p);
162 final String lname = p < 0 ? qname : qname.substring(p + 1);
163
164 final String vpfxmsg = Verifier.checkNamespacePrefix(pfx);
165 if (vpfxmsg != null) {
166 throw new IllegalArgumentException("Prefix '" + pfx
167 + "' for variable " + qname + " is illegal: "
168 + vpfxmsg);
169 }
170 final String vnamemsg = Verifier.checkXMLName(lname);
171 if (vnamemsg != null) {
172 throw new IllegalArgumentException("Variable name '"
173 + lname + "' for variable " + qname
174 + " is illegal: " + vnamemsg);
175 }
176
177 final Namespace ns = xnamespaces.get(pfx);
178 if (ns == null) {
179 throw new IllegalArgumentException("Prefix '" + pfx
180 + "' for variable " + qname
181 + " has not been assigned a Namespace.");
182 }
183
184 Map<String, Object> vmap = xvariables.get(ns.getURI());
185 if (vmap == null) {
186 vmap = new HashMap<String, Object>();
187 xvariables.put(ns.getURI(), vmap);
188 }
189
190 if (vmap.put(lname, me.getValue()) != null) {
191 throw new IllegalArgumentException("Variable with name "
192 + me.getKey() + "' has already been defined.");
193 }
194 }
195 }
196 xquery = query;
197 xfilter = filter;
198 }
199
200 /**
201 * Subclasses of this AbstractXPathCompile class must call super.clone() in
202 * their clone methods!
203 * <p>
204 * This would be a sample clone method from a subclass:
205 *
206 *
207 * <code><pre>
208 * public XPathExpression&lt;T&gt; clone() {
209 * {@literal @}SuppressWarnings("unchecked")
210 * final MyXPathCompiled&lt;T&gt; ret = (MyXPathCompiled&lt;T&gt;)super.clone();
211 * // change any fields that need to be cloned.
212 * ....
213 * return ret;
214 * }
215 * </pre></code>
216 *
217 * Here's the documentation from {@link XPathExpression#clone()}
218 * <p>
219 * {@inheritDoc}
220 */
221 @Override
222 public XPathExpression<T> clone() {
223 AbstractXPathCompiled<T> ret = null;
224 try {
225 @SuppressWarnings("unchecked")
226 final AbstractXPathCompiled<T> c = (AbstractXPathCompiled<T>) super
227 .clone();
228 ret = c;
229 } catch (CloneNotSupportedException cnse) {
230 throw new IllegalStateException(
231 "Should never be getting a CloneNotSupportedException!",
232 cnse);
233 }
234 Map<String, Map<String, Object>> vmt = new HashMap<String, Map<String, Object>>();
235 for (Map.Entry<String, Map<String, Object>> me : xvariables.entrySet()) {
236 final Map<String, Object> cmap = new HashMap<String, Object>();
237 for (Map.Entry<String, Object> ne : me.getValue().entrySet()) {
238 cmap.put(ne.getKey(), ne.getValue());
239 }
240 vmt.put(me.getKey(), cmap);
241 }
242 ret.xvariables = vmt;
243 return ret;
244 }
245
246 @Override
247 public final String getExpression() {
248 return xquery;
249 }
250
251 @Override
252 public final Namespace getNamespace(final String prefix) {
253 final Namespace ns = xnamespaces.get(prefix);
254 if (ns == null) {
255 throw new IllegalArgumentException("Namespace with prefix '"
256 + prefix + "' has not been declared.");
257 }
258 return ns;
259 }
260
261 @Override
262 public Namespace[] getNamespaces() {
263 final Namespace[] nsa = xnamespaces.values().toArray(
264 new Namespace[xnamespaces.size()]);
265 Arrays.sort(nsa, NSSORT);
266 return nsa;
267 }
268
269 @Override
270 public final Object getVariable(final String name, Namespace uri) {
271 final Map<String, Object> vmap =
272 xvariables.get(uri == null ? "" : uri.getURI());
273 if (vmap == null) {
274 throw new IllegalArgumentException("Variable with name '" + name
275 + "' in namespace '" + uri.getURI() + "' has not been declared.");
276 }
277 final Object ret = vmap.get(name);
278 if (ret == null) {
279 if (!vmap.containsKey(name)) {
280 throw new IllegalArgumentException("Variable with name '"
281 + name + "' in namespace '" + uri.getURI()
282 + "' has not been declared.");
283 }
284 // leave translating null variable values to the implementation.
285 return null;
286 }
287 return ret;
288 }
289
290 @Override
291 public Object getVariable(String qname) {
292 if (qname == null) {
293 throw new NullPointerException(
294 "Cannot get variable value for null qname");
295 }
296 final int pos = qname.indexOf(':');
297 if (pos >= 0) {
298 return getVariable(qname.substring(pos + 1),
299 getNamespace(qname.substring(0, pos)));
300 }
301 return getVariable(qname, Namespace.NO_NAMESPACE);
302 }
303
304 @Override
305 public Object setVariable(String name, Namespace uri, Object value) {
306 final Object ret = getVariable(name, uri);
307 // if that succeeded then we have it easy....
308 xvariables.get(uri.getURI()).put(name, value);
309 return ret;
310 }
311
312 @Override
313 public Object setVariable(String qname, Object value) {
314 if (qname == null) {
315 throw new NullPointerException(
316 "Cannot get variable value for null qname");
317 }
318 final int pos = qname.indexOf(':');
319 if (pos >= 0) {
320 return setVariable(qname.substring(pos + 1),
321 getNamespace(qname.substring(0, pos)), value);
322 }
323 return setVariable(qname, Namespace.NO_NAMESPACE, value);
324 }
325
326 /**
327 * utility method that allows descendant classes to access the variables
328 * that were set on this expression, in a format that can be used in a constructor (qname/value).
329 * @return the variables set on this instance.
330 */
331 protected Map<String,Object> getVariables() {
332 HashMap<String,Object> vars = new HashMap<String, Object>();
333 Namespace[] nsa = getNamespaces();
334 for (Map.Entry<String, Map<String,Object>> ue : xvariables.entrySet()) {
335 final String uri = ue.getKey();
336 final String pfx = getPrefixForURI(uri, nsa);
337 for (Map.Entry<String, Object> ve : ue.getValue().entrySet()) {
338 if ("".equals(pfx)) {
339 vars.put(ve.getKey(), ve.getValue());
340 } else {
341 vars.put(pfx + ":" + ve.getKey(), ve.getValue());
342 }
343 }
344 }
345 return vars;
346 }
347
348 @Override
349 public final Filter<T> getFilter() {
350 return xfilter;
351 }
352
353 @Override
354 public List<T> evaluate(Object context) {
355 return xfilter.filter(evaluateRawAll(context));
356 }
357
358 /**
359 *
360 */
361 @Override
362 public T evaluateFirst(Object context) {
363 Object raw = evaluateRawFirst(context);
364 if (raw == null) {
365 return null;
366 }
367 return xfilter.filter(raw);
368 }
369
370 @Override
371 public XPathDiagnostic<T> diagnose(Object context, boolean firstonly) {
372 final List<?> result = firstonly ? Collections
373 .singletonList(evaluateRawFirst(context))
374 : evaluateRawAll(context);
375 return new XPathDiagnosticImpl<T>(context, this, result, firstonly);
376 }
377
378 @Override
379 public String toString() {
380 int nscnt = xnamespaces.size();
381 int vcnt = 0;
382 for (Map<String, Object> cmap : xvariables.values()) {
383 vcnt += cmap.size();
384 }
385 return String.format(
386 "[XPathExpression: %d namespaces and %d variables for query %s]",
387 nscnt, vcnt, getExpression());
388 }
389
390 /**
391 * This is the raw expression evaluator to be implemented by the back-end
392 * XPath library.
393 *
394 * @param context
395 * The context against which to evaluate the query
396 * @return A list of XPath results.
397 */
398 protected abstract List<?> evaluateRawAll(Object context);
399
400 /**
401 * This is the raw expression evaluator to be implemented by the back-end
402 * XPath library. When this method is processed the implementing library is
403 * free to stop processing when the result that would be the first result is
404 * retrieved.
405 * <p>
406 * Only the first value in the result will be processed (if any).
407 *
408 * @param context
409 * The context against which to evaluate the query
410 * @return The first item in the XPath results, or null if there are no
411 * results.
412 */
413 protected abstract Object evaluateRawFirst(Object context);
414
415 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.xpath.util;
55
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.List;
59
60 import org.jdom.filter2.Filter;
61 import org.jdom.xpath.XPathExpression;
62 import org.jdom.xpath.XPathDiagnostic;
63
64 /**
65 * A diagnostic implementation useful for diagnosing problems in XPath results.
66 * <p>
67 * This class tries to make all the data available as part of the internal
68 * structure which may assist people who are stepping-through the code from
69 * a debugging environment.
70 *
71 * @author Rolf Lear
72 *
73 * @param <T> The generic type of the results from the {@link XPathExpression}
74 */
75 public class XPathDiagnosticImpl<T> implements XPathDiagnostic<T> {
76
77 /*
78 * Keep nice list references here to help users who debug and step through
79 * code. They can inspect the various lists directly.
80 */
81 private final Object dcontext;
82 private final XPathExpression<T> dxpath;
83 private final List<Object> draw;
84 private final List<Object> dfiltered;
85 private final List<T> dresult;
86 private final boolean dfirstonly;
87
88 /**
89 * Create a useful Diagnostic instance for tracing XPath query results.
90 * @param dcontext The context against which the XPath query was run.
91 * @param dxpath The {@link XPathExpression} instance which created this diagnostic.
92 * @param inraw The data as returned from the XPath library.
93 * @param dfirstonly If the XPath library was allowed to terminate after the first result.
94 */
95 public XPathDiagnosticImpl(Object dcontext, XPathExpression<T> dxpath,
96 List<?> inraw, boolean dfirstonly) {
97
98 final int sz = inraw.size();
99 final List<Object> raw = new ArrayList<Object>(sz);
100 final List<Object> filtered = new ArrayList<Object>(sz);
101 final List<T> result = new ArrayList<T>(sz);
102 final Filter<T> filter = dxpath.getFilter();
103
104 for (Object o : inraw) {
105 raw.add(o);
106 T t = filter.filter(o);
107 if (t == null) {
108 filtered.add(o);
109 } else {
110 result.add(t);
111 }
112 }
113
114 this.dcontext = dcontext;
115 this.dxpath = dxpath;
116 this.dfirstonly = dfirstonly;
117
118 this.dfiltered = Collections.unmodifiableList(filtered);
119 this.draw = Collections.unmodifiableList(raw);
120 this.dresult = Collections.unmodifiableList(result);
121
122 }
123
124 @Override
125 public Object getContext() {
126 return dcontext;
127 }
128
129 @Override
130 public XPathExpression<T> getXPathExpression() {
131 return dxpath;
132 }
133
134 @Override
135 public List<T> getResult() {
136 return dresult;
137 }
138
139 @Override
140 public List<Object> getFilteredResults() {
141 return dfiltered;
142 }
143
144 @Override
145 public List<Object> getRawResults() {
146 return draw;
147 }
148
149 @Override
150 public boolean isFirstOnly() {
151 return dfirstonly;
152 }
153
154 @Override
155 public String toString() {
156 return String.format("[XPathDiagnostic: '%s' evaluated (%s) against " +
157 "%s produced raw=%d discarded=%d returned=%d]",
158 dxpath.getExpression(), (dfirstonly ? "first" : "all"),
159 dcontext.getClass().getName(), draw.size(), dfiltered.size(),
160 dresult.size());
161 }
162
163 }
0 <body>
1 Classes useful for interfacing the JDOM XPath API to full XPath libraries.
2 </body>
0 #!/usr/bin/env sh
1
2 ##############################################################################
3 ##
4 ## Gradle start up script for UN*X
5 ##
6 ##############################################################################
7
8 # Attempt to set APP_HOME
9 # Resolve links: $0 may be a link
10 PRG="$0"
11 # Need this for relative symlinks.
12 while [ -h "$PRG" ] ; do
13 ls=`ls -ld "$PRG"`
14 link=`expr "$ls" : '.*-> \(.*\)$'`
15 if expr "$link" : '/.*' > /dev/null; then
16 PRG="$link"
17 else
18 PRG=`dirname "$PRG"`"/$link"
19 fi
20 done
21 SAVED="`pwd`"
22 cd "`dirname \"$PRG\"`/" >/dev/null
23 APP_HOME="`pwd -P`"
24 cd "$SAVED" >/dev/null
25
26 APP_NAME="Gradle"
27 APP_BASE_NAME=`basename "$0"`
28
29 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
30 DEFAULT_JVM_OPTS=""
31
32 # Use the maximum available, or set MAX_FD != -1 to use that value.
33 MAX_FD="maximum"
34
35 warn () {
36 echo "$*"
37 }
38
39 die () {
40 echo
41 echo "$*"
42 echo
43 exit 1
44 }
45
46 # OS specific support (must be 'true' or 'false').
47 cygwin=false
48 msys=false
49 darwin=false
50 nonstop=false
51 case "`uname`" in
52 CYGWIN* )
53 cygwin=true
54 ;;
55 Darwin* )
56 darwin=true
57 ;;
58 MINGW* )
59 msys=true
60 ;;
61 NONSTOP* )
62 nonstop=true
63 ;;
64 esac
65
66 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
67
68 # Determine the Java command to use to start the JVM.
69 if [ -n "$JAVA_HOME" ] ; then
70 if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
71 # IBM's JDK on AIX uses strange locations for the executables
72 JAVACMD="$JAVA_HOME/jre/sh/java"
73 else
74 JAVACMD="$JAVA_HOME/bin/java"
75 fi
76 if [ ! -x "$JAVACMD" ] ; then
77 die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
78
79 Please set the JAVA_HOME variable in your environment to match the
80 location of your Java installation."
81 fi
82 else
83 JAVACMD="java"
84 which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
85
86 Please set the JAVA_HOME variable in your environment to match the
87 location of your Java installation."
88 fi
89
90 # Increase the maximum file descriptors if we can.
91 if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
92 MAX_FD_LIMIT=`ulimit -H -n`
93 if [ $? -eq 0 ] ; then
94 if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
95 MAX_FD="$MAX_FD_LIMIT"
96 fi
97 ulimit -n $MAX_FD
98 if [ $? -ne 0 ] ; then
99 warn "Could not set maximum file descriptor limit: $MAX_FD"
100 fi
101 else
102 warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
103 fi
104 fi
105
106 # For Darwin, add options to specify how the application appears in the dock
107 if $darwin; then
108 GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
109 fi
110
111 # For Cygwin, switch paths to Windows format before running java
112 if $cygwin ; then
113 APP_HOME=`cygpath --path --mixed "$APP_HOME"`
114 CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
115 JAVACMD=`cygpath --unix "$JAVACMD"`
116
117 # We build the pattern for arguments to be converted via cygpath
118 ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
119 SEP=""
120 for dir in $ROOTDIRSRAW ; do
121 ROOTDIRS="$ROOTDIRS$SEP$dir"
122 SEP="|"
123 done
124 OURCYGPATTERN="(^($ROOTDIRS))"
125 # Add a user-defined pattern to the cygpath arguments
126 if [ "$GRADLE_CYGPATTERN" != "" ] ; then
127 OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
128 fi
129 # Now convert the arguments - kludge to limit ourselves to /bin/sh
130 i=0
131 for arg in "$@" ; do
132 CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
133 CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
134
135 if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
136 eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
137 else
138 eval `echo args$i`="\"$arg\""
139 fi
140 i=$((i+1))
141 done
142 case $i in
143 (0) set -- ;;
144 (1) set -- "$args0" ;;
145 (2) set -- "$args0" "$args1" ;;
146 (3) set -- "$args0" "$args1" "$args2" ;;
147 (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
148 (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
149 (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
150 (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
151 (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
152 (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
153 esac
154 fi
155
156 # Escape application args
157 save () {
158 for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
159 echo " "
160 }
161 APP_ARGS=$(save "$@")
162
163 # Collect all arguments for the java command, following the shell quoting and substitution rules
164 eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
165
166 # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
167 if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
168 cd "$(dirname "$0")"
169 fi
170
171 exec "$JAVACMD" "$@"
0 @if "%DEBUG%" == "" @echo off
1 @rem ##########################################################################
2 @rem
3 @rem Gradle startup script for Windows
4 @rem
5 @rem ##########################################################################
6
7 @rem Set local scope for the variables with windows NT shell
8 if "%OS%"=="Windows_NT" setlocal
9
10 set DIRNAME=%~dp0
11 if "%DIRNAME%" == "" set DIRNAME=.
12 set APP_BASE_NAME=%~n0
13 set APP_HOME=%DIRNAME%
14
15 @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
16 set DEFAULT_JVM_OPTS=
17
18 @rem Find java.exe
19 if defined JAVA_HOME goto findJavaFromJavaHome
20
21 set JAVA_EXE=java.exe
22 %JAVA_EXE% -version >NUL 2>&1
23 if "%ERRORLEVEL%" == "0" goto init
24
25 echo.
26 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
27 echo.
28 echo Please set the JAVA_HOME variable in your environment to match the
29 echo location of your Java installation.
30
31 goto fail
32
33 :findJavaFromJavaHome
34 set JAVA_HOME=%JAVA_HOME:"=%
35 set JAVA_EXE=%JAVA_HOME%/bin/java.exe
36
37 if exist "%JAVA_EXE%" goto init
38
39 echo.
40 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
41 echo.
42 echo Please set the JAVA_HOME variable in your environment to match the
43 echo location of your Java installation.
44
45 goto fail
46
47 :init
48 @rem Get command-line arguments, handling Windows variants
49
50 if not "%OS%" == "Windows_NT" goto win9xME_args
51
52 :win9xME_args
53 @rem Slurp the command line arguments.
54 set CMD_LINE_ARGS=
55 set _SKIP=2
56
57 :win9xME_args_slurp
58 if "x%~1" == "x" goto execute
59
60 set CMD_LINE_ARGS=%*
61
62 :execute
63 @rem Setup the command line
64
65 set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
66
67 @rem Execute Gradle
68 "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
69
70 :end
71 @rem End local scope for the variables with windows NT shell
72 if "%ERRORLEVEL%"=="0" goto mainEnd
73
74 :fail
75 rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
76 rem the _cmd.exe /c_ return code!
77 if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
78 exit /b 1
79
80 :mainEnd
81 if "%OS%"=="Windows_NT" endlocal
82
83 :omega
0 <project>
1 <modelVersion>4.0.0</modelVersion>
2 <groupId>org.jdom</groupId>
3 <artifactId>@artifactID@</artifactId>
4 <packaging>jar</packaging>
5
6 <name>JDOM</name>
7 <version>@version@</version>
8
9 <description>
10 A complete, Java-based solution for accessing, manipulating,
11 and outputting XML data
12 </description>
13 <url>http://www.jdom.org</url>
14
15 <organization>
16 <name>JDOM</name>
17 <url>http://www.jdom.org</url>
18 </organization>
19
20 <mailingLists>
21 <mailingList>
22 <name>JDOM-interest Mailing List</name>
23 <post>jdom-interest@jdom.org</post>
24 <archive>http://jdom.markmail.org/</archive>
25 </mailingList>
26 </mailingLists>
27
28 <licenses>
29 <license>
30 <name>Similar to Apache License but with the acknowledgment clause removed</name>
31 <url>https://raw.github.com/hunterhacker/jdom/master/LICENSE.txt</url>
32 <distribution>repo</distribution>
33 <comments xml:space="preserve"><![CDATA[
34
35 @license@
36
37 ]]></comments>
38 </license>
39 </licenses>
40
41 <scm>
42 <url>git@github.com:/hunterhacker/jdom</url>
43 <connection>scm:git:git@github.com:hunterhacker/jdom</connection>
44 <developerConnection>scm:git:git@github.com:hunterhacker/jdom</developerConnection>
45 </scm>
46
47 <developers>
48 <developer>
49 <id>hunterhacker</id>
50 <name>Jason Hunter</name>
51 <email>jhunter@servlets.com</email>
52 </developer>
53 <developer>
54 <id>rolfl</id>
55 <name>Rolf Lear</name>
56 <email>jdom@tuis.net</email>
57 </developer>
58 </developers>
59
60 <dependencies>
61 <dependency>
62 <groupId>jaxen</groupId>
63 <artifactId>jaxen</artifactId>
64 <version>1.1.6</version>
65 <optional>true</optional>
66 </dependency>
67 <dependency>
68 <groupId>xerces</groupId>
69 <artifactId>xercesImpl</artifactId>
70 <version>2.11.0</version>
71 <optional>true</optional>
72 </dependency>
73 <dependency>
74 <groupId>xalan</groupId>
75 <artifactId>xalan</artifactId>
76 <version>2.7.2</version>
77 <optional>true</optional>
78 </dependency>
79
80 </dependencies>
81
82 <properties>
83 <jdk.version>@jdk@</jdk.version>
84 </properties>
85 </project>
0 include 'core', 'test', 'contrib'
0 /build
1 /out
0 Introduction
1 ============
2
3 this 'test' folder is the home for a set of test cases covering all aspects
4 of JDOM behavior, used to ensure the JDOM core library consistently behaves as
5 documented. My expectation is that we'll run these tests before every
6 check-in. Currently the module includes a set of JUnit library. Your help in
7 fleshing out the test cases is most welcome. Send patches to the
8 jdom-interest list.
9
10 You can run the test cases with 'ant junit' in the parent directory.
11
0 dependencies {
1 compile project(':core')
2 testCompile project(':contrib')
3 testCompile 'junit:junit:4.12'
4 testRuntime 'jaxen:jaxen:1.1.6'
5 }
6
7 sourceSets {
8 test {
9 java {
10 srcDir 'src/java'
11 }
12 resources {
13 srcDir 'src/resources'
14 }
15 resources {
16 srcDir 'src/java'
17 include '**/*.xml', '**/*.xsd', '**/*.dtd'
18 }
19 }
20 }
21
0 package org.jdom;
1
2 import static org.junit.Assert.*;
3
4 import org.junit.Test;
5
6 @SuppressWarnings("javadoc")
7 public class TestIllegalAddExceptn {
8
9 @Test
10 public void testIllegalAddExceptionElementAttributeString() {
11 DefaultJDOMFactory fac = new DefaultJDOMFactory();
12 assertTrue (null !=
13 new IllegalAddException(fac.element("emt"),
14 fac.attribute("att", "val"), "msg").getMessage());
15 }
16
17 @Test
18 public void testIllegalAddExceptionElementElementString() {
19 DefaultJDOMFactory fac = new DefaultJDOMFactory();
20 assertTrue (null !=
21 new IllegalAddException(fac.element("emt1"),
22 fac.element("emt2"), "msg").getMessage());
23 }
24
25 @Test
26 public void testIllegalAddExceptionElementString() {
27 DefaultJDOMFactory fac = new DefaultJDOMFactory();
28 assertTrue (null !=
29 new IllegalAddException(fac.element("emt"),
30 "msg").getMessage());
31 }
32
33 @Test
34 public void testIllegalAddExceptionElementProcessingInstructionString() {
35 DefaultJDOMFactory fac = new DefaultJDOMFactory();
36 assertTrue (null !=
37 new IllegalAddException(fac.element("emt"),
38 fac.processingInstruction("target", "data"), "msg").getMessage());
39 }
40
41 @Test
42 public void testIllegalAddExceptionProcessingInstructionString() {
43 DefaultJDOMFactory fac = new DefaultJDOMFactory();
44 assertTrue (null !=
45 new IllegalAddException(fac.processingInstruction("target", "data"),
46 "msg").getMessage());
47 }
48
49 @Test
50 public void testIllegalAddExceptionElementCommentString() {
51 DefaultJDOMFactory fac = new DefaultJDOMFactory();
52 assertTrue (null !=
53 new IllegalAddException(fac.element("emt"),
54 fac.comment("no comment!"), "msg").getMessage());
55 }
56
57 @Test
58 public void testIllegalAddExceptionElementCDATAString() {
59 DefaultJDOMFactory fac = new DefaultJDOMFactory();
60 assertTrue (null !=
61 new IllegalAddException(fac.element("emt"),
62 fac.cdata("cdata"), "msg").getMessage());
63 }
64
65 @Test
66 public void testIllegalAddExceptionElementTextString() {
67 DefaultJDOMFactory fac = new DefaultJDOMFactory();
68 assertTrue (null !=
69 new IllegalAddException(fac.element("emt"),
70 fac.text("text"), "msg").getMessage());
71 }
72
73 @Test
74 public void testIllegalAddExceptionCommentString() {
75 DefaultJDOMFactory fac = new DefaultJDOMFactory();
76 assertTrue (null !=
77 new IllegalAddException(fac.comment("no comment!"), "msg").getMessage());
78 }
79
80 @Test
81 public void testIllegalAddExceptionElementEntityRefString() {
82 DefaultJDOMFactory fac = new DefaultJDOMFactory();
83 assertTrue (null !=
84 new IllegalAddException(fac.element("emt"),
85 fac.entityRef("name"), "msg").getMessage());
86 }
87
88 @Test
89 public void testIllegalAddExceptionElementNamespaceString() {
90 DefaultJDOMFactory fac = new DefaultJDOMFactory();
91 assertTrue (null !=
92 new IllegalAddException(fac.element("emt"),
93 Namespace.getNamespace("prefix", "ns"), "msg").getMessage());
94 }
95
96 @Test
97 public void testIllegalAddExceptionDocTypeString() {
98 DefaultJDOMFactory fac = new DefaultJDOMFactory();
99 assertTrue (null !=
100 new IllegalAddException(
101 fac.docType("emt"), "msg").getMessage());
102 }
103
104 @Test
105 public void testIllegalAddExceptionString() {
106 assertTrue (null !=
107 new IllegalAddException("msg").getMessage());
108 }
109
110 }
0 package org.jdom;
1
2 import static org.junit.Assert.*;
3
4 import org.junit.Test;
5
6 @SuppressWarnings("javadoc")
7 public class TestIllegalNameExceptn {
8
9 @Test
10 public void testIllegalNameExceptionStringStringString() {
11 assertTrue (null !=
12 new IllegalNameException("name", "construct", "reason").getMessage());
13 }
14
15 @Test
16 public void testIllegalNameExceptionStringString() {
17 assertTrue (null !=
18 new IllegalNameException("name", "construct").getMessage());
19 }
20
21 @Test
22 public void testIllegalNameExceptionString() {
23 assertTrue (null !=
24 new IllegalNameException("reason").getMessage());
25 }
26
27 }
0 package org.jdom;
1
2 import static org.junit.Assert.*;
3
4 import org.junit.Test;
5
6 @SuppressWarnings("javadoc")
7 public class TestIllegalTargetExceptn {
8
9 @Test
10 public void testIllegalTargetExceptionStringString() {
11 assertTrue (null !=
12 new IllegalTargetException("target", "reason").getMessage());
13
14 }
15
16 @Test
17 public void testIllegalTargetExceptionString() {
18 assertTrue (null !=
19 new IllegalTargetException("reason").getMessage());
20 }
21
22 }
0 package org.jdom;
1
2 import static org.junit.Assert.*;
3
4 import org.jdom.test.util.UnitTestUtil;
5 import org.junit.Test;
6
7 @SuppressWarnings("javadoc")
8 public class TestStringBin {
9
10 // The following 4 all have the same hashcode 31776 ..... clever... huh?
11 private static final String[] samehc = new String[] {
12 "\u03FA\u00DA",
13 "\u0401\u0001",
14 "\u0400\u0020",
15 "\u03FF\u003F",
16 " ",
17 "\u03FE\u005E",
18 "\u03FD\u007D",
19 "\u03FC\u009C",
20 "\u03FB\u00BB",
21 };
22
23 @Test
24 public void testNegativeCapacity() {
25 try {
26 new StringBin(-1);
27 fail("excpect exception!");
28 } catch (Exception e) {
29 UnitTestUtil.checkException(IllegalArgumentException.class, e);
30 }
31 }
32
33 @Test
34 public void testSmallCapacity() {
35 assertNotNull(new StringBin(1));
36 }
37
38 @Test
39 public void testNull() {
40 StringBin bin = new StringBin();
41 assertNull(bin.reuse(null));
42 }
43
44 @Test
45 public void testSameHashCode() {
46 for (int i = 0; i < samehc.length; i++) {
47 int hc = samehc[i].hashCode();
48 if (hc != 31776) {
49 fail("Missed '" + samehc[i] + "' -> " + samehc[i].hashCode());
50 }
51 }
52 StringBin bin = new StringBin();
53 String[] actuals = new String[samehc.length];
54 for (int i = 0; i < samehc.length; i++) {
55 actuals[i] = bin.reuse(samehc[i]);
56 assertEquals(samehc[i], actuals[i]);
57 // should have compacted things.
58 assertTrue(samehc[i] != actuals[i]);
59 }
60 assertTrue(bin.size() == samehc.length);
61 for (int i = 0; i < samehc.length; i++) {
62 assertTrue(actuals[i] == bin.reuse(samehc[i]));
63 }
64 assertTrue(bin.size() == samehc.length);
65
66
67 bin = new StringBin();
68 for (int i = samehc.length - 1; i >= 0; i--) {
69 actuals[i] = bin.reuse(samehc[i]);
70 assertEquals(samehc[i], actuals[i]);
71 assertTrue(samehc[i] != actuals[i]);
72 }
73 for (int i = 0; i < samehc.length; i++) {
74 assertTrue(actuals[i] == bin.reuse(samehc[i]));
75 }
76 }
77
78 @Test
79 public final void bulkIntern() {
80 String[] tstvals = new String[1024 * 256];
81 String[] actvals = new String[tstvals.length];
82 String[] dupvals = new String[tstvals.length];
83 StringBin bin = new StringBin(2048);
84 int hc = 0;
85 for (int i = 0; i < tstvals.length; i++) {
86 tstvals[i] = "value " + i;
87 hc ^= tstvals[i].hashCode();
88 dupvals[i] = "value " + i;
89 hc ^= dupvals[i].hashCode();
90 }
91 assertTrue(hc == 0);
92 for (int i = 0; i < tstvals.length; i++) {
93 actvals[i] = bin.reuse(tstvals[i]);
94 assertTrue(tstvals[i] != actvals[i]);
95 assertEquals(tstvals[i], actvals[i]);
96 }
97 assertTrue(bin.size() == tstvals.length);
98
99 for (int i = 0; i < tstvals.length; i++) {
100 assertTrue(actvals[i] == bin.reuse(tstvals[i]));
101 }
102 assertTrue(bin.size() == tstvals.length);
103
104 for (int i = 0; i < tstvals.length; i++) {
105 assertTrue(actvals[i] == bin.reuse(dupvals[i]));
106 }
107 assertTrue(bin.size() == tstvals.length);
108
109 String[] acthc = new String[samehc.length];
110 for (int i = 0; i < samehc.length; i++) {
111 acthc[i] = bin.reuse(samehc[i]);
112 assertTrue(acthc[i] != samehc[i]);
113 assertEquals(samehc[i], acthc[i]);
114 }
115 assertTrue(bin.size() == tstvals.length + samehc.length);
116 for (int i = 0; i < samehc.length; i++) {
117 assertTrue(acthc[i] == bin.reuse(samehc[i]));
118 }
119 assertTrue(bin.size() == tstvals.length + samehc.length);
120 }
121
122 }
0 package org.jdom.input.sax;
1
2 import static org.junit.Assert.*;
3
4 import org.junit.Test;
5
6 @SuppressWarnings("javadoc")
7 public class TestTextBuffer {
8
9 @Test
10 public void testIsAllWhitespace() {
11 TextBuffer tb = new TextBuffer();
12 tb.append(" ".toCharArray(), 0, 3);
13 assertTrue(tb.isAllWhitespace());
14 tb.append("frodo".toCharArray(), 0, 4);
15 assertFalse(tb.isAllWhitespace());
16 }
17
18 @Test
19 public void testToString() {
20 // this tests the expansion of the backing array.
21 final StringBuilder sb = new StringBuilder();
22 final TextBuffer tb = new TextBuffer();
23 final char[] data = "frodo".toCharArray();
24 for (int i = 1000; i >= 0; i--) {
25 sb.append(data);
26 tb.append(data, 0, data.length);
27 assertEquals(sb.toString(), tb.toString());
28 }
29 }
30
31 }
0 test.resourceRoot=./test/resources
1 test.scratchDirectory=./build/tmp
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.*;
3
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import org.jdom.Attribute;
8 import org.jdom.CDATA;
9 import org.jdom.Comment;
10 import org.jdom.Content;
11 import org.jdom.DocType;
12 import org.jdom.Document;
13 import org.jdom.Element;
14 import org.jdom.EntityRef;
15 import org.jdom.JDOMFactory;
16 import org.jdom.Namespace;
17 import org.jdom.ProcessingInstruction;
18 import org.jdom.Text;
19 import org.jdom.located.Located;
20
21 import org.junit.Test;
22
23 @SuppressWarnings("javadoc")
24 public abstract class AbstractTestJDOMFactory {
25
26 private final boolean located;
27
28 public AbstractTestJDOMFactory(boolean located) {
29 this.located = located;
30 }
31
32 protected abstract JDOMFactory buildFactory();
33
34 private void checkLocated(final Content c) {
35 if (located) {
36 assertTrue("Expected " + c + " to be Located", c instanceof Located);
37 Located loc = (Located)c;
38 assertTrue(1 == loc.getLine());
39 assertTrue(2 == loc.getColumn());
40 } else {
41 assertFalse(c instanceof Located);
42 }
43 }
44
45 @Test
46 public void testCdata() {
47 CDATA cdata = buildFactory().cdata("foo");
48 assertTrue(cdata != null);
49 assertTrue("foo".equals(cdata.getValue()));
50
51 CDATA ldata = buildFactory().cdata(1,2,"foo");
52 assertTrue(ldata != null);
53 assertTrue("foo".equals(ldata.getValue()));
54 checkLocated(ldata);
55 }
56
57 @Test
58 public void testText() {
59 Text text = buildFactory().text("foo");
60 assertTrue(text != null);
61 assertTrue("foo".equals(text.getValue()));
62
63 Text ltext = buildFactory().text(1, 2, "foo");
64 assertTrue(ltext != null);
65 assertTrue("foo".equals(ltext.getValue()));
66 checkLocated(ltext);
67 }
68
69 @Test
70 public void testComment() {
71 Comment comment = buildFactory().comment("foo");
72 assertTrue(comment != null);
73 assertTrue("foo".equals(comment.getText()));
74
75 Comment lcomment = buildFactory().comment(1, 2, "foo");
76 assertTrue(lcomment != null);
77 assertTrue("foo".equals(lcomment.getText()));
78 checkLocated(lcomment);
79 }
80
81 @Test
82 public void testAttributeStringStringNamespace() {
83 Attribute att = buildFactory().attribute("att", "val", Namespace.getNamespace("p", "uri"));
84 assertTrue("att".equals(att.getName()));
85 assertTrue("val".equals(att.getValue()));
86 assertTrue("uri".equals(att.getNamespace().getURI()));
87 assertTrue(Attribute.UNDECLARED_TYPE == att.getAttributeType());
88
89 att = buildFactory().attribute("att", "val", (Namespace)null);
90 assertTrue("att".equals(att.getName()));
91 assertTrue("val".equals(att.getValue()));
92 assertTrue("".equals(att.getNamespace().getURI()));
93 assertTrue(Attribute.UNDECLARED_TYPE == att.getAttributeType());
94 }
95
96 @Test
97 public void testAttributeStringStringIntNamespace() {
98 @SuppressWarnings("deprecation")
99 Attribute att = buildFactory().attribute("att", "val", Attribute.ID_TYPE.ordinal(), Namespace.getNamespace("p", "uri"));
100 assertTrue("att".equals(att.getName()));
101 assertTrue("val".equals(att.getValue()));
102 assertTrue("uri".equals(att.getNamespace().getURI()));
103 assertTrue(Attribute.ID_TYPE == att.getAttributeType());
104
105 att = buildFactory().attribute("att", "val", Attribute.ID_TYPE, null);
106 assertTrue("att".equals(att.getName()));
107 assertTrue("val".equals(att.getValue()));
108 assertTrue("".equals(att.getNamespace().getURI()));
109 assertTrue(Attribute.ID_TYPE == att.getAttributeType());
110 }
111
112
113 @Test
114 public void testAttributeStringStringAttributeTypeNamespace() {
115 Attribute att = buildFactory().attribute("att", "val", Attribute.ID_TYPE, Namespace.getNamespace("p", "uri"));
116 assertTrue("att".equals(att.getName()));
117 assertTrue("val".equals(att.getValue()));
118 assertTrue("uri".equals(att.getNamespace().getURI()));
119 assertTrue(Attribute.ID_TYPE == att.getAttributeType());
120
121 att = buildFactory().attribute("att", "val", Attribute.ID_TYPE, null);
122 assertTrue("att".equals(att.getName()));
123 assertTrue("val".equals(att.getValue()));
124 assertTrue("".equals(att.getNamespace().getURI()));
125 assertTrue(Attribute.ID_TYPE == att.getAttributeType());
126 }
127
128 @Test
129 public void testAttributeStringString() {
130 Attribute att = buildFactory().attribute("att", "val");
131 assertTrue("att".equals(att.getName()));
132 assertTrue("val".equals(att.getValue()));
133 assertTrue("".equals(att.getNamespace().getURI()));
134 assertTrue(Attribute.UNDECLARED_TYPE == att.getAttributeType());
135 }
136
137 @Test
138 public void testAttributeStringStringInt() {
139 @SuppressWarnings("deprecation")
140 Attribute att = buildFactory().attribute("att", "val", Attribute.ID_TYPE.ordinal());
141 assertTrue("att".equals(att.getName()));
142 assertTrue("val".equals(att.getValue()));
143 assertTrue("".equals(att.getNamespace().getURI()));
144 assertTrue(Attribute.ID_TYPE == att.getAttributeType());
145 }
146
147 @Test
148 public void testAttributeStringStringType() {
149 Attribute att = buildFactory().attribute("att", "val", Attribute.ID_TYPE);
150 assertTrue("att".equals(att.getName()));
151 assertTrue("val".equals(att.getValue()));
152 assertTrue("".equals(att.getNamespace().getURI()));
153 assertTrue(Attribute.ID_TYPE == att.getAttributeType());
154 }
155
156 @Test
157 public void testDocTypeStringStringString() {
158 DocType dt = buildFactory().docType("element", "public", "system");
159 assertTrue("element".equals(dt.getElementName()));
160 assertTrue("public".equals(dt.getPublicID()));
161 assertTrue("system".equals(dt.getSystemID()));
162
163 DocType ldt = buildFactory().docType(1, 2, "element", "public", "system");
164 assertTrue("element".equals(ldt.getElementName()));
165 assertTrue("public".equals(ldt.getPublicID()));
166 assertTrue("system".equals(ldt.getSystemID()));
167 checkLocated(ldt);
168 }
169
170 @Test
171 public void testDocTypeStringString() {
172 DocType dt = buildFactory().docType("element", "system");
173 assertTrue("element".equals(dt.getElementName()));
174 assertTrue(null == dt.getPublicID());
175 assertTrue("system".equals(dt.getSystemID()));
176 DocType ldt = buildFactory().docType(1, 2, "element", "system");
177 assertTrue("element".equals(ldt.getElementName()));
178 assertTrue(null == ldt.getPublicID());
179 assertTrue("system".equals(ldt.getSystemID()));
180 checkLocated(ldt);
181 }
182
183 @Test
184 public void testDocTypeString() {
185 DocType dt = buildFactory().docType("element");
186 assertTrue("element".equals(dt.getElementName()));
187 assertTrue(null == dt.getPublicID());
188 assertTrue(null == dt.getSystemID());
189
190 DocType ldt = buildFactory().docType(1, 2, "element");
191 assertTrue("element".equals(ldt.getElementName()));
192 assertTrue(null == ldt.getPublicID());
193 assertTrue(null == ldt.getSystemID());
194 checkLocated(ldt);
195 }
196
197 @Test
198 public void testElementStringNamespace() {
199 Element root = buildFactory().element("root", Namespace.getNamespace("uri"));
200 assertEquals("root", root.getName());
201 assertEquals("uri", root.getNamespace().getURI());
202
203 Namespace n = null;
204 root = buildFactory().element("root", n);
205 assertEquals("root", root.getName());
206 assertEquals("", root.getNamespace().getURI());
207
208 Element lroot = buildFactory().element(1, 2, "root", Namespace.getNamespace("uri"));
209 checkLocated(lroot);
210
211 }
212
213 @Test
214 public void testElementString() {
215 Element root = buildFactory().element("root");
216 assertEquals("root", root.getName());
217 assertEquals("", root.getNamespace().getURI());
218
219 Element lroot = buildFactory().element(1, 2, "root");
220 checkLocated(lroot);
221 }
222
223 @Test
224 public void testElementStringString() {
225 Element root = buildFactory().element("root", "uri");
226 assertEquals("root", root.getName());
227 assertEquals("uri", root.getNamespace().getURI());
228
229 Element lroot = buildFactory().element(1, 2, "root", "uri");
230 checkLocated(lroot);
231 }
232
233 @Test
234 public void testElementStringStringString() {
235 Element root = buildFactory().element("root", "p", "uri");
236 assertEquals("root", root.getName());
237 assertEquals("p", root.getNamespace().getPrefix());
238 assertEquals("uri", root.getNamespace().getURI());
239
240 Element lroot = buildFactory().element(1, 2, "root", "p", "uri");
241 checkLocated(lroot);
242 }
243
244 @Test
245 public void testProcessingInstructionString() {
246 ProcessingInstruction pi = buildFactory().processingInstruction("target");
247 assertEquals("target", pi.getTarget());
248 assertEquals("", pi.getData());
249
250 ProcessingInstruction lpi = buildFactory().processingInstruction(1, 2, "target");
251 checkLocated(lpi);
252 }
253
254 @Test
255 public void testProcessingInstructionStringMap() {
256 Map<String,String> data = new HashMap<String, String>();
257 data.put("key", "val");
258 ProcessingInstruction pi = buildFactory().processingInstruction("target", data);
259 assertEquals("target", pi.getTarget());
260 assertEquals("key=\"val\"", pi.getData());
261
262 ProcessingInstruction lpi = buildFactory().processingInstruction(1, 2, "target", data);
263 checkLocated(lpi);
264 }
265
266 @Test
267 public void testProcessingInstructionStringString() {
268 ProcessingInstruction pi = buildFactory().processingInstruction("target", "data");
269 assertEquals("target", pi.getTarget());
270 assertEquals("data", pi.getData());
271
272 ProcessingInstruction lpi = buildFactory().processingInstruction(1, 2, "target", "data");
273 checkLocated(lpi);
274 }
275
276 @Test
277 public void testEntityRefString() {
278 EntityRef er = buildFactory().entityRef("name");
279 assertEquals("name", er.getName());
280 assertEquals(null, er.getPublicID());
281 assertEquals(null, er.getSystemID());
282
283 EntityRef ler = buildFactory().entityRef(1, 2, "name");
284 checkLocated(ler);
285 }
286
287 @Test
288 public void testEntityRefStringStringString() {
289 EntityRef er = buildFactory().entityRef("name", "public", "system");
290 assertEquals("name", er.getName());
291 assertEquals("public", er.getPublicID());
292 assertEquals("system", er.getSystemID());
293
294 EntityRef ler = buildFactory().entityRef(1, 2, "name", "public", "system");
295 checkLocated(ler);
296 }
297
298 @Test
299 public void testEntityRefStringString() {
300 EntityRef er = buildFactory().entityRef("name", "system");
301 assertEquals("name", er.getName());
302 assertEquals(null, er.getPublicID());
303 assertEquals("system", er.getSystemID());
304
305 EntityRef ler = buildFactory().entityRef(1, 2, "name", "system");
306 checkLocated(ler);
307 }
308
309 @Test
310 public void testDocumentElementDocTypeString() {
311 JDOMFactory fac = buildFactory();
312 Element root = fac.element("root");
313 DocType dt = fac.docType("root");
314 Document doc = buildFactory().document(root, dt, "baseuri");
315 assertTrue(doc.getRootElement() == root);
316 assertTrue(doc.getDocType() == dt);
317 assertEquals("baseuri", doc.getBaseURI());
318
319 root.detach();
320 dt.detach();
321
322 root = null;
323 doc = buildFactory().document(root, dt, "baseuri");
324 assertFalse(doc.hasRootElement());
325 assertTrue(doc.getDocType() == dt);
326 assertEquals("baseuri", doc.getBaseURI());
327 }
328
329 @Test
330 public void testDocumentElementDocType() {
331 JDOMFactory fac = buildFactory();
332 Element root = fac.element("root");
333 DocType dt = fac.docType("root");
334 Document doc = buildFactory().document(root, dt);
335 assertTrue(doc.getRootElement() == root);
336 assertTrue(doc.getDocType() == dt);
337 assertEquals(null, doc.getBaseURI());
338 }
339
340 @Test
341 public void testDocumentElement() {
342 JDOMFactory fac = buildFactory();
343 Element root = fac.element("root");
344 Document doc = buildFactory().document(root);
345 assertTrue(doc.getRootElement() == root);
346 assertTrue(doc.getDocType() == null);
347 assertEquals(null, doc.getBaseURI());
348 }
349
350 @Test
351 public void testAddContent() {
352 JDOMFactory fac = buildFactory();
353 Element root = fac.element("root");
354 fac.addContent(root, new Text("foo"));
355 assertEquals(root.getTextNormalize(), "foo");
356 }
357
358 @Test
359 public void testSetAttribute() {
360 JDOMFactory fac = buildFactory();
361 Element root = fac.element("root");
362 fac.setAttribute(root, fac.attribute("att", "val"));
363 assertEquals(root.getAttributeValue("att"), "val");
364 }
365
366 @Test
367 public void testAddNamespaceDeclaration() {
368 JDOMFactory fac = buildFactory();
369 Element root = fac.element("root");
370 Namespace nsa = Namespace.getNamespace("p", "uri");
371 fac.addNamespaceDeclaration(root, nsa);
372 assertTrue(root.getAdditionalNamespaces().contains(nsa));
373 Namespace nsb = Namespace.getNamespace("p", "uri");
374 fac.addNamespaceDeclaration(root, nsb);
375 assertTrue(root.getAdditionalNamespaces().contains(nsb));
376 assertTrue(root.getAdditionalNamespaces().contains(nsa));
377 }
378
379 @Test
380 public void testSetRoot() {
381 JDOMFactory fac = buildFactory();
382 Document doc = fac.document(null);
383 Element root = fac.element("root");
384 assertFalse(doc.hasRootElement());
385 assertTrue(root.getParent() == null);
386 fac.setRoot(doc, root);
387 assertTrue(doc.hasRootElement());
388 assertTrue(doc.getRootElement() == root);
389 assertTrue(root.getParent() == doc);
390 }
391
392 }
0 package org.jdom.test.cases;
1
2 /*--
3
4 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact license@jdom.org.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management (pm@jdom.org).
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Brett McLaughlin <brett@jdom.org> and
51 Jason Hunter <jhunter@jdom.org>. For more information on the
52 JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56
57 import static org.junit.Assert.assertEquals;
58 import static org.junit.Assert.assertFalse;
59 import static org.junit.Assert.assertNotNull;
60 import static org.junit.Assert.assertNull;
61 import static org.junit.Assert.assertTrue;
62 import static org.junit.Assert.fail;
63
64 import org.junit.Test;
65 import org.junit.runner.JUnitCore;
66
67 import org.jdom.Attribute;
68 import org.jdom.AttributeType;
69 import org.jdom.DataConversionException;
70 import org.jdom.Document;
71 import org.jdom.Element;
72 import org.jdom.IllegalDataException;
73 import org.jdom.IllegalNameException;
74 import org.jdom.Namespace;
75 import org.jdom.test.util.UnitTestUtil;
76
77 /**
78 * Test the expected behaviour of the Attribute class.
79 *
80 * @author unascribed
81 * @version 0.1
82 */
83 @SuppressWarnings("javadoc")
84 public final class TestAttribute {
85
86 /**
87 * The main method runs all the tests in the text ui
88 */
89 public static void main (final String args[]) {
90 JUnitCore.runClasses(TestAttribute.class);
91 }
92
93 /**
94 * Test the simple case of constructing an attribute without name, value,
95 * namespace or prefix
96 */
97 @Test
98 public void test_TCC() {
99 final Attribute attribute = new Attribute(){
100 private static final long serialVersionUID = 200L;
101 };
102 assertTrue(null == attribute.getName());
103 assertTrue(attribute.isSpecified());
104 }
105
106 /**
107 * Test the simple case of constructing an attribute without
108 * namespace or prefix
109 */
110 @Test
111 public void test_TCC___String_String() {
112 final Attribute attribute = new Attribute("test", "value");
113 assertTrue(attribute.isSpecified());
114 assertTrue("incorrect attribute name", attribute.getName().equals("test"));
115 assertTrue("incoorect attribute value", attribute.getValue().equals("value"));
116 assertEquals("incorrect attribute type", attribute.getAttributeType(), Attribute.UNDECLARED_TYPE);
117
118 //should have been put in the NO_NAMESPACE namespace
119 assertTrue("incorrect namespace", attribute.getNamespace().equals(Namespace.NO_NAMESPACE));
120
121
122 try {
123 new Attribute(null, "value");
124 fail("didn't catch null attribute name");
125 } catch (final NullPointerException e) {
126 // Do nothing
127 } catch (Exception e) {
128 fail("Unexpected exception " + e.getClass());
129 }
130
131 try {
132 new Attribute("test", null);
133 fail("didn't catch null attribute value");
134 } catch (final NullPointerException e) {
135 // Do nothing
136 } catch (Exception e) {
137 fail("Unexpected exception " + e.getClass());
138 }
139
140 try {
141 new Attribute("test" + (char)0x01, "value");
142 fail("didn't catch invalid attribute name");
143 } catch (final IllegalArgumentException e) {
144 // Do nothing
145 } catch (Exception e) {
146 fail("Unexpected exception " + e.getClass());
147 }
148
149 try {
150 new Attribute("test", "test" + (char)0x01);
151 fail("didn't catch invalid attribute value");
152 } catch (final IllegalArgumentException e) {
153 // Do nothing
154 } catch (Exception e) {
155 fail("Unexpected exception " + e.getClass());
156 }
157
158 }
159
160 /**
161 * Test the constructor with name, value and namespace
162 */
163 @Test
164 public void test_TCC___String_String_OrgJdomNamespace() {
165 {
166 final Namespace namespace = Namespace.getNamespace("prefx", "http://some.other.place");
167
168 final Attribute attribute = new Attribute("test", "value", namespace);
169 assertTrue("incorrect attribute name", attribute.getName().equals("test"));
170 assertTrue("incoorect attribute value", attribute.getValue().equals("value"));
171 assertTrue("incorrect Namespace", attribute.getNamespace().equals(namespace));
172
173 assertEquals("incoorect attribute type", attribute.getAttributeType(), Attribute.UNDECLARED_TYPE);
174 }
175
176 //now test that the attribute cannot be created with a namespace
177 //without a prefix
178 final Namespace defaultNamespace = Namespace.getNamespace("http://some.other.place");
179 try {
180 new Attribute("test", "value", defaultNamespace);
181 fail("allowed creation of attribute with a default namespace");
182 } catch (final IllegalNameException e) {
183 // Do nothing
184 } catch (Exception e) {
185 fail("Unexpected exception " + e.getClass());
186 }
187
188 try {
189 new Attribute("test", "value", (Namespace)null);
190 } catch (Exception e) {
191 fail("didn't handle null attribute namespace");
192 }
193 }
194
195
196 /**
197 * Test the constructor with name, value and namespace
198 */
199 @Test
200 public void test_TCC___String_String_int() {
201 {
202
203 @SuppressWarnings("deprecation")
204 final Attribute attribute = new Attribute("test", "value", AttributeType.ID.ordinal());
205 assertTrue("incorrect attribute name", attribute.getName().equals("test"));
206 assertTrue("incoorect attribute value", attribute.getValue().equals("value"));
207 assertTrue("incorrect Namespace", attribute.getNamespace().equals(Namespace.NO_NAMESPACE));
208
209 assertEquals("incoorect attribute type", attribute.getAttributeType(), Attribute.ID_TYPE);
210 }
211
212 }
213
214
215 /**
216 * Test the constructor with name, value and namespace
217 */
218 @Test
219 public void test_TCC___String_String_int_OrgJdomNamespace() {
220 {
221 final Namespace namespace = Namespace.getNamespace("prefx", "http://some.other.place");
222
223 @SuppressWarnings("deprecation")
224 final Attribute attribute = new Attribute("test", "value", Attribute.ID_TYPE.ordinal(), namespace);
225 assertTrue("incorrect attribute name", attribute.getName().equals("test"));
226 assertTrue("incoorect attribute value", attribute.getValue().equals("value"));
227 assertTrue("incorrect Namespace", attribute.getNamespace().equals(namespace));
228
229 assertEquals("incoorect attribute type", attribute.getAttributeType(), Attribute.ID_TYPE);
230 }
231
232 //now test that the attribute cannot be created with a namespace
233 //without a prefix
234 final Namespace defaultNamespace = Namespace.getNamespace("http://some.other.place");
235 try {
236 new Attribute("test", "value", defaultNamespace);
237 fail("allowed creation of attribute with a default namespace");
238 } catch (final IllegalNameException e) {
239 // Do nothing
240 } catch (Exception e) {
241 fail("Unexpected exception " + e.getClass());
242 }
243
244 try {
245 new Attribute("test", "value", (Namespace)null);
246 } catch (Exception e) {
247 fail("didn't handle null attribute namespace");
248 }
249 }
250
251
252 /**
253 * Test possible attribute values
254 */
255 @SuppressWarnings("deprecation")
256 @Test
257 public void test_TCM__Attribute_setAttributeType_int() {
258 final Attribute attribute = new Attribute("test", "value");
259
260 for(int attributeType = -10; attributeType < 15; attributeType++) {
261 if (
262 Attribute.UNDECLARED_TYPE.ordinal() <= attributeType &&
263 attributeType <= Attribute.ENUMERATED_TYPE.ordinal()
264 ) {
265 attribute.setAttributeType(attributeType);
266 assertTrue(attribute.getAttributeType().ordinal() == attributeType);
267 continue;
268 }
269 try {
270 attribute.setAttributeType(attributeType);
271 fail("set unvalid attribute type: "+ attributeType);
272 }
273 catch(final IllegalDataException ignore) {
274 // is expected
275 }
276 catch(final Exception exception) {
277 exception.printStackTrace();
278 fail("unknown exception throws: "+ exception);
279 }
280 }
281 }
282
283 /**
284 * Test a simple object comparison
285 */
286 @Test
287 public void test_TCM__boolean_equals_Object() {
288 final Attribute attribute = new Attribute("test", "value");
289
290 assertFalse("attribute equal to null", attribute.equals(null));
291
292 final Object object = attribute;
293 assertTrue("object not equal to attribute", attribute.equals(object));
294 assertTrue("attribute not equal to object", object.equals(attribute));
295
296 // current implementation checks only for identity
297 // final Attribute clonedAttribute = (Attribute) attribute.clone();
298 // assertTrue("attribute not equal to its clone", attribute.equals(clonedAttribute));
299 // assertTrue("clone not equal to attribute", clonedAttribute.equals(attribute));
300 }
301
302 /**
303 * test the convienience method getBooleanValue();
304 */
305 @Test
306 public void test_TCM__boolean_getBooleanValue() {
307 final Attribute attribute = new Attribute("test", "true");
308 try {
309 assertTrue("incorrect boolean true value", attribute.getBooleanValue());
310
311 attribute.setValue("false");
312 assertTrue("incorrect boolean false value", !attribute.getBooleanValue());
313
314 attribute.setValue("TRUE");
315 assertTrue("incorrect boolean TRUE value", attribute.getBooleanValue());
316
317 attribute.setValue("FALSE");
318 assertTrue("incorrect boolean FALSE value", !attribute.getBooleanValue());
319
320 attribute.setValue("On");
321 assertTrue("incorrect boolean TRUE value", attribute.getBooleanValue());
322
323 attribute.setValue("Yes");
324 assertTrue("incorrect boolean TRUE value", attribute.getBooleanValue());
325
326 attribute.setValue("1");
327 assertTrue("incorrect boolean TRUE value", attribute.getBooleanValue());
328
329 attribute.setValue("OfF");
330 assertTrue("incorrect boolean FALSE value", !attribute.getBooleanValue());
331
332 attribute.setValue("0");
333 assertTrue("incorrect boolean FALSE value", !attribute.getBooleanValue());
334
335 attribute.setValue("No");
336 assertTrue("incorrect boolean FALSE value", !attribute.getBooleanValue());
337
338 } catch (DataConversionException e) {
339 fail("couldn't convert boolean value");
340 }
341
342 try {
343 attribute.setValue("foo");
344 assertTrue("incorrectly returned boolean from non boolean value", attribute.getBooleanValue());
345
346 } catch (DataConversionException e) {
347 // good
348 } catch (Exception e) {
349 fail("Expected DataConversionException, but got " + e.getClass().getName());
350 }
351
352
353 }
354 /**
355 * Test convience method for getting doubles from an Attribute
356 */
357 @Test
358 public void test_TCM__double_getDoubleValue() {
359 Attribute attr = new Attribute("test", "11111111111111");
360 try {
361 assertTrue("incorrect double value", attr.getDoubleValue() == 11111111111111d );
362
363 attr.setValue("0");
364 assertTrue("incorrect double value", attr.getDoubleValue() == 0 );
365
366 attr.setValue(Double.toString(java.lang.Double.MAX_VALUE));
367 assertTrue("incorrect double value", attr.getDoubleValue() == java.lang.Double.MAX_VALUE);
368
369 attr.setValue(Double.toString(java.lang.Double.MIN_VALUE));
370 assertTrue("incorrect double value", attr.getDoubleValue() == java.lang.Double.MIN_VALUE);
371
372 } catch (DataConversionException e) {
373 fail("couldn't convert boolean value");
374 }
375
376 try {
377 attr.setValue("foo");
378 fail("incorrectly returned double from non double value" + attr.getDoubleValue());
379
380 } catch (DataConversionException e) {
381 // Do nothing
382 } catch (Exception e) {
383 fail("Unexpected exception " + e.getClass());
384 }
385
386 }
387
388 /**
389 * Test floats returned from Attribute values. Checks that both correctly
390 * formatted (java style) and incorrectly formatted float strings are
391 * returned or raise a DataConversionException
392 */
393 @Test
394 public void test_TCM__float_getFloatValue() {
395 Attribute attr = new Attribute("test", "1.00000009999e+10f");
396 float flt = 1.00000009999e+10f;
397 try {
398 assertTrue("incorrect float conversion",
399 attr.getFloatValue() == flt);
400 } catch (DataConversionException e) {
401 fail("couldn't convert to float");
402 }
403
404 // test an invalid float
405
406 attr.setValue("1.00000009999e");
407 try {
408 attr.getFloatValue();
409 fail("incorrect float conversion from non float");
410 } catch (DataConversionException e) {
411 // Do nothing
412 } catch (Exception e) {
413 fail("Unexpected exception " + e.getClass());
414 }
415
416 }
417
418 /**
419 * Tests that Attribute can convert value strings to ints and
420 * that is raises DataConversionException if it is not an int.
421 */
422 @Test
423 public void test_TCM__int_getIntValue() {
424 final Attribute attribute = new Attribute("test", "");
425 int summand = 3;
426 for(int i = 0; i < 28; i++) {
427 summand <<= 1;
428 final int value = Integer.MIN_VALUE + summand;
429
430 attribute.setValue("" + value);
431 try {
432 assertEquals("incorrect int conversion", attribute.getIntValue(), value);
433 } catch (final DataConversionException e) {
434 fail("couldn't convert to int");
435 }
436 }
437
438 //test an invalid int
439 TCM__int_getIntValue_invalidInt("" + Long.MIN_VALUE);
440 TCM__int_getIntValue_invalidInt("" + Long.MAX_VALUE);
441 TCM__int_getIntValue_invalidInt("" + Float.MIN_VALUE);
442 TCM__int_getIntValue_invalidInt("" + Float.MAX_VALUE);
443 TCM__int_getIntValue_invalidInt("" + Double.MIN_VALUE);
444 TCM__int_getIntValue_invalidInt("" + Double.MAX_VALUE);
445 }
446
447 private void TCM__int_getIntValue_invalidInt(final String value) {
448 final Attribute attribute = new Attribute("test", value);
449 try {
450 attribute.getIntValue();
451 fail("incorrect int conversion from non int");
452 } catch (final DataConversionException e) {
453 // Do nothing
454 } catch (Exception e) {
455 fail("Unexpected exception " + e.getClass());
456 }
457 }
458 /**
459 * Test that Attribute returns a valid hashcode.
460 */
461 @Test
462 public void test_TCM__int_hashCode() {
463 final Attribute attr = new Attribute("test", "value");
464 //only an exception would be a problem
465 int i = -1;
466 try {
467 i = attr.hashCode();
468 }
469 catch(Exception e) {
470 fail("bad hashCode");
471 }
472 final Attribute attr2 = new Attribute("test", "value");
473
474 //different Attributes, same text
475 final int x = attr2.hashCode();
476 assertFalse("Different Attributes with same value have same hashcode", x == i);
477
478 final Attribute attr3 = new Attribute("test2", "value");
479 //only an exception would be a problem
480 final int y = attr3.hashCode();
481 assertFalse("Different Attributes have same hashcode", y == x);
482 }
483
484 /**
485 * Test the convienience method for returning a long from an Attribute
486 */
487 @Test
488 public void test_TCM__long_getLongValue() {
489 final Attribute attribute = new Attribute("test", "");
490 long summand = 3;
491 for(int i = 0; i < 60; i++) {
492 summand <<= 1;
493 final long value = Long.MIN_VALUE + summand;
494
495 attribute.setValue("" + value);
496 try {
497 assertEquals("incorrect long conversion", attribute.getLongValue(), value);
498 } catch (final DataConversionException e) {
499 fail("couldn't convert to long");
500 }
501 }
502
503 //test an invalid long
504 attribute.setValue("100000000000000000000000000");
505 try {
506 attribute.getLongValue();
507 fail("incorrect long conversion from non long");
508 } catch (final DataConversionException e) {
509 // Do nothing
510 } catch (Exception e) {
511 fail("Unexpected exception " + e.getClass());
512 }
513 }
514
515 /**
516 * Test that an Attribute can clone itself correctly. The test
517 * covers the simple case and with the attribute using a namespace
518 * and prefix.
519 */
520 @Test
521 public void test_TCM__Object_clone() {
522 TCM__Object_clone__default();
523
524 TCM__Object_clone__attributeType(Attribute.UNDECLARED_TYPE);
525 TCM__Object_clone__attributeType(Attribute.CDATA_TYPE);
526 TCM__Object_clone__attributeType(Attribute.ID_TYPE);
527 TCM__Object_clone__attributeType(Attribute.IDREF_TYPE);
528 TCM__Object_clone__attributeType(Attribute.IDREFS_TYPE);
529 TCM__Object_clone__attributeType(Attribute.ENTITY_TYPE);
530 TCM__Object_clone__attributeType(Attribute.ENTITIES_TYPE);
531 TCM__Object_clone__attributeType(Attribute.NMTOKEN_TYPE);
532 TCM__Object_clone__attributeType(Attribute.NMTOKENS_TYPE);
533 TCM__Object_clone__attributeType(Attribute.NOTATION_TYPE);
534 TCM__Object_clone__attributeType(Attribute.ENUMERATED_TYPE);
535
536
537 TCM__Object_clone__Namespace_default();
538
539 TCM__Object_clone__Namespace_attributeType(Attribute.UNDECLARED_TYPE);
540 TCM__Object_clone__Namespace_attributeType(Attribute.CDATA_TYPE);
541 TCM__Object_clone__Namespace_attributeType(Attribute.ID_TYPE);
542 TCM__Object_clone__Namespace_attributeType(Attribute.IDREF_TYPE);
543 TCM__Object_clone__Namespace_attributeType(Attribute.IDREFS_TYPE);
544 TCM__Object_clone__Namespace_attributeType(Attribute.ENTITY_TYPE);
545 TCM__Object_clone__Namespace_attributeType(Attribute.ENTITIES_TYPE);
546 TCM__Object_clone__Namespace_attributeType(Attribute.NMTOKEN_TYPE);
547 TCM__Object_clone__Namespace_attributeType(Attribute.NMTOKENS_TYPE);
548 TCM__Object_clone__Namespace_attributeType(Attribute.NOTATION_TYPE);
549 TCM__Object_clone__Namespace_attributeType(Attribute.ENUMERATED_TYPE);
550 }
551
552 /**
553 * Test that an Attribute can clone itself correctly. The test covers the
554 * simple case with only name and value.
555 */
556 private void TCM__Object_clone__default() {
557 final String attributeName = "test";
558 final String attributeValue = "value";
559
560 final Attribute attribute = new Attribute(attributeName, attributeValue);
561 final Attribute clonedAttribute = attribute.clone();
562
563 assertTrue("incorrect name in clone", clonedAttribute.getName().equals(attributeName));
564 assertTrue("incorrect value in clone", clonedAttribute.getValue().equals(attributeValue));
565 assertEquals("incoorect attribute type in clone", clonedAttribute.getAttributeType(), Attribute.UNDECLARED_TYPE);
566 }
567
568 /**
569 * Test that an Attribute can clone itself correctly. The test covers the
570 * simple case with only name, value and a given attribute type.
571 */
572 private void TCM__Object_clone__attributeType(final AttributeType attributeType) {
573 final String attributeName = "test";
574 final String attributeValue = "value";
575
576 final Attribute attribute = new Attribute(attributeName, attributeValue, attributeType);
577 final Attribute clonedAttribute = attribute.clone();
578
579 assertTrue("incorrect name in clone", clonedAttribute.getName().equals(attributeName));
580 assertTrue("incorrect value in clone", clonedAttribute.getValue().equals(attributeValue));
581 assertEquals("incoorect attribute type in clone", clonedAttribute.getAttributeType(), attributeType);
582 }
583
584 /**
585 * Test that an Attribute can clone itself correctly. The test covers the
586 * case with name, value, prefix, namespace and a given attribute type.
587 */
588 private void TCM__Object_clone__Namespace_default() {
589 final String prefix = "prefx";
590 final String uri = "http://some.other.place";
591
592 final Namespace namespace = Namespace.getNamespace(prefix, uri);
593
594 final String attributeName = "test";
595 final String attributeValue = "value";
596
597 final Attribute attribute = new Attribute(attributeName, attributeValue, namespace);
598 final Attribute clonedAttribute = attribute.clone();
599
600 assertTrue("incorrect name in clone", clonedAttribute.getName().equals(attributeName));
601 assertTrue("incorrect value in clone", clonedAttribute.getValue().equals(attributeValue));
602 assertEquals("incoorect attribute type in clone", clonedAttribute.getAttributeType(), Attribute.UNDECLARED_TYPE);
603
604 assertTrue("incorrect prefix in clone", clonedAttribute.getNamespacePrefix().equals(prefix));
605 assertTrue("incorrect qualified name in clone", clonedAttribute.getQualifiedName().equals(prefix + ':' + attributeName));
606 assertTrue("incorrect Namespace URI in clone", clonedAttribute.getNamespaceURI().equals(uri));
607 }
608
609 /**
610 * Test that an Attribute can clone itself correctly. The test covers the
611 * case with name, value, prefix, namespace and a given attribute type.
612 */
613 private void TCM__Object_clone__Namespace_attributeType(final AttributeType attributeType) {
614 final String prefix = "prefx";
615 final String uri = "http://some.other.place";
616
617 final Namespace namespace = Namespace.getNamespace(prefix, uri);
618
619 final String attributeName = "test";
620 final String attributeValue = "value";
621
622 final Attribute attribute = new Attribute(attributeName, attributeValue, attributeType, namespace);
623 final Attribute clonedAttribute = attribute.clone();
624
625 assertTrue("incorrect name in clone", clonedAttribute.getName().equals(attributeName));
626 assertTrue("incorrect value in clone", clonedAttribute.getValue().equals(attributeValue));
627 assertEquals("incoorect attribute type in clone", clonedAttribute.getAttributeType(), attributeType);
628
629 assertTrue("incorrect prefix in clone", clonedAttribute.getNamespacePrefix().equals(prefix));
630 assertTrue("incorrect qualified name in clone", clonedAttribute.getQualifiedName().equals(prefix + ':' + attributeName));
631 assertTrue("incorrect Namespace URI in clone", clonedAttribute.getNamespaceURI().equals(uri));
632 }
633
634 /**
635 * Test that setting an Attribute's value works correctly.
636 */
637 @Test
638 public void test_TCM__OrgJdomAttribute_setValue_String() {
639 final Namespace namespace = Namespace.getNamespace("prefx", "http://some.other.place");
640
641 final Attribute attribute = new Attribute("test", "value", namespace);
642
643 assertTrue("incorrect value before set", attribute.getValue().equals("value"));
644
645 attribute.setValue("foo");
646 assertTrue("incorrect value after set", attribute.getValue().equals("foo"));
647
648 //test that the verifier is called
649 try {
650 attribute.setValue(null);
651 fail("Attribute setValue didn't catch null string");
652 } catch (final NullPointerException e) {
653 // Do nothing
654 } catch (Exception e) {
655 fail("Unexpected exception " + e.getClass());
656 }
657
658 try {
659 final char c= 0x11;
660 final StringBuilder buffer = new StringBuilder("hhhh");
661 buffer.setCharAt(2, c);
662 attribute.setValue(buffer.toString());
663 fail("Attribute setValue didn't catch invalid comment string");
664 } catch (final IllegalDataException e) {
665 // Do nothing
666 } catch (Exception e) {
667 fail("Unexpected exception " + e.getClass());
668 }
669
670 }
671
672 /**
673 * check that the attribute can return the correct parent element
674 */
675 @Test
676 public void test_TCM__OrgJdomElement_getParent() {
677 final Attribute attribute = new Attribute("test", "value");
678 assertNull("attribute returned parent when there was none", attribute.getParent());
679
680 final Element element = new Element("element");
681 element.setAttribute(attribute);
682
683 assertNotNull("no parent element found", attribute.getParent());
684
685 assertEquals("invalid parent element", attribute.getParent(), element);
686 }
687
688 /**
689 * check that the attribute can return the correct document
690 */
691 @Test
692 public void test_TCM__OrgJdomDocument_getDocument() {
693 final Attribute attribute = new Attribute("test", "value");
694 assertNull("attribute returned document when there was none", attribute.getDocument());
695
696 final Element element = new Element("element");
697 element.setAttribute(attribute);
698 assertNull("attribute returned document when there was none", attribute.getDocument());
699
700 final Document document = new Document(element);
701
702 assertEquals("invalid document", attribute.getDocument(), document);
703 }
704
705 /**
706 * Test that an independantly created Namespace and one
707 * retrieved from an Attribute create with the same namespace
708 * parameters are the same namespace.
709 */
710 @Test
711 public void test_TCM__OrgJdomNamespace_getNamespace() {
712 final Namespace ns = Namespace.getNamespace("prefx", "http://some.other.place");
713
714 final Attribute attr = new Attribute("test", "value", ns);
715 final Namespace ns2 = Namespace.getNamespace("prefx", "http://some.other.place");
716
717 assertTrue("incorrect Namespace", attr.getNamespace().equals(ns2));
718
719 }
720
721 /**
722 * Test that an Attribute returns it's correct name.
723 */
724 @Test
725 public void test_TCM__String_getName() {
726 final Attribute attr = new Attribute("test", "value");
727 assertTrue("incorrect attribute name", attr.getName().equals("test"));
728
729 }
730
731 /**
732 * Test that an Attribute returns the correct Namespace prefix.
733 */
734 @Test
735 public void test_TCM__String_getNamespacePrefix() {
736 final Namespace namespace = Namespace.getNamespace("prefx", "http://some.other.place");
737
738 final Attribute attribute = new Attribute("test", "value", namespace);
739 assertTrue("incorrect prefix", attribute.getNamespacePrefix().equals("prefx"));
740 }
741
742 /**
743 * Test that an Attribute returns the correct Namespace URI.
744 */
745 @Test
746 public void test_TCM__String_getNamespaceURI() {
747 final Namespace namespace = Namespace.getNamespace("prefx", "http://some.other.place");
748
749 final Attribute attribute = new Attribute("test", "value", namespace);
750 assertTrue("incorrect URI", attribute.getNamespaceURI().equals("http://some.other.place"));
751
752 }
753
754 /**
755 * Tests that an Attribute returns the correct Qualified Name.
756 */
757 @Test
758 public void test_TCM__String_getQualifiedName() {
759 final String prefix = "prefx";
760 final String uri = "http://some.other.place";
761
762 final Namespace namespace = Namespace.getNamespace(prefix, uri);
763
764 final String attributeName = "test";
765 final String attributeQName = prefix + ':' + attributeName;
766 final String attributeValue = "value";
767
768 final Attribute qulifiedAttribute = new Attribute(attributeName, attributeValue, namespace);
769 assertEquals("incorrect qualified name", qulifiedAttribute.getQualifiedName(), attributeQName);
770
771 final Attribute attribute = new Attribute(attributeName, attributeValue);
772 assertEquals("incorrect qualified name", attribute.getQualifiedName(), attributeName);
773
774 }
775 /**
776 * Test that Attribute returns the correct serialized form.
777 */
778 @Test
779 public void test_TCM__String_getSerializedForm() {
780 /* noop because the method is deprecated
781
782 Namespace ns = Namespace.getNamespace("prefx", "http://some.other.place");
783 Attribute attr = new Attribute("test", "value", ns);
784 String serialized = attr.getSerializedForm();
785 assertTrue("incorrect serialized form", serialized.equals("prefx:test=\"value\""));
786 */
787
788 }
789
790 /**
791 * Test that an Attribute returns the correct value.
792 */
793 @Test
794 public void test_TCM__String_getValue() {
795 final Namespace ns = Namespace.getNamespace("prefx", "http://some.other.place");
796 final Attribute attr = new Attribute("test", "value", ns);
797 assertTrue("incorrect value", attr.getValue().equals("value"));
798
799 }
800
801 /**
802 * Test that the toString function works according to the
803 * JDOM spec.
804 */
805 @Test
806 public void test_TCM__String_toString() {
807 //expected value
808 final Namespace ns = Namespace.getNamespace("prefx", "http://some.other.place");
809 final Attribute attr = new Attribute("test", "value", ns);
810 String str= attr.toString();
811 assertTrue("incorrect toString form", str.equals("[Attribute: prefx:test=\"value\"]"));
812
813 }
814
815 /**
816 * Test that the detach() function works according to the JDOM spec.
817 *
818 * @see Attribute#detach()
819 */
820 @Test
821 public void test_TCM___detach() {
822 final Element element = new Element("element");
823 element.setAttribute("name", "value");
824
825 final Attribute attribute = element.getAttribute("name");
826
827 // should never occur, just to be sure
828 assertNotNull("no attribute found", attribute);
829
830
831 assertNotNull("no parent for attribute found", attribute.getParent());
832
833 attribute.detach();
834
835 assertNull("attribute has still a parent", attribute.getParent());
836 }
837
838 @Test
839 public void serialization_default() {
840 final String attributeName = "test";
841 final String attributeValue = "value";
842
843 final Attribute attribute = new Attribute(attributeName, attributeValue);
844
845 final Attribute serializedAttribute = UnitTestUtil.deSerialize(attribute);
846
847 assertTrue(attribute != serializedAttribute);
848
849 assertTrue("incorrect name in serialized attribute", serializedAttribute.getName().equals(attributeName));
850 assertTrue("incorrect value in serialized attribute", serializedAttribute.getValue().equals(attributeValue));
851 assertEquals("incoorect attribute type in serialized attribute", serializedAttribute.getAttributeType(), Attribute.UNDECLARED_TYPE);
852
853 assertEquals("incorrect Namespace in serialized attribute", serializedAttribute.getNamespace(), Namespace.NO_NAMESPACE);
854 }
855
856 @Test
857 public void serialization_Namespace() {
858 final String prefix = "prefx";
859 final String uri = "http://some.other.place";
860
861 final Namespace namespace = Namespace.getNamespace(prefix, uri);
862
863 final String attributeName = "test";
864 final String attributeValue = "value";
865
866 final Attribute attribute = new Attribute(attributeName, attributeValue, namespace);
867
868 final Attribute serializedAttribute = UnitTestUtil.deSerialize(attribute);
869
870 assertTrue("incorrect name in serialized attribute", serializedAttribute.getName().equals(attributeName));
871 assertTrue("incorrect value in serialized attribute", serializedAttribute.getValue().equals(attributeValue));
872 assertEquals("incoorect attribute type in serialized attribute", serializedAttribute.getAttributeType(), Attribute.UNDECLARED_TYPE);
873
874 assertTrue("incorrect prefix in serialized attribute", serializedAttribute.getNamespacePrefix().equals(prefix));
875 assertTrue("incorrect qualified name in serialized attribute", serializedAttribute.getQualifiedName().equals(prefix + ':' + attributeName));
876 assertTrue("incorrect Namespace URI in serialized attribute", serializedAttribute.getNamespaceURI().equals(uri));
877
878 assertEquals("incorrect Namespace in serialized attribute", serializedAttribute.getNamespace(), namespace);
879 }
880
881 @Test
882 public void testInfinity() throws DataConversionException {
883 Attribute infinity = new Attribute("name", "Infinity");
884 Attribute neginfinity = new Attribute("name", "-Infinity");
885 Attribute inf = new Attribute("name", "INF");
886 Attribute neginf = new Attribute("name", "-INF");
887 assertEquals(infinity.getDoubleValue(), Double.POSITIVE_INFINITY, 0.0);
888 assertEquals(neginfinity.getDoubleValue(), Double.NEGATIVE_INFINITY, 0.0);
889 assertEquals(inf.getDoubleValue(), Double.POSITIVE_INFINITY, 0.0);
890 assertEquals(neginf.getDoubleValue(), Double.NEGATIVE_INFINITY, 0.0);
891 }
892
893 @Test
894 public void testDetatchCloneParentAttribute() {
895 Element parent = new Element("root");
896 Attribute content = new Attribute("att", "val");
897 parent.setAttribute(content);
898 Attribute clone = content.detach().clone();
899 assertEquals(content.getValue(), clone.getValue());
900 assertNull(content.getParent());
901 assertNull(clone.getParent());
902 }
903
904 @Test
905 public void testCloneDetatchParentAttribute() {
906 Element parent = new Element("root");
907 Attribute content = new Attribute("att", "val");
908 parent.setAttribute(content);
909 Attribute clone = content.clone();
910 assertNull(clone.getParent());
911 assertEquals(parent, content.getParent());
912 assertEquals(content.getValue(), clone.getValue());
913 content.detach();
914 assertNull(content.getParent());
915 assertNull(clone.getParent());
916 }
917
918 @Test
919 public void testNullAttributeType() {
920 Attribute att = new Attribute("att", "value", AttributeType.CDATA);
921 assertTrue(att.getAttributeType() == AttributeType.CDATA);
922 att.setAttributeType(null);
923 assertTrue(att.getAttributeType() == AttributeType.UNDECLARED);
924 att.setAttributeType(AttributeType.ID);
925 assertTrue(att.getAttributeType() == AttributeType.ID);
926 }
927
928 @Test
929 public void testSpecified() {
930 Attribute att = new Attribute("att", "value");
931 assertTrue(att.isSpecified());
932 att.setSpecified(false);
933 assertFalse(att.isSpecified());
934
935 att.setValue("val");
936 assertTrue(att.isSpecified());
937 att.setSpecified(false);
938 assertFalse(att.isSpecified());
939
940 att.setName("attb");
941 assertTrue(att.isSpecified());
942 att.setSpecified(false);
943 assertFalse(att.isSpecified());
944
945 att.setNamespace(Namespace.getNamespace("pfx", "nothing"));
946 assertTrue(att.isSpecified());
947 att.setSpecified(false);
948 assertFalse(att.isSpecified());
949
950 att.setAttributeType(AttributeType.ID);
951 assertTrue(att.isSpecified());
952 att.setSpecified(false);
953 assertFalse(att.isSpecified());
954
955 }
956
957 }
0 package org.jdom.test.cases;
1
2 import java.util.ArrayList;
3 import java.util.Arrays;
4 import java.util.Iterator;
5 import java.util.List;
6
7 import org.jdom.Attribute;
8 import org.jdom.Comment;
9 import org.jdom.Element;
10 import org.jdom.IllegalAddException;
11 import org.jdom.Namespace;
12 import org.jdom.Text;
13 import org.jdom.internal.ArrayCopy;
14 import org.jdom.test.util.AbstractTestList;
15
16 import org.junit.Before;
17 import org.junit.Test;
18
19 import static org.junit.Assert.*;
20 import static org.jdom.test.util.UnitTestUtil.*;
21
22 @SuppressWarnings("javadoc")
23 public class TestAttributeList extends AbstractTestList<Attribute> {
24
25 private static final Element base = new Element("dummy");
26
27
28 public TestAttributeList() {
29 super(Attribute.class, false);
30 }
31
32 @Override
33 public List<Attribute> buildEmptyList() {
34 base.getAttributes().clear();
35 return base.getAttributes();
36 }
37
38 @Override
39 public Attribute[] buildSampleContent() {
40 return new Attribute[]{ new Attribute("zero", "val"),
41 new Attribute("one", "val"), new Attribute("two", "val"),
42 new Attribute("three", "val"), new Attribute("four", "val"),
43 new Attribute("five", "val"), new Attribute("six", "val"),
44 new Attribute("att", "val", Namespace.getNamespace("pfx", "nsX")),
45 new Attribute("sec", "val", Namespace.getNamespace("pfx", "nsX"))
46 };
47 }
48
49
50
51 @Override
52 public Attribute[] buildAdditionalContent() {
53 return new Attribute[]{ new Attribute("seven", "val"),
54 new Attribute("eight", "val")};
55 }
56
57 @Override
58 public Object[] buildIllegalClassContent() {
59 Object[] ret = new Object[] {
60 new Text("Hello"),
61 new Comment("Hello!")
62 };
63 return ret;
64 }
65
66 @Override
67 public Attribute[] buildIllegalArgumentContent() {
68 // this is illegal because it redefines the namespace from uri nsY to nsZ
69 return new Attribute[]{
70 new Attribute("att", "val", Namespace.getNamespace("pfx", "nsY")),
71 new Attribute("att", "val", Namespace.getNamespace("pfx", "nsZ"))
72
73 };
74 }
75
76 @Before
77 public void detatchAll () {
78 // make sure all content is detatched before each test.
79 for (Attribute c : buildSampleContent()) {
80 c.detach();
81 }
82 }
83
84 @Test
85 public void testDuplicateAttribute() {
86 Element emt = new Element("mine");
87 List<Attribute> attlist = emt.getAttributes();
88 Attribute att = new Attribute("hi", "there");
89 Attribute frodo = new Attribute("hi", "frodo");
90 Attribute bilbo = new Attribute("boo", "bilbo");
91 attlist.add(att);
92 try {
93 Element e2 = new Element("gandalph");
94 e2.setAttribute(frodo);
95 attlist.add(frodo);
96 failNoException(IllegalAddException.class);
97 } catch (Exception e) {
98 checkException(IllegalAddException.class, e);
99 }
100 frodo.detach();
101
102 // adding one 'hi' attribute should displace the other.
103 assertTrue(att.getParent() == emt);
104 assertTrue(attlist.add(frodo));
105 assertTrue(att.getParent() == null);
106 assertTrue(attlist.add(att));
107 assertTrue(att.getParent() == emt);
108 assertTrue(att == att.detach());
109
110 // list is now empty.
111 assertTrue(attlist.isEmpty());
112 assertTrue(attlist.add(frodo));
113 assertTrue(attlist.add(bilbo));
114 assertTrue(frodo == attlist.set(0, att));
115
116 try {
117 attlist.add(attlist.size(), frodo);
118 failNoException(IllegalAddException.class);
119 } catch (Exception e) {
120 checkException(IllegalAddException.class, e);
121 }
122 try {
123 attlist.set(1, frodo);
124 failNoException(IllegalAddException.class);
125 } catch (Exception e) {
126 checkException(IllegalAddException.class, e);
127 }
128 }
129
130 @Test
131 public void testAttributeNamspaceCollision() {
132 Element emt = new Element("mine");
133 List<Attribute> attlist = emt.getAttributes();
134 Attribute atta = new Attribute("hi", "there", Namespace.getNamespace("mypfx", "nsa"));
135 Attribute attb = new Attribute("hi", "there", Namespace.getNamespace("mypfx", "nsb"));
136 attlist.add(atta);
137 try {
138 // cannot add two different namespaces with same prefix.
139 attlist.add(attb);
140 failNoException(IllegalAddException.class);
141 } catch (Exception e) {
142 checkException(IllegalAddException.class, e);
143 }
144 Attribute attc = new Attribute("bilbo", "baggins", Namespace.getNamespace("mypfc", "nsc"));
145 // can add a different prefix.
146 attlist.add(attc);
147 try {
148 // cannot set an attribute that causes a conflict.
149 attlist.set(1, attb);
150 failNoException(IllegalAddException.class);
151 } catch (Exception e) {
152 checkException(IllegalAddException.class, e);
153 }
154
155 // but you can swap an existing attribute with a different one that changes
156 // the namespace URI for a prefix.
157 attlist.set(0, attb);
158
159 }
160
161 @Test
162 public void testSetAttributes() {
163 final Attribute[] extra = buildAdditionalContent();
164 if (extra.length <= 0) {
165 // android
166 //Assume.assumeTrue(extra.length > 0);
167 return;
168 }
169 final Attribute[] content = buildSampleContent();
170 if (content.length <= 0) {
171 // android
172 // Assume.assumeTrue(content.length > 0);
173 return;
174 }
175
176 // populate the list.
177 List<Attribute> list = buildEmptyList();
178 assertTrue(list.addAll(0, Arrays.asList(content)));
179 quickCheck(list, content);
180
181 // OK, we have a list of attributes.... behind the scenes, we have an
182 // an Element too... we need the element to get the setAttributes()
183 // method which in turn accesses the clearAndSet().
184 Element myelement = list.get(0).getParent();
185 assertNotNull(myelement);
186
187 ArrayList<Attribute> toset = new ArrayList<Attribute>(extra.length);
188 toset.addAll(Arrays.asList(extra));
189
190 // OK, test the setAttributes first.
191 assertTrue(myelement == myelement.setAttributes(toset));
192 // attributes should be the new ones.
193 quickCheck(list, extra);
194 // restore the old ones.
195 assertTrue(myelement == myelement.setAttributes(Arrays.asList(content)));
196 // ensure an empty list clears...
197 toset.clear();
198 assertTrue(myelement == myelement.setAttributes(toset));
199 assertTrue(list.isEmpty());
200 // restore the old ones.
201 assertTrue(myelement == myelement.setAttributes(Arrays.asList(content)));
202 // ensure a null list clears...
203 toset = null;
204 assertTrue(myelement == myelement.setAttributes(toset));
205 assertTrue(list.isEmpty());
206
207
208 }
209
210
211 @Test
212 public void testIllegalSetAttributes() {
213 final Attribute[] illegal = buildIllegalArgumentContent();
214 if (illegal.length <= 0) {
215 //Assume.assumeTrue(illegal.length > 0);
216 return;
217 }
218 final Attribute[] extra = buildAdditionalContent();
219 if (extra.length <= 0) {
220 // Assume.assumeTrue(extra.length > 0);
221 return;
222 }
223 final Attribute[] content = buildSampleContent();
224 if (content.length <= 0) {
225 //Assume.assumeTrue(content.length > 0);
226 return;
227 }
228 // the ' + 1' ensures a null value too!
229 Attribute[] toadd = ArrayCopy.copyOf(extra, extra.length + illegal.length + 1);
230 System.arraycopy(illegal, 0, toadd, extra.length, illegal.length);
231
232 // right, we have legal content in 'content', and then in 'illegal' we
233 // have some legal content, and then some illegal content.
234
235 // populate the list.
236 List<Attribute> list = buildEmptyList();
237 assertTrue(list.addAll(0, Arrays.asList(content)));
238 quickCheck(list, content);
239
240 // OK, we have a list of attributes.... behind the scenes, we have an
241 // an Element too... we need the element to get the setAttributes()
242 // method which in turn accesses the clearAndSet().
243 Element myelement = list.get(0).getParent();
244 assertNotNull(myelement);
245
246 // check that the first to-add can be added.
247 list.add(0, toadd[0]);
248 //then remove it again.
249 assertTrue(toadd[0] == list.remove(0));
250
251 quickCheck(list, content);
252
253 // now, add the illegal, and then inspect the list...
254 try {
255 myelement.setAttributes(Arrays.asList(toadd));
256 failNoException(IllegalArgumentException.class);
257 } catch (Exception e) {
258 checkException(IllegalArgumentException.class, e);
259 }
260
261 // make sure that the member that previously could be added can
262 // still be added.
263 list.add(0, toadd[0]);
264 //then remove it again.
265 assertTrue(toadd[0] == list.remove(0));
266
267 // make sure it's all OK.
268 exercise(list, content);
269
270 if (content.length < 2) {
271 //Assume.assumeTrue(content.length >= 2);
272 return;
273 }
274
275 // now check to make sure that concurrency is not affected....
276 Iterator<Attribute> it = list.iterator();
277 // move it along at least once.....
278 assertTrue(content[0] == it.next());
279 // now do a failed addAll.
280 try {
281 myelement.setAttributes(Arrays.asList(toadd));
282 failNoException(IllegalArgumentException.class);
283 } catch (Exception e) {
284 checkException(IllegalArgumentException.class, e);
285 }
286 // we should be able to move the iterator because the modCount should
287 // not have been affected.....
288 assertTrue(content[1] == it.next());
289 }
290
291 @Test
292 public void testAlreadyHasParent () {
293 // create an attribute.
294 final Attribute att = new Attribute("att", "val");
295 // give this attribute a parent.
296 final Element parent = new Element("parent");
297 parent.setAttribute(att);
298
299 // none will have no attributes.
300 final Element none = new Element("none");
301 // same will have an attribute with the same name as att.
302 final Element same = new Element("same");
303 same.setAttribute("att", "val");
304 // other will have an attrubute not the same as att.
305 final Element other = new Element("other");
306 other.setAttribute("diff", "other");
307
308 try {
309 // cannot set an attribute with an existing parent.
310 none.setAttribute(att);
311 failNoException(IllegalAddException.class);
312 } catch (Exception e) {
313 checkException(IllegalAddException.class, e);
314 }
315
316 try {
317 // cannot set an attribute with an existing parent.
318 same.setAttribute(att);
319 failNoException(IllegalAddException.class);
320 } catch (Exception e) {
321 checkException(IllegalAddException.class, e);
322 }
323
324 try {
325 // cannot set an attribute with an existing parent.
326 other.setAttribute(att);
327 failNoException(IllegalAddException.class);
328 } catch (Exception e) {
329 checkException(IllegalAddException.class, e);
330 }
331
332 try {
333 // cannot add an attribute with an existing parent.
334 none.getAttributes().add(att);
335 failNoException(IllegalAddException.class);
336 } catch (Exception e) {
337 checkException(IllegalAddException.class, e);
338 }
339
340 try {
341 // cannot add an attribute with an existing parent.
342 same.getAttributes().add(att);
343 failNoException(IllegalAddException.class);
344 } catch (Exception e) {
345 checkException(IllegalAddException.class, e);
346 }
347
348 try {
349 // cannot add an attribute with an existing parent.
350 other.getAttributes().add(att);
351 failNoException(IllegalAddException.class);
352 } catch (Exception e) {
353 checkException(IllegalAddException.class, e);
354 }
355
356 try {
357 // cannot add an attribute with an existing parent.
358 none.getAttributes().add(0, att);
359 failNoException(IllegalAddException.class);
360 } catch (Exception e) {
361 checkException(IllegalAddException.class, e);
362 }
363
364 try {
365 // cannot add an attribute with an existing parent.
366 same.getAttributes().add(0, att);
367 failNoException(IllegalAddException.class);
368 } catch (Exception e) {
369 checkException(IllegalAddException.class, e);
370 }
371
372 try {
373 // cannot add an attribute with an existing parent.
374 other.getAttributes().add(0, att);
375 failNoException(IllegalAddException.class);
376 } catch (Exception e) {
377 checkException(IllegalAddException.class, e);
378 }
379
380 try {
381 // cannot set an empty value.
382 // cannot add an attribute with an existing parent.
383 none.getAttributes().set(0, att);
384 failNoException(IndexOutOfBoundsException.class);
385 } catch (Exception e) {
386 checkException(IndexOutOfBoundsException.class, e);
387 }
388
389 try {
390 // cannot add an attribute with an existing parent.
391 same.getAttributes().set(0, att);
392 failNoException(IllegalAddException.class);
393 } catch (Exception e) {
394 checkException(IllegalAddException.class, e);
395 }
396
397 try {
398 // cannot add an attribute with an existing parent.
399 other.getAttributes().set(0, att);
400 failNoException(IllegalAddException.class);
401 } catch (Exception e) {
402 checkException(IllegalAddException.class, e);
403 }
404
405 assertEquals("val", same.getAttributeValue("att"));
406 assertEquals("other", other.getAttributeValue("diff"));
407 assertFalse(none.hasAttributes());
408
409 }
410
411 }
0 package org.jdom.test.cases;
1
2 import static org.jdom.test.util.UnitTestUtil.compare;
3 import static org.junit.Assert.assertTrue;
4
5 import java.lang.reflect.Method;
6 import java.util.ArrayList;
7
8 import org.junit.Test;
9
10 import org.jdom.Attribute;
11 import org.jdom.CDATA;
12 import org.jdom.Comment;
13 import org.jdom.DocType;
14 import org.jdom.Document;
15 import org.jdom.EntityRef;
16 import org.jdom.NamespaceAware;
17 import org.jdom.ProcessingInstruction;
18 import org.jdom.Text;
19
20 /**
21 * When you use Generics Java automatically creates 'bridge' methods.
22 * <p>
23 * Additionally, when you use the concept of 'co-variant return values' you
24 * create 'bridge' methods. By way of example, because we change the return
25 * type of clone() from Object to 'ZZZZ', Java is forced to put in a
26 * 'bridge' method that has an Object return type, even though we never
27 * actually call it.
28 * <p>
29 * This has an impact on the code coverage tool Cobertura, which reports
30 * that there is missed code (and there is, the bridge method). It reports
31 * it as being '0' calls to the 'class' line (the class line is marked red).
32 * <p>
33 * This test class exercises many of these 'bridge' methods, and thus improves
34 * the code coverage.
35 *
36 * @author Rolf Lear
37 *
38 */
39 public class TestBridgeMethods {
40
41 private static final Object[] invokeAll(final Object o, final String name) {
42 final ArrayList<Object> al = new ArrayList<Object>();
43 for (Method m : o.getClass().getMethods()) {
44 if (m.getName().equals(name) && m.isBridge() &&
45 m.getParameterTypes().length == 0) {
46 try {
47 al.add(m.invoke(o));
48 } catch (Exception e) {
49 throw new IllegalStateException(e);
50 }
51 }
52 }
53 return al.toArray();
54 }
55
56 /**
57 * Test various known Bridge Methods. This improves code coverage.
58 */
59 @Test
60 public void testDetachBridges() {
61 final NamespaceAware[] cnt = {
62 new Text("Text"),
63 new CDATA("cdata"),
64 new Comment("comment"),
65 new DocType("root"),
66 new EntityRef("ref"),
67 new ProcessingInstruction("pi"),
68 new Attribute("att", "val"),
69 new Document()
70 };
71 for (NamespaceAware c : cnt) {
72 Object[] a = invokeAll(c, "clone");
73 for (Object o : a) {
74 compare(c, (NamespaceAware)o);
75 }
76 Object[] d = invokeAll(c, "detach");
77 for (Object o : d) {
78 assertTrue(o == c);
79 }
80 Object[] e = invokeAll(c, "getParent");
81 for (Object o : e) {
82 assertTrue(o == null);
83 }
84 }
85 }
86
87 }
0 /*--
1
2 Copyright (C) 2006 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53 package org.jdom.test.cases;
54
55 import org.jdom.CDATA;
56 import org.jdom.Content;
57 import org.jdom.Element;
58 import org.jdom.IllegalDataException;
59 import org.jdom.Text;
60 import org.junit.Test;
61 import org.junit.runner.JUnitCore;
62 import static org.junit.Assert.*;
63
64 /**
65 * Test for {@link CDATA}.
66 *
67 * @author Victor Toni
68 * @version 1.0.0
69 */
70 @SuppressWarnings("javadoc")
71 public final class TestCDATA {
72
73 /**
74 * The main method runs all the tests in the text ui
75 */
76 public static void main (final String args[]) {
77 JUnitCore.runClasses(TestCDATA.class);
78 }
79
80 /**
81 * Test the protected CDATA constructor.
82 */
83 @Test
84 public void test_TCC() {
85 new CDATA() {
86 // check protected constructor via anonymous class
87 private static final long serialVersionUID = 200L;
88 };
89 }
90
91 /**
92 * Test the CDATA constructor with a valid and an invalid string.
93 */
94 @Test
95 public void test_TCC___String() {
96 final String text = "this is a CDATA section";
97
98 final CDATA cdata = new CDATA(text);
99
100 assertEquals(
101 "incorrect CDATA constructed",
102 "[CDATA: " + text + ']',
103 cdata.toString());
104
105 try {
106 new CDATA("");
107 } catch (final IllegalDataException e) {
108 fail("CDATA constructor did throw exception on empty string");
109 }
110
111 try {
112 new CDATA(null);
113 } catch (final IllegalDataException e) {
114 fail("CDATA constructor did throw exception on null");
115 }
116
117 try {
118 new CDATA("some valid <text> with a CDATA section ending ]]>");
119 fail("CDATA constructor didn't catch invalid comment string");
120 } catch (final IllegalDataException e) {
121 // Do nothing
122 } catch (Exception e) {
123 fail("Unexpected exception " + e.getClass());
124 }
125 }
126
127 /**
128 * Verify a simple object == object test
129 */
130 @Test
131 public void test_TCM__boolean_equals_Object() {
132 final String text = "this is a CDATA section";
133 final CDATA cdata = new CDATA(text);
134
135 final Object object = cdata;
136
137 assertTrue("object not equal to CDATA", cdata.equals(object));
138 assertTrue("CDATA not equal to object", object.equals(cdata));
139 }
140
141 /**
142 * Test that a real hashcode is returned and that a different one is returned
143 * for a different CDATA.
144 */
145 @Test
146 public void test_TCM__int_hashCode() {
147 final String text = "this is a CDATA section";
148 final CDATA cdata = new CDATA(text);
149
150 //only an exception would be a problem
151 int hash = -1;
152 try {
153 hash = cdata.hashCode();
154 }
155 catch(final Exception exception) {
156 fail("bad hashCode");
157 }
158
159 // same text but created out of parts to avoid object re-usage
160 final CDATA similarCDATA = new CDATA("this"+ " is" +" a" + " CDATA" + " section");
161
162 //different CDATA sections, same text
163 final int similarHash = similarCDATA.hashCode();
164 assertTrue("Different comments with same value have same hashcode", hash != similarHash);
165
166 final CDATA otherCDATA = new CDATA("this is another CDATA section");
167
168 //only an exception would be a problem
169 int otherHash = otherCDATA.hashCode();
170 assertTrue("Different comments have same hashcode", otherHash != hash);
171 assertTrue("Different comments have same hashcode", otherHash != similarHash);
172 }
173
174 /**
175 * Test setting and resetting the text value of this CDATA.
176 */
177 @Test
178 public void test_TCM__orgJdomText_setText_String() {
179 // simple text in CDATA section
180 final String text = "this is a CDATA section";
181 final CDATA cdata = new CDATA(text);
182 assertEquals("incorrect CDATA text", text, cdata.getText());
183
184 // set it to the empty string
185 final String emptyString = "";
186 cdata.setText(emptyString);
187 assertEquals("incorrect CDATA text", emptyString, cdata.getText());
188
189 // set it to a another string
190 final String otherString = "12345qwerty";
191 cdata.setText(otherString);
192 assertEquals("incorrect CDATA text", otherString, cdata.getText());
193
194 // set it to the null (after it was set to another string so that we
195 // are sure something has changed)
196 cdata.setText(null);
197 assertEquals("incorrect CDATA text", emptyString, cdata.getText());
198
199 // the following test check for invalid data and transactional behavior
200 // means the content must not be change on exceptions so we set a default
201
202 // set text with some special characters
203 final String specialText = "this is CDATA section with special characters as < > & &amp; &lt; &gt; [[ ]] > <![![";
204 cdata.setText(specialText);
205 assertEquals("incorrect CDATA text", specialText, cdata.getText());
206
207
208 cdata.setText(otherString);
209 try {
210 final char c= 0x11;
211 final StringBuilder buffer = new StringBuilder("hhhh");
212 buffer.setCharAt(2, c);
213
214 cdata.setText(buffer.toString());
215 fail("Comment setText didn't catch invalid CDATA string");
216 } catch (final IllegalDataException exception) {
217 assertEquals("incorrect CDATA text after exception", otherString, cdata.getText());
218 }
219
220 cdata.setText(text);
221 try {
222 final String invalidCDATAString = "some valid <text> with an invlaid CDATA section ending ]]>";
223
224 cdata.setText(invalidCDATAString);
225 fail("Comment setText didn't catch invalid CDATA string");
226 } catch (final IllegalDataException exception) {
227 assertEquals("incorrect CDATA text after exception", text, cdata.getText());
228 }
229 }
230
231 /**
232 * Test appending text values to this CDATA.
233 */
234 @Test
235 public void test_TCM___append_String() {
236 final String emptyString = "";
237 final String nullString = null;
238 final String text = "this is a CDATA section";
239 final String otherString = "12345qwerty";
240 final String specialCharactersText = "this is CDATA section with special characters as < > & &amp; &lt; &gt; [[ ]] > <![![";
241 final String specialText = "> this is a CDATA section with special characters as ]]";
242 final String cdataEndText = "this is aCDATA section with a CDATA end marke ]]> somewhere inside";
243
244 {
245 // simple text in CDATA section
246 final CDATA cdata = new CDATA(text);
247 assertEquals("incorrect CDATA text", text, cdata.getText());
248 cdata.append(text);
249 assertEquals("incorrect CDATA text", text+text, cdata.getText());
250 try {
251 cdata.append(cdataEndText);
252 fail("failed to detect CDATA end marker");
253 } catch (final IllegalDataException exception) {
254 // Do nothing
255 } catch (Exception e) {
256 fail("Unexpected exception " + e.getClass());
257 }
258 }
259
260 {
261 // set it to the empty string
262 final CDATA cdata = new CDATA(emptyString);
263 assertEquals("incorrect CDATA text", "", cdata.getText());
264 cdata.append(emptyString);
265 assertEquals("incorrect CDATA text", "", cdata.getText());
266 cdata.append(text);
267 assertEquals("incorrect CDATA text", text, cdata.getText());
268 cdata.append(nullString);
269 assertEquals("incorrect CDATA text", text, cdata.getText());
270 cdata.append(specialCharactersText);
271 assertEquals("incorrect CDATA text", text + specialCharactersText, cdata.getText());
272 cdata.append(nullString);
273 assertEquals("incorrect CDATA text", text + specialCharactersText, cdata.getText());
274 cdata.append(emptyString);
275 assertEquals("incorrect CDATA text", text + specialCharactersText, cdata.getText());
276 cdata.append(otherString);
277 assertEquals("incorrect CDATA text", text + specialCharactersText + otherString, cdata.getText());
278 try {
279 cdata.append(cdataEndText);
280 fail("failed to detect CDATA end marker");
281 } catch (final IllegalDataException exception) {
282 // Do nothing
283 } catch (Exception e) {
284 fail("Unexpected exception " + e.getClass());
285 }
286 }
287
288 {
289 // set it to a another string
290 final CDATA cdata = new CDATA(otherString);
291 assertEquals("incorrect CDATA text", otherString, cdata.getText());
292 cdata.append(text);
293 assertEquals("incorrect CDATA text", otherString + text, cdata.getText());
294 cdata.append(nullString);
295 assertEquals("incorrect CDATA text", otherString + text, cdata.getText());
296 cdata.append(specialCharactersText);
297 assertEquals("incorrect CDATA text", otherString + text + specialCharactersText, cdata.getText());
298 cdata.append(nullString);
299 assertEquals("incorrect CDATA text", otherString + text + specialCharactersText, cdata.getText());
300 cdata.append(emptyString);
301 assertEquals("incorrect CDATA text", otherString + text + specialCharactersText, cdata.getText());
302 try {
303 cdata.append(cdataEndText);
304 fail("failed to detect CDATA end marker");
305 } catch (final IllegalDataException exception) {
306 // Do nothing
307 } catch (Exception e) {
308 fail("Unexpected exception " + e.getClass());
309 }
310 }
311
312 {
313 // set it to the null (after it was set to another string so that we
314 // are sure something has changed)
315 final CDATA cdata = new CDATA(nullString);
316 assertEquals("incorrect CDATA text", "", cdata.getText());
317 cdata.append(specialCharactersText);
318 assertEquals("incorrect CDATA text", specialCharactersText, cdata.getText());
319 cdata.append(nullString);
320 assertEquals("incorrect CDATA text", specialCharactersText, cdata.getText());
321 cdata.append(text);
322 assertEquals("incorrect CDATA text", specialCharactersText + text, cdata.getText());
323 cdata.append(nullString);
324 assertEquals("incorrect CDATA text", specialCharactersText + text, cdata.getText());
325 cdata.append(emptyString);
326 assertEquals("incorrect CDATA text", specialCharactersText + text, cdata.getText());
327 cdata.append(otherString);
328 assertEquals("incorrect CDATA text", specialCharactersText + text + otherString, cdata.getText());
329 try {
330 cdata.append(cdataEndText);
331 fail("failed to detect CDATA end marker");
332 } catch (final IllegalDataException exception) {
333 // Do nothing
334 } catch (Exception e) {
335 fail("Unexpected exception " + e.getClass());
336 }
337 }
338
339 {
340 // set it to the null (after it was set to another string so that we
341 // are sure something has changed)
342 final CDATA cdata = new CDATA(null);
343 assertEquals("incorrect CDATA text", "", cdata.getText());
344 cdata.append((String) null);
345 assertEquals("incorrect CDATA text", "", cdata.getText());
346 try {
347 cdata.append(cdataEndText);
348 fail("failed to detect CDATA end marker");
349 } catch (final IllegalDataException exception) {
350 // Do nothing
351 } catch (Exception e) {
352 fail("Unexpected exception " + e.getClass());
353 }
354 }
355
356 {
357 // set it to the null (after it was set to another string so that we
358 // are sure something has changed)
359 final CDATA cdata = new CDATA(null);
360 assertEquals("incorrect CDATA text", "", cdata.getText());
361 cdata.append((Text) null);
362 assertEquals("incorrect CDATA text", "", cdata.getText());
363 try {
364 cdata.append(cdataEndText);
365 fail("failed to detect CDATA end marker");
366 } catch (final IllegalDataException exception) {
367 // Do nothing
368 } catch (Exception e) {
369 fail("Unexpected exception " + e.getClass());
370 }
371 }
372
373 {
374 // set text with some special characters
375 final CDATA cdata = new CDATA(specialCharactersText);
376 assertEquals("incorrect CDATA text", specialCharactersText, cdata.getText());
377 cdata.append(specialCharactersText);
378 assertEquals("incorrect CDATA text", specialCharactersText + specialCharactersText, cdata.getText());
379 try {
380 cdata.append(cdataEndText);
381 fail("failed to detect CDATA end marker");
382 } catch (final IllegalDataException exception) {
383 // Do nothing
384 } catch (Exception e) {
385 fail("Unexpected exception " + e.getClass());
386 }
387 }
388
389
390 try {
391 // set text with some special characters which should result into an exception
392 final CDATA cdata = new CDATA(specialText);
393 assertEquals("incorrect CDATA text", specialText, cdata.getText());
394 cdata.append(specialText);
395
396 fail("failed to detect CDATA end marker");
397 } catch (final IllegalDataException exception) {
398 // Do nothing
399 } catch (Exception e) {
400 fail("Unexpected exception " + e.getClass());
401 }
402 }
403
404 /**
405 * Test appending text values to this CDATA.
406 */
407 @Test
408 public void test_TCM___append_Text() {
409 final String emptyString = "";
410 final String nullString = null;
411 final String text = "this is a CDATA section";
412 final String otherString = "12345qwerty";
413 final String specialCharactersText = "this is CDATA section with special characters as < > & &amp; &lt; &gt; [[ ]] > <![![";
414 final String specialText = "> this is a CDATA section with special characters as ]]";
415 final String cdataEndText = "this is aCDATA section with a CDATA end marke ]]> somewhere inside";
416
417 {
418 // simple text in CDATA section
419 final CDATA cdata = new CDATA(text);
420 assertEquals("incorrect CDATA text", text, cdata.getText());
421 cdata.append(new Text(text));
422 assertEquals("incorrect CDATA text", text+text, cdata.getText());
423 try {
424 cdata.append(new Text(cdataEndText));
425 fail("failed to detect CDATA end marker");
426 } catch (final IllegalDataException exception) {
427 // Do nothing
428 } catch (Exception e) {
429 fail("Unexpected exception " + e.getClass());
430 }
431 }
432
433 {
434 // set it to the empty string
435 final CDATA cdata = new CDATA(emptyString);
436 assertEquals("incorrect CDATA text", "", cdata.getText());
437 cdata.append(new Text(emptyString));
438 assertEquals("incorrect CDATA text", "", cdata.getText());
439 cdata.append(new Text(text));
440 assertEquals("incorrect CDATA text", text, cdata.getText());
441 cdata.append(new Text(nullString));
442 assertEquals("incorrect CDATA text", text, cdata.getText());
443 cdata.append(new Text(specialCharactersText));
444 assertEquals("incorrect CDATA text", text + specialCharactersText, cdata.getText());
445 cdata.append(new Text(nullString));
446 assertEquals("incorrect CDATA text", text + specialCharactersText, cdata.getText());
447 cdata.append(new Text(emptyString));
448 assertEquals("incorrect CDATA text", text + specialCharactersText, cdata.getText());
449 cdata.append(new Text(otherString));
450 assertEquals("incorrect CDATA text", text + specialCharactersText + otherString, cdata.getText());
451 try {
452 cdata.append(new Text(cdataEndText));
453 fail("failed to detect CDATA end marker");
454 } catch (final IllegalDataException exception) {
455 // Do nothing
456 } catch (Exception e) {
457 fail("Unexpected exception " + e.getClass());
458 }
459 }
460
461 {
462 // set it to a another string
463 final CDATA cdata = new CDATA(otherString);
464 assertEquals("incorrect CDATA text", otherString, cdata.getText());
465 cdata.append(new Text(text));
466 assertEquals("incorrect CDATA text", otherString + text, cdata.getText());
467 cdata.append(new Text(nullString));
468 assertEquals("incorrect CDATA text", otherString + text, cdata.getText());
469 cdata.append(new Text(specialCharactersText));
470 assertEquals("incorrect CDATA text", otherString + text + specialCharactersText, cdata.getText());
471 cdata.append(new Text(nullString));
472 assertEquals("incorrect CDATA text", otherString + text + specialCharactersText, cdata.getText());
473 cdata.append(new Text(emptyString));
474 assertEquals("incorrect CDATA text", otherString + text + specialCharactersText, cdata.getText());
475 try {
476 cdata.append(new Text(cdataEndText));
477 fail("failed to detect CDATA end marker");
478 } catch (final IllegalDataException exception) {
479 // Do nothing
480 } catch (Exception e) {
481 fail("Unexpected exception " + e.getClass());
482 }
483 }
484
485 {
486 // set it to the null (after it was set to another string so that we
487 // are sure something has changed)
488 final CDATA cdata = new CDATA(nullString);
489 assertEquals("incorrect CDATA text", "", cdata.getText());
490 cdata.append(new Text(specialCharactersText));
491 assertEquals("incorrect CDATA text", specialCharactersText, cdata.getText());
492 cdata.append(new Text(nullString));
493 assertEquals("incorrect CDATA text", specialCharactersText, cdata.getText());
494 cdata.append(new Text(text));
495 assertEquals("incorrect CDATA text", specialCharactersText + text, cdata.getText());
496 cdata.append(new Text(nullString));
497 assertEquals("incorrect CDATA text", specialCharactersText + text, cdata.getText());
498 cdata.append(new Text(emptyString));
499 assertEquals("incorrect CDATA text", specialCharactersText + text, cdata.getText());
500 cdata.append(new Text(otherString));
501 assertEquals("incorrect CDATA text", specialCharactersText + text + otherString, cdata.getText());
502 try {
503 cdata.append(new Text(cdataEndText));
504 fail("failed to detect CDATA end marker");
505 } catch (final IllegalDataException exception) {
506 // Do nothing
507 } catch (Exception e) {
508 fail("Unexpected exception " + e.getClass());
509 }
510 }
511
512 {
513 // set it to the null (after it was set to another string so that we
514 // are sure comething has changed)
515 final CDATA cdata = new CDATA(null);
516 assertEquals("incorrect CDATA text", "", cdata.getText());
517 cdata.append((String) null);
518 assertEquals("incorrect CDATA text", "", cdata.getText());
519 try {
520 cdata.append(new Text(cdataEndText));
521 fail("failed to detect CDATA end marker");
522 } catch (final IllegalDataException exception) {
523 // Do nothing
524 } catch (Exception e) {
525 fail("Unexpected exception " + e.getClass());
526 }
527 }
528
529 {
530 // set it to the null (after it was set to another string so that we
531 // are sure something has changed)
532 final CDATA cdata = new CDATA(null);
533 assertEquals("incorrect CDATA text", "", cdata.getText());
534 cdata.append((Text) null);
535 assertEquals("incorrect CDATA text", "", cdata.getText());
536 try {
537 cdata.append(new Text(cdataEndText));
538 fail("failed to detect CDATA end marker");
539 } catch (final IllegalDataException exception) {
540 // Do nothing
541 } catch (Exception e) {
542 fail("Unexpected exception " + e.getClass());
543 }
544 }
545
546 {
547 // set text with some special characters
548 final CDATA cdata = new CDATA(specialCharactersText);
549 assertEquals("incorrect CDATA text", specialCharactersText, cdata.getText());
550 cdata.append(new Text(specialCharactersText));
551 assertEquals("incorrect CDATA text", specialCharactersText + specialCharactersText, cdata.getText());
552 try {
553 cdata.append(new Text(cdataEndText));
554 fail("failed to detect CDATA end marker");
555 } catch (final IllegalDataException exception) {
556 // Do nothing
557 } catch (Exception e) {
558 fail("Unexpected exception " + e.getClass());
559 }
560 }
561
562
563 try {
564 // set text with some special characters which sould result into an exception
565 final CDATA cdata = new CDATA(specialText);
566 assertEquals("incorrect CDATA text", specialText, cdata.getText());
567 cdata.append(new Text(specialText));
568
569 fail("failed to detect CDATA end marker");
570 } catch (final IllegalDataException exception) {
571 // Do nothing
572 } catch (Exception e) {
573 fail("Unexpected exception " + e.getClass());
574 }
575 }
576
577 /**
578 * Verify that the text of the CDATA matches expected value.
579 * It assumes that the constructor is working correctly
580 */
581 @Test
582 public void test_TCM__String_getText() {
583 {
584 final String text = "this is a CDATA section";
585
586 final CDATA cdata = new CDATA(text);
587 assertEquals("incorrect CDATA text", text, cdata.getText());
588 }
589
590 {
591 //set it to the empty string
592 final String emptyString = "";
593 final CDATA cdata = new CDATA(emptyString);
594 assertEquals("incorrect CDATA text", emptyString, cdata.getText());
595 }
596
597 {
598 // set it to a another string
599 final String otherString = "12345qwerty";
600 final CDATA cdata = new CDATA(otherString);
601 assertEquals("incorrect CDATA text", otherString, cdata.getText());
602 }
603
604 {
605 // set it to the null
606 final CDATA cdata = new CDATA(null);
607 assertEquals("incorrect CDATA text", "", cdata.getText());
608 }
609 }
610
611 /**
612 * check for the expected toString text value of Comment.
613 */
614 @Test
615 public void test_TCM__String_toString() {
616 {
617 final String text = "this is a simple CDATA section";
618 final CDATA cdata = new CDATA(text);
619
620 assertEquals(
621 "incorrect CDATA constructed",
622 "[CDATA: " + text + ']',
623 cdata.toString());
624 }
625
626 {
627 final String text = "this is CDATA section with special characters as < > & &amp; &lt; &gt; [[ ]] > <![![";
628 final CDATA cdata = new CDATA(text);
629
630 assertEquals(
631 "incorrect CDATA constructed",
632 "[CDATA: " + text + ']',
633 cdata.toString());
634 }
635
636 }
637
638 @Test
639 public void testCloneDetatchParentCDATA() {
640 Element parent = new Element("root");
641 CDATA content = new CDATA("val");
642 parent.addContent(content);
643 CDATA clone = content.detach().clone();
644 assertEquals(content.getValue(), clone.getValue());
645 assertNull(content.getParent());
646 assertNull(clone.getParent());
647 }
648
649 @Test
650 public void testContentCType() {
651 assertTrue(Content.CType.CDATA == new CDATA("").getCType());
652 }
653 }
0 package org.jdom.test.cases;
1
2 /*--
3
4 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact license@jdom.org.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management (pm@jdom.org).
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Brett McLaughlin <brett@jdom.org> and
51 Jason Hunter <jhunter@jdom.org>. For more information on the
52 JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56
57 /**
58 * Please put a description of your test here.
59 *
60 * @author Philip Nelson
61 * @version 1.0
62 */
63 import static org.junit.Assert.assertEquals;
64 import static org.junit.Assert.assertNull;
65 import static org.junit.Assert.assertTrue;
66 import static org.junit.Assert.fail;
67
68 import org.jdom.Comment;
69 import org.jdom.Content;
70 import org.jdom.Element;
71 import org.jdom.IllegalDataException;
72 import org.junit.Test;
73 import org.junit.runner.JUnitCore;
74
75 @SuppressWarnings("javadoc")
76 public final class TestComment {
77
78 /**
79 * The main method runs all the tests in the text ui
80 */
81 public static void main (String args[])
82 {
83 JUnitCore.runClasses(TestComment.class);
84 }
85
86 @Test
87 public void test_TCC() {
88 // test creating a subclass with an anonymous instance
89 final Comment theComment = new Comment() {
90 // no modifications.
91 private static final long serialVersionUID = 200L;
92 };
93 assertTrue(null == theComment.getText());
94 }
95 /**
96 * Test the comment constructor with a valid and an invalid string.
97 */
98 @Test
99 public void test_TCC___String() {
100 Comment theComment = new org.jdom.Comment("this is a comment");
101
102 assertEquals(
103 "incorrect Comment constructed",
104 "[Comment: <!--this is a comment-->]",
105 theComment.toString());
106 try {
107 theComment = new org.jdom.Comment(null);
108 fail("Comment constructor didn't catch invalid comment string");
109 } catch (IllegalDataException e) {
110 // Do nothing
111 } catch (Exception e) {
112 fail("Unexpected exception " + e.getClass());
113 }
114 }
115 /**
116 * Verify a simple object == object test
117 */
118 @Test
119 public void test_TCM__boolean_equals_Object() {
120 Comment com = new Comment("test");
121
122 Object ob = com;
123
124 assertTrue("object not equal to comment", com.equals(ob));
125 }
126 /**
127 * Test that a real hashcode is returned and that a different one is returned
128 * for a different comment.
129 */
130 @Test
131 public void test_TCM__int_hashCode() {
132 //not sure what to test!
133
134 Comment com = new Comment("test");
135 //only an exception would be a problem
136 int i = -1;
137 try {
138 i = com.hashCode();
139 }
140 catch(Exception e) {
141 fail("bad hashCode");
142 }
143 Comment com2 = new Comment("test");
144 //different comments, same text
145 int x = com2.hashCode();
146 assertTrue("Different comments with same value have same hashcode", x != i);
147 Comment com3 = new Comment("test2");
148 //only an exception would be a problem
149 int y = com3.hashCode();
150 assertTrue("Different comments have same hashcode", y != x);
151 }
152
153 /**
154 * Test setting and resetting the text value of this Comment.
155 */
156 @Test
157 public void test_TCM__OrgJdomComment_setText_String() {
158 Comment theComment= new org.jdom.Comment("this is a comment");
159
160 assertEquals(
161 "incorrect Comment constructed",
162 "[Comment: <!--this is a comment-->]",
163 theComment.toString());
164
165 //set it to the empty string
166 theComment.setText("");
167
168 assertEquals("incorrect Comment text", "", theComment.getText());
169 assertEquals(theComment.getText(), theComment.getValue());
170 //set it to a new string
171 theComment.setText("12345qwerty");
172
173 assertEquals("incorrect Comment text", "12345qwerty", theComment.getText());
174 assertEquals(theComment.getText(), theComment.getValue());
175
176 //tests for invalid data but setText doesn't
177
178 try {
179 theComment.setText(null);
180 fail("Comment setText didn't catch invalid comment string");
181 } catch (IllegalDataException e) {
182 // Do nothing
183 } catch (Exception e) {
184 fail("Unexpected exception " + e.getClass());
185 }
186 try {
187 char c= 0x11;
188 StringBuilder b= new StringBuilder("hhhh");
189 b.setCharAt(2, c);
190 theComment.setText(b.toString());
191 fail("Comment setText didn't catch invalid comment string");
192 } catch (IllegalDataException e) {
193 // Do nothing
194 } catch (Exception e) {
195 fail("Unexpected exception " + e.getClass());
196 }
197
198 }
199
200 /**
201 * Match the XML fragment this comment produces.
202 */
203 @Test
204 public void test_TCM__String_getSerializedForm() {
205
206 /** No op because the method is deprecated
207 Comment theComment = new org.jdom.Comment("this is a comment");
208
209 assertEquals(
210 "incorrect Comment constructed",
211 "<!--this is a comment-->",
212 theComment.getSerializedForm());
213 */
214
215 }
216
217 /**
218 * verify that the text of the Comment matches expected value.
219 */
220 @Test
221 public void test_TCM__String_getText() {
222 Comment theComment = new org.jdom.Comment("this is a comment");
223
224 assertEquals(
225 "incorrect Comment constructed",
226 "this is a comment",
227 theComment.getText());
228
229
230 }
231 /**
232 * check for the expected toString text value of Comment.
233 */
234 @Test
235 public void test_TCM__String_toString() {
236 Comment theComment= new org.jdom.Comment("this is a comment");
237
238 assertEquals(
239 "incorrect Comment constructed",
240 "[Comment: <!--this is a comment-->]",
241 theComment.toString());
242 try {
243 theComment= new org.jdom.Comment(null);
244 fail("Comment constructor didn't catch invalid comment string");
245 } catch (IllegalDataException e) {
246 // Do nothing
247 } catch (Exception e) {
248 fail("Unexpected exception " + e.getClass());
249 }
250 }
251
252 @Test
253 public void testCloneDetatchParentComment() {
254 Element parent = new Element("root");
255 Comment content = new Comment("val");
256 parent.addContent(content);
257 Comment clone = content.detach().clone();
258 assertEquals(content.getValue(), clone.getValue());
259 assertNull(content.getParent());
260 assertNull(clone.getParent());
261 }
262
263 @Test
264 public void testContentCType() {
265 assertTrue(Content.CType.Comment == new Comment("").getCType());
266 }
267 }
0 package org.jdom.test.cases;
1
2 import static org.jdom.test.util.UnitTestUtil.checkException;
3 import static org.jdom.test.util.UnitTestUtil.failNoException;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertTrue;
6
7 import java.util.Arrays;
8 import java.util.Iterator;
9 import java.util.List;
10
11 import org.jdom.Content;
12 import org.jdom.DocType;
13 import org.jdom.Element;
14 import org.jdom.internal.ArrayCopy;
15 import org.jdom.test.util.AbstractTestList;
16
17 import org.junit.Before;
18 import org.junit.Test;
19
20 @SuppressWarnings("javadoc")
21 public class TestContentList extends AbstractTestList<Content> {
22
23 public TestContentList() {
24 super(Content.class, false);
25 }
26
27 @Override
28 public List<Content> buildEmptyList() {
29 Element e = new Element("dummy");
30 return e.getContent();
31 }
32
33 @Override
34 public Content[] buildSampleContent() {
35 return new Content[]{ new Element("zero"),
36 new Element("one"), new Element("two"),
37 new Element("three"), new Element("four"),
38 new Element("five"), new Element("six")};
39 }
40
41 @Override
42 public Content[] buildAdditionalContent() {
43 return new Content[]{ new Element("seven"),
44 new Element("eight")};
45 }
46
47 @Override
48 public Object[] buildIllegalClassContent() {
49 Object[] ret = new Object[] {
50 new Integer(10),
51 new StringBuilder("Hello!")
52 };
53 return ret;
54 }
55
56 @Override
57 public Content[] buildIllegalArgumentContent() {
58 return new Content[]{new DocType("root")};
59 }
60
61 @Before
62 public void detatchAll () {
63 // make sure all content is detatched before each test.
64 for (Content c : buildSampleContent()) {
65 c.detach();
66 }
67 }
68
69 @Test
70 public void testIllegalSetContent() {
71 final Content[] illegal = buildIllegalArgumentContent();
72 if (illegal.length <= 0) {
73 //Assume.assumeTrue(illegal.length > 0);
74 return;
75 }
76 final Content[] extra = buildAdditionalContent();
77 if (extra.length <= 0) {
78 //Assume.assumeTrue(extra.length > 0);
79 return;
80 }
81 final Content[] content = buildSampleContent();
82 if (content.length <= 0) {
83 // Assume.assumeTrue(content.length > 0);
84 return;
85 }
86 // the ' + 1' ensures a null value too!
87 Content[] toadd = ArrayCopy.copyOf(extra, extra.length + illegal.length + 1);
88 System.arraycopy(illegal, 0, toadd, extra.length, illegal.length);
89
90 // right, we have legal content in 'content', and then in 'illegal' we
91 // have some legal content, and then some illegal content.
92
93 // populate the list.
94 List<Content> list = buildEmptyList();
95 assertTrue(list.addAll(0, Arrays.asList(content)));
96 quickCheck(list, content);
97
98 // OK, we have a list of attributes.... behind the scenes, we have an
99 // an Element too... we need the element to get the setContents()
100 // method which in turn accesses the clearAndSet().
101 Element myelement = list.get(0).getParentElement();
102 assertNotNull(myelement);
103
104 // check that the first to-add can be added.
105 list.add(0, toadd[0]);
106 //then remove it again.
107 assertTrue(toadd[0] == list.remove(0));
108
109 quickCheck(list, content);
110
111 // now, add the illegal, and then inspect the list...
112 try {
113 myelement.setContent(Arrays.asList(toadd));
114 failNoException(IllegalArgumentException.class);
115 } catch (Exception e) {
116 checkException(IllegalArgumentException.class, e);
117 }
118
119 // make sure that the member that previously could be added can
120 // still be added.
121 list.add(0, toadd[0]);
122 //then remove it again.
123 assertTrue(toadd[0] == list.remove(0));
124
125 // make sure it's all OK.
126 exercise(list, content);
127
128 if (content.length < 2) {
129 //Assume.assumeTrue(content.length >= 2);
130 return;
131 }
132
133 // now check to make sure that concurrency is not affected....
134 Iterator<Content> it = list.iterator();
135 // move it along at least once.....
136 assertTrue(content[0] == it.next());
137 // now do a failed addAll.
138 try {
139 myelement.setContent(Arrays.asList(toadd));
140 failNoException(IllegalArgumentException.class);
141 } catch (Exception e) {
142 checkException(IllegalArgumentException.class, e);
143 }
144 // we should be able to move the iterator because the modCount should
145 // not have been affected.....
146 assertTrue(content[1] == it.next());
147 }
148
149 }
0 package org.jdom.test.cases;
1
2 import org.jdom.DefaultJDOMFactory;
3 import org.jdom.JDOMFactory;
4
5 @SuppressWarnings("javadoc")
6 public class TestDefaultJDOMFactory extends AbstractTestJDOMFactory {
7
8 /**
9 * @param located
10 */
11 public TestDefaultJDOMFactory() {
12 super(false);
13 }
14
15 @Override
16 protected JDOMFactory buildFactory() {
17 return new DefaultJDOMFactory();
18 }
19
20 }
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7
8 import java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.NoSuchElementException;
11
12 import org.jdom.Content;
13 import org.jdom.Document;
14 import org.jdom.Element;
15 import org.jdom.filter.ElementFilter;
16 import org.jdom.util.IteratorIterable;
17
18 import org.junit.Test;
19
20 @SuppressWarnings("javadoc")
21 public class TestDescendantFilterIterator {
22 private static final String[] fellowship = new String[] {
23 "frodo", "sam", "pippin", "merry",
24 "legolas", "aragorn", "gimli", "boromir", "gandalf"
25 };
26
27 private static final IteratorIterable<Element> buildIterator() {
28 Element root = new Element("root");
29 Document doc = new Document(root);
30 for (String c : fellowship) {
31 root.addContent(new Element(c));
32 }
33
34 return doc.getDescendants(new ElementFilter());
35 }
36
37 @Test
38 public void testIteration() {
39 Iterator<Element> it = buildIterator();
40 assertTrue(it.hasNext());
41 Object f = it.next();
42 assertNotNull(f != null);
43 assertTrue(f instanceof Element);
44 assertEquals("root", ((Element)f).getName());
45 for (int i = 0; i < fellowship.length; i++) {
46 assertTrue(it.hasNext());
47 assertEquals(fellowship[i], it.next().getName());
48 }
49 assertFalse(it.hasNext());
50 try {
51 assertTrue(null != it.next().toString());
52 fail("Should not be able to iterate off the end of the descendants.");
53 } catch (NoSuchElementException nse) {
54 // good
55 } catch (Exception e) {
56 fail("Expected NoSuchElementException, but got " + e.getClass().getName());
57 }
58
59 }
60
61 @Test
62 public void testIterable() {
63 int i = 0;
64 for (Content c : buildIterator()) {
65 assertNotNull(c != null);
66 assertTrue(c instanceof Element);
67 Element e = (Element)c;
68 if (i == 0) {
69 assertEquals("root", e.getName());
70 } else {
71 assertEquals(fellowship[i - 1], e.getName());
72 }
73 i++;
74 }
75 }
76
77 @Test
78 public void testRemoveOne() {
79 Iterator<Element> it = buildIterator();
80 assertTrue(it.hasNext());
81 try {
82 it.remove();
83 fail("Should not be able to remove before next().");
84 } catch (IllegalStateException ise) {
85 // good
86 } catch (Exception e) {
87 e.printStackTrace();
88 fail ("Expected IllegalStateException but got " + e.getClass());
89 }
90
91 Object f = it.next();
92 assertNotNull(f != null);
93 assertTrue(f instanceof Element);
94 assertEquals("root", ((Element)f).getName());
95
96 // this should remove the root element, which effectively should
97 // make the descendant iterator empty.
98 it.remove();
99
100 try {
101 it.remove();
102 fail("Should not be able to double-remove.");
103 } catch (IllegalStateException ise) {
104 // good
105 } catch (Exception e) {
106 e.printStackTrace();
107 fail ("Expected IllegalStateException but got " + e.getClass());
108 }
109
110
111 assertFalse(it.hasNext());
112 try {
113 assertTrue(null != it.next().toString());
114 fail("Should not be able to iterate off the end of the descendants.");
115 } catch (NoSuchElementException nse) {
116 // good
117 } catch (Exception e) {
118 fail("Expected NoSuchElementException, but got " + e.getClass().getName());
119 }
120
121 }
122
123 @Test
124 public void testIllegal() {
125 try {
126 Element emt = new Element("root");
127 emt.getDescendants(null);
128 } catch (NullPointerException npe) {
129 // good
130 } catch (Exception e) {
131 fail("Expected NullPointerException, but got " + e.getClass().getName());
132 }
133 }
134
135 @Test
136 public void testDeep() {
137 Document doc = new Document();
138 Element emt = new Element("root");
139 Element kid = new Element("kid");
140 Element leaf = new Element("leaf");
141 kid.addContent(leaf);
142 emt.addContent(kid);
143 emt.addContent(new Element("sib"));
144 doc.addContent(emt);
145 String[] tags = new String[] {"root", "kid", "leaf", "sib"};
146 ArrayList<String> al = new ArrayList<String>();
147 Iterator<Element> it = doc.getDescendants(new ElementFilter());
148 while (it.hasNext()) {
149 al.add(it.next().getName());
150 }
151 assertTrue(al.size() == tags.length);
152 for (int i = 0; i < tags.length; i++) {
153 assertEquals(tags[i], al.get(i));
154 }
155
156 }
157
158 }
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7
8 import java.util.ArrayList;
9 import java.util.Iterator;
10 import java.util.NoSuchElementException;
11
12 import org.junit.Test;
13
14 import org.jdom.Content;
15 import org.jdom.Document;
16 import org.jdom.Element;
17 import org.jdom.test.util.UnitTestUtil;
18 import org.jdom.util.IteratorIterable;
19
20 @SuppressWarnings("javadoc")
21 public class TestDescendantIterator {
22 private static final String[] fellowship = new String[] {
23 "frodo", "sam", "pippin", "merry",
24 "legolas", "aragorn", "gimli", "boromir", "gandalf"
25 };
26
27 private static final IteratorIterable<Content> buildIterator() {
28 Element root = new Element("root");
29 Document doc = new Document(root);
30 for (String c : fellowship) {
31 root.addContent(new Element(c));
32 }
33
34 return doc.getDescendants();
35 }
36
37 private static final Element buildTestDoc() {
38 Element hobbits = new Element(fellowship[0]);
39 hobbits.addContent(new Element(fellowship[1]));
40 hobbits.addContent(new Element(fellowship[2]));
41 hobbits.addContent(new Element(fellowship[3]));
42 Element humans = new Element(fellowship[4]);
43 humans.addContent(new Element(fellowship[5]));
44 humans.addContent(new Element(fellowship[6]));
45 humans.addContent(new Element(fellowship[7]));
46 hobbits.addContent(humans);
47 // gandalf
48 hobbits.addContent(new Element(fellowship[8]));
49 return new Element("root").addContent(hobbits);
50 }
51
52 @Test
53 public void testIteration() {
54 Iterator<Content> it = buildIterator();
55 assertTrue(it.hasNext());
56 Object f = it.next();
57 assertNotNull(f != null);
58 assertTrue(f instanceof Element);
59 assertEquals("root", ((Element)f).getName());
60 for (int i = 0; i < fellowship.length; i++) {
61 assertTrue(it.hasNext());
62 assertEquals(fellowship[i], ((Element)it.next()).getName());
63 }
64 assertFalse(it.hasNext());
65 try {
66 assertTrue(null != it.next().toString());
67 fail("Should not be able to iterate off the end of the descendants.");
68 } catch (NoSuchElementException nse) {
69 // good
70 } catch (Exception e) {
71 fail("Expected NoSuchElementException, but got " + e.getClass().getName());
72 }
73
74 }
75
76 @Test
77 public void testIterable() {
78 int i = 0;
79 for (Content c : buildIterator()) {
80 assertNotNull(c != null);
81 assertTrue(c instanceof Element);
82 Element e = (Element)c;
83 if (i == 0) {
84 assertEquals("root", e.getName());
85 } else {
86 assertEquals(fellowship[i - 1], e.getName());
87 }
88 i++;
89 }
90 }
91
92 @Test
93 public void testRemoveOne() {
94 Iterator<Content> it = buildIterator();
95 assertTrue(it.hasNext());
96 Object f = it.next();
97 assertNotNull(f != null);
98 assertTrue(f instanceof Element);
99 assertEquals("root", ((Element)f).getName());
100
101 // this should remove the root element, which effectively should
102 // make the descendant iterator empty.
103 it.remove();
104
105
106 assertFalse(it.hasNext());
107 try {
108 assertTrue(null != it.next().toString());
109 fail("Should not be able to iterate off the end of the descendants.");
110 } catch (NoSuchElementException nse) {
111 // good
112 } catch (Exception e) {
113 fail("Expected NoSuchElementException, but got " + e.getClass().getName());
114 }
115
116 }
117
118
119 @Test
120 public void testRemoves() {
121 for (int i = fellowship.length - 1; i >= 0; i--) {
122 checkRemove(i);
123 }
124 }
125
126 private void checkIterator(final Iterator<Content> it, final String...values) {
127 for (int i = 0; i < values.length; i++) {
128 assertTrue(it.hasNext());
129 assertEquals(values[i], ((Element)it.next()).getName());
130 }
131 assertFalse(it.hasNext());
132 try {
133 assertTrue(null != it.next().toString());
134 fail("Should not be able to iterate off the end of the descendants.");
135 } catch (NoSuchElementException nse) {
136 // good
137 } catch (Exception e) {
138 fail("Expected NoSuchElementException, but got " + e.getClass().getName());
139 }
140 }
141
142 private void checkRemove(final int remove) {
143 Element doc = buildTestDoc();
144 checkIterator(doc.getDescendants(), fellowship);
145 Iterator<Content> it1 = doc.getDescendants();
146 it1.next();
147 for (int i = 0; i < remove; i++) {
148 it1.next();
149 }
150 it1.remove();
151 try {
152 it1.remove();
153 fail ("Should not be able to double-remove");
154 } catch (Exception e) {
155 UnitTestUtil.checkException(IllegalStateException.class, e);
156 }
157 ArrayList<String> al = new ArrayList<String>();
158 Iterator<Content> it2 = doc.getDescendants();
159 int i = remove;
160 while (--i >= 0) {
161 it2.next();
162 }
163 while (it2.hasNext()) {
164 al.add(((Element)it2.next()).getName());
165 }
166 checkIterator(it1, al.toArray(new String[al.size()]));
167 }
168
169 @Test
170 public void testDeepNesting() {
171 ArrayList<String> names = new ArrayList<String>(64);
172 Element p = new Element("name");
173 names.add("name");
174 Document doc = new Document(p);
175 for (int i = 0; i < 64; i++) {
176 names.add("name" + i);
177 final Element e = new Element("name" + i);
178 p.getContent().add(e);
179 p = e;
180 }
181
182 checkIterator(doc.getDescendants(), names.toArray(new String[names.size()]));
183 }
184
185 @Test
186 public void testSpecialCaseRemove() {
187 // this is designed to test a special case:
188 // the iterator's next move was to go down next, but, we did a remove(),
189 // and now we can't go down next, but, there's no more siblings either,
190 // so our next move will be up, but the level up is no more siblings
191 // either, but some level above that has siblings, so we go there....
192 /*
193 * <root>
194 * <filler1>
195 * <toremove>
196 * <child />
197 * </toremove>
198 * </filler1>
199 * <postremove />
200 * </root>
201 */
202 Element root = new Element("root");
203 Element filler1 = new Element("filler");
204 root.addContent(filler1);
205
206 // right, this will be the thing we remove.
207 Element toremove = new Element("toremove");
208 filler1.addContent(toremove);
209
210 // but, this needs to have kids to go down to...
211 toremove.addContent(new Element("child"));
212
213
214 // this will be what next() returns after the remove.
215 Element postremove = new Element("postremove");
216 root.addContent(postremove);
217
218 Document doc = new Document(root);
219 Iterator<Content> it = doc.getDescendants();
220 while (it.hasNext()) {
221 Content c = it.next();
222 if (c == toremove) {
223 it.remove();
224 assertTrue(it.hasNext());
225 assertTrue(postremove == it.next());
226 }
227 }
228
229 }
230
231
232
233 }
0 package org.jdom.test.cases;
1
2 /*--
3
4 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact license@jdom.org.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management (pm@jdom.org).
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Brett McLaughlin <brett@jdom.org> and
51 Jason Hunter <jhunter@jdom.org>. For more information on the
52 JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 /**
57 * Please put a description of your test here.
58 *
59 * @author unascribed
60 * @version 0.1
61 */
62 import org.jdom.*;
63 import org.junit.Test;
64 import org.junit.runner.JUnitCore;
65 import static org.junit.Assert.*;
66
67 @SuppressWarnings("javadoc")
68 public final class TestDocType {
69 /**
70 * The main method runs all the tests in the text ui
71 */
72 public static void main (String args[])
73 {
74 JUnitCore.runClasses(TestDocType.class);
75 }
76
77
78 /**
79 * Test a simple DocType with a name.
80 */
81 @Test
82 public void test_TCC() {
83 DocType theDocType = new DocType() {
84 // change nothing
85 private static final long serialVersionUID = 200L;
86 };
87
88 assertNull("incorrect element name", theDocType.getElementName());
89 }
90
91 /**
92 * Test a simple DocType with a name.
93 */
94 @Test
95 public void test_TCC___String() {
96 DocType theDocType = new DocType("anElement");
97
98 assertEquals("incorrect element name", "anElement", theDocType.getElementName());
99 }
100
101 /**
102 * test both the setting of the element name and systemID.
103 */
104 @Test
105 public void test_TCC___String_String() {
106 String systemID = "FILE://temp/test.dtd";
107 DocType theDocType = new DocType("anElement", systemID);
108
109 assertEquals("incorrect element name", "anElement", theDocType.getElementName());
110 assertEquals("incorrect system ID", systemID, theDocType.getSystemID());
111 }
112
113 /**
114 * test with element name, public and systemIDs.
115 */
116 @Test
117 public void test_TCC___String_String_String() {
118 String publicID = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
119 String systemID = "FILE://temp/test.dtd";
120 DocType theDocType = new DocType("anElement", publicID, systemID);
121
122 assertEquals("incorrect element name", "anElement", theDocType.getElementName());
123 assertEquals("incorrect public ID", publicID, theDocType.getPublicID());
124 assertEquals("incorrect system ID", systemID, theDocType.getSystemID());
125
126 }
127
128 /**
129 * Do an object comparison with itself to confirm boolean equals works.
130 */
131 @Test
132 public void test_TCM__boolean_equals_Object() {
133 String publicID = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
134 String systemID = "FILE://temp/test.dtd";
135 DocType theDocType = new DocType("anElement", publicID, systemID);
136
137 Object ob = theDocType;
138 assertEquals(theDocType, ob);
139 }
140
141 /**
142 * look for a integer hashCode
143 */
144 @Test
145 public void test_TCM__int_hashCode() {
146 String publicID = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
147 String systemID = "FILE://temp/test.dtd";
148 DocType theDocType = new DocType("anElement", publicID, systemID);
149 assertTrue(theDocType.hashCode() == theDocType.hashCode());
150 // assuming no exception was thrown, an integer was created.
151 }
152
153 /**
154 * use toString to test the clone.
155 */
156 @Test
157 public void test_TCM__Object_clone() {
158 String publicID = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
159 String systemID = "FILE://temp/test.dtd";
160 DocType theDocType = new DocType("anElement", publicID, systemID);
161
162 DocType theDocType2 = theDocType.clone();
163
164 //assuming toString works as advertised....
165
166 assertEquals(theDocType.toString(), theDocType2.toString());
167 }
168
169 /**
170 * Test the setter for publicID.
171 */
172 @Test
173 public void test_TCM__OrgJdomDocType_setPublicID_String() {
174 String publicID = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
175
176 DocType theDocType = new DocType("anElement");
177
178 theDocType.setPublicID(publicID);
179
180 assertEquals(publicID, theDocType.getPublicID());
181 }
182
183 /**
184 * Test the setter for SystemID
185 */
186 @Test
187 public void test_TCM__OrgJdomDocType_setSystemID_String() {
188 String systemID = "FILE://temp/doodah.dtd";
189
190 DocType theDocType = new DocType("anElement");
191
192 theDocType.setSystemID(systemID);
193
194 assertEquals(systemID, theDocType.getSystemID());
195 }
196
197 /**
198 * Test getElementName.
199 */
200 @Test
201 public void test_TCM__String_getElementName() {
202 DocType theDocType = new DocType("anElement");
203
204 assertEquals("incorrect element name", "anElement", theDocType.getElementName());
205 }
206
207 /**
208 * Test that getPublicID matches the value from the constructor.
209 */
210 @Test
211 public void test_TCM__String_getPublicID() {
212 String publicID = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
213
214 DocType theDocType = new DocType("anElement", publicID, "");
215
216 assertEquals(publicID, theDocType.getPublicID());
217 assertTrue("".equals(theDocType.getValue()));
218 }
219
220 /**
221 * Test that getSerializedForm works as expected.
222 */
223 @Test
224 public void test_TCM__String_getSerializedForm() {
225 /** No op because the method is deprecated
226 String publicID = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
227 String systemID = "FILE://temp/test.dtd";
228 DocType theDocType = new DocType("anElement", publicID, systemID);
229
230 String result = theDocType.getSerializedForm();
231 String compareTo =
232 "<!DOCTYPE anElement PUBLIC \"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN\"" +
233 " \"FILE://temp/test.dtd\">";
234
235 assertEquals("incorrect serialized form", result, compareTo);
236 */
237 }
238
239 /**
240 * Test that getSystemID returns the same value as set in the constructor.
241 */
242 @Test
243 public void test_TCM__String_getSystemID() {
244 String systemID = "FILE://temp/doodah.dtd";
245 DocType theDocType = new DocType("anElement", systemID);
246
247 assertEquals(systemID, theDocType.getSystemID());
248 assertTrue("".equals(theDocType.getValue()));
249 }
250
251 /**
252 * Test toString returns the expected string.
253 */
254 @Test
255 public void test_TCM__String_toString() {
256 String publicID = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
257 String systemID = "FILE://temp/test.dtd";
258 DocType theDocType = new DocType("anElement", publicID, systemID);
259 String result = theDocType.toString();
260 String compareTo =
261 "[DocType: <!DOCTYPE anElement PUBLIC \"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN\"" +
262 " \"FILE://temp/test.dtd\">]";
263
264 assertEquals("incorrect toString form", compareTo, result);
265 assertTrue("".equals(theDocType.getValue()));
266 }
267
268 @Test (expected=IllegalNameException.class)
269 public void testIllegalNameA() {
270 new DocType("f0$0");
271 }
272
273 @Test (expected=IllegalNameException.class)
274 public void testIllegalNameB() {
275 new DocType("f0$0", "systemid");
276 }
277
278 @Test (expected=IllegalNameException.class)
279 public void testIllegalNameC() {
280 new DocType("f0$0", "publicid", "systemid");
281 }
282
283 @Test (expected=IllegalNameException.class)
284 public void testIllegalNameD() {
285 DocType dt = new DocType("foo", "publicid", "systemid");
286 dt.setElementName("f0$0");
287 }
288
289 @Test (expected=IllegalDataException.class)
290 public void testIllegalPublicA() {
291 new DocType("foo", "pub~id", null);
292 }
293
294 @Test (expected=IllegalDataException.class)
295 public void testIllegalPublicB() {
296 DocType dt = new DocType("foo", "pubid", null);
297 dt.setPublicID("pub~id");
298 }
299
300 @Test (expected=IllegalDataException.class)
301 public void testIllegalSystemA() {
302 char illegal = 0x0B;
303 new DocType("foo", "pubid", "sys" + illegal + "id");
304 }
305
306 @Test (expected=IllegalDataException.class)
307 public void testIllegalSystemB() {
308 DocType dt = new DocType("foo", "pubid", "sysid");
309 char illegal = 0x0B;
310 dt.setSystemID("sys" + illegal + "id");
311 }
312
313 @Test (expected=IllegalDataException.class)
314 public void testIllegalSystemC() {
315 DocType dt = new DocType("foo", "pubid", "sysid");
316 dt.setSystemID("sys'id \" with quote");
317 }
318
319 @Test
320 public void testCloneDetatchParentDocType() {
321 Document parent = new Document();
322 DocType content = new DocType("val");
323 parent.addContent(content);
324 DocType clone = content.detach().clone();
325 assertEquals(content.getValue(), clone.getValue());
326 assertNull(content.getParent());
327 assertNull(clone.getParent());
328 }
329
330 @Test
331 public void testContentCType() {
332 assertTrue(Content.CType.DocType == new DocType("root").getCType());
333 }
334 }
0 package org.jdom.test.cases;
1
2 /* Please run replic.pl on me ! */
3 /**
4 * Please put a description of your test here.
5 *
6 * @author unascribed
7 * @version 0.1
8 */
9 import org.jdom.*;
10 import org.junit.Test;
11 import org.junit.runner.JUnitCore;
12
13 import static org.junit.Assert.*;
14
15 import java.io.*;
16 import java.util.*;
17
18 import org.jdom.filter.ContentFilter;
19 import org.jdom.filter.ElementFilter;
20 import org.jdom.output.*;
21 import org.jdom.test.util.UnitTestUtil;
22
23 @SuppressWarnings("javadoc")
24 public final class TestDocument {
25
26 /**
27 * The main method runs all the tests in the text ui
28 */
29 public static void main (String args[])
30 {
31 JUnitCore.runClasses(TestDocument.class);
32 }
33
34 /**
35 * Test constructor of Document with a List of content including the root element.
36 */
37 @Test
38 public void test_TCC___List() {
39 Element bogus = new Element("bogus-root");
40 Element element = new Element("element");
41 Comment comment = new Comment("comment");
42 List<Content> list = new ArrayList<Content>();
43
44 list.add(element);
45 list.add(comment);
46 Document doc = new Document(list);
47 // Get a live list back
48 list = doc.getContent();
49 assertEquals("incorrect root element returned", element, doc.getRootElement());
50
51 //no root element
52 element.detach();
53 try {
54 doc.getRootElement();
55 fail("didn't catch missing root element");
56 } catch (IllegalStateException e) {
57 // Do nothing
58 } catch (Exception e) {
59 fail("Unexpected exception " + e.getClass());
60 }
61
62 //set root back, then try to add another element to our
63 //live list
64 doc.setRootElement(element);
65 try {
66 list.add(bogus);
67 fail("didn't catch duplicate root element");
68 } catch (IllegalAddException e) {
69 // Do nothing
70 } catch (Exception e) {
71 fail("Unexpected exception " + e.getClass());
72 }
73 assertEquals("incorrect root element returned", element, doc.getRootElement());
74
75 //how about replacing it in our live list
76 try {
77 Element oldRoot = doc.getRootElement();
78 int i = doc.indexOf(oldRoot);
79 list.set(i, bogus);
80 } catch (Exception e) {
81 fail("Root replacement shouldn't have throw a exception");
82 }
83 //and through the document
84 try {
85 doc.setRootElement(element);
86 } catch (Exception e) {
87 fail("Root replacement shouldn't have throw a exception");
88 }
89
90 list = null;
91 try {
92 doc = new Document(list);
93 } catch (IllegalAddException e) {
94 fail("didn't handle null list");
95 } catch (NullPointerException e) {
96 fail("didn't handle null list");
97 }
98
99 }
100
101 /**
102 * Test constructor of a Document with a List of content and a DocType.
103 */
104 @Test
105 public void test_TCC___List_OrgJdomDocType() {
106 Element bogus = new Element("bogus-root");
107 Element element = new Element("element");
108 Comment comment = new Comment("comment");
109 DocType docType = new DocType("element");
110 List<Content> list = new ArrayList<Content>();
111
112 list.add(docType);
113 list.add(element);
114 list.add(comment);
115 Document doc = new Document(list);
116 // Get a live list back
117 list = doc.getContent();
118 assertEquals("incorrect root element returned", element, doc.getRootElement());
119 assertEquals("incorrect doc type returned", docType, doc.getDocType());
120
121 element.detach();
122 try {
123 doc.getRootElement();
124 fail("didn't catch missing root element");
125 } catch (IllegalStateException e) {
126 // Do nothing
127 } catch (Exception e) {
128 fail("Unexpected exception " + e.getClass());
129 }
130
131 //set root back, then try to add another element to our
132 //live list
133 doc.setRootElement(element);
134 try {
135 list.add(bogus);
136 fail("didn't catch duplicate root element");
137 } catch (IllegalAddException e) {
138 // Do nothing
139 } catch (Exception e) {
140 fail("Unexpected exception " + e.getClass());
141 }
142 assertEquals("incorrect root element returned", element, doc.getRootElement());
143
144 //how about replacing it in our live list
145 try {
146 Element oldRoot = doc.getRootElement();
147 int i = doc.indexOf(oldRoot);
148 list.set(i,bogus);
149 } catch (Exception e) {
150 fail("Root replacement shouldn't have throw a exception");
151 }
152 //and through the document
153 try {
154 doc.setRootElement(element);
155 } catch (Exception e) {
156 fail("Root replacement shouldn't have throw a exception");
157 }
158
159 list = null;
160 try {
161 doc = new Document(list);
162 } catch (IllegalAddException e) {
163 fail("didn't handle null list");
164 } catch (NullPointerException e) {
165 fail("didn't handle null list");
166 }
167
168 }
169
170 /**
171 * Test the constructor with only a root element.
172 */
173 @Test
174 public void test_TCC___OrgJdomElement() {
175 Element element = new Element("element");
176
177 Document doc = new Document(element);
178 assertEquals("incorrect root element returned", element, doc.getRootElement());
179
180 element = null;
181 try {
182 doc = new Document(element);
183 } catch (IllegalAddException e) {
184 fail("didn't handle null element");
185 } catch (NullPointerException e) {
186 fail("didn't handle null element");
187 }
188
189 }
190
191 /**
192 * Test constructor of Document with and Element and Doctype
193 */
194 @Test
195 public void test_TCC___OrgJdomElement_OrgJdomDocType() {
196 Element element = new Element("element");
197 DocType docType = new DocType("element");
198
199 Document doc = new Document(element, docType);
200 assertEquals("incorrect root element returned", element, doc.getRootElement());
201 assertEquals("incorrect doc type returned", docType, doc.getDocType());
202
203 docType = new DocType("element");
204 element = null;
205 try {
206 doc = new Document(element, docType);
207 } catch (IllegalAddException e) {
208 fail("didn't handle null element");
209 } catch (NullPointerException e) {
210 fail("didn't handle null element");
211 }
212
213 }
214
215 /**
216 * Test constructor of Document with and Element and Doctype
217 */
218 @Test
219 public void test_TCC___OrgJdomElement_OrgJdomDocType_JavaLangString() {
220 Element element = new Element("element");
221 DocType docType = new DocType("element");
222 String baseuri = "BaseURI";
223
224 Document doc = new Document(element, docType, baseuri);
225 assertTrue(doc.hasRootElement());
226 assertEquals("incorrect root element returned", element, doc.getRootElement());
227 assertEquals("incorrect doc type returned", docType, doc.getDocType());
228 assertEquals("incorrect BaseURI returned", "BaseURI", doc.getBaseURI());
229
230 try {
231 element.detach();
232 docType.detach();
233 doc = new Document(null, docType, baseuri);
234 assertFalse(doc.hasRootElement());
235 assertEquals("incorrect doc type returned", docType, doc.getDocType());
236 assertEquals("incorrect BaseURI returned", "BaseURI", doc.getBaseURI());
237 try {
238 assertEquals("incorrect root element returned", null, doc.getRootElement());
239 fail ("Should not be ableto query the root element if it is not set...");
240 } catch (IllegalStateException ise) {
241 // OK, Root Element not set.
242 }
243 } catch (IllegalAddException e) {
244 fail("didn't handle null element");
245 } catch (NullPointerException e) {
246 fail("didn't handle null element");
247 }
248
249 try {
250 element.detach();
251 docType.detach();
252 doc = new Document(element, null, baseuri);
253 assertTrue(doc.hasRootElement());
254 assertEquals("incorrect root element returned", element, doc.getRootElement());
255 assertEquals("incorrect doc type returned", null, doc.getDocType());
256 assertEquals("incorrect BaseURI returned", "BaseURI", doc.getBaseURI());
257 } catch (IllegalAddException e) {
258 fail("didn't handle null docType");
259 } catch (NullPointerException e) {
260 fail("didn't handle null docType");
261 }
262
263 try {
264 element.detach();
265 docType.detach();
266 doc = new Document(element, docType, null);
267 assertTrue(doc.hasRootElement());
268 assertEquals("incorrect root element returned", element, doc.getRootElement());
269 assertEquals("incorrect doc type returned", docType, doc.getDocType());
270 assertEquals("incorrect BaseURI returned", null, doc.getBaseURI());
271 } catch (IllegalAddException e) {
272 fail("didn't handle null baseuri");
273 } catch (NullPointerException e) {
274 fail("didn't handle null baseuri");
275 }
276
277 try {
278 element.detach();
279 docType.detach();
280 doc = new Document(null, docType, null);
281 assertFalse(doc.hasRootElement());
282 try {
283 assertEquals("incorrect root element returned", null, doc.getRootElement());
284 fail ("Should not be ableto query the root element if it is not set...");
285 } catch (IllegalStateException ise) {
286 // OK, Root Element not set.
287 }
288 assertEquals("incorrect doc type returned", docType, doc.getDocType());
289 assertEquals("incorrect BaseURI returned", null, doc.getBaseURI());
290 } catch (IllegalAddException e) {
291 fail("didn't handle null element and baseuri");
292 } catch (NullPointerException e) {
293 fail("didn't handle null element and baseuri");
294 }
295
296 try {
297 element.detach();
298 docType.detach();
299 doc = new Document(null, null, null);
300 assertFalse(doc.hasRootElement());
301 try {
302 assertEquals("incorrect root element returned", null, doc.getRootElement());
303 fail ("Should not be ableto query the root element if it is not set...");
304 } catch (IllegalStateException ise) {
305 // OK, Root Element not set.
306 }
307 assertEquals("incorrect doc type returned", null, doc.getDocType());
308 assertEquals("incorrect BaseURI returned", null, doc.getBaseURI());
309 } catch (IllegalAddException e) {
310 fail("didn't handle null parameters");
311 } catch (NullPointerException e) {
312 fail("didn't handle null parameters");
313 }
314
315 }
316
317 /**
318 * Test object equality.
319 */
320 @Test
321 public void test_TCM__boolean_equals_Object() {
322 Element element = new Element("element");
323
324 Object doc = new Document(element);
325 assertEquals("invalid object equality", doc, doc);
326
327 }
328
329 /**
330 * Test removeContent for a given Comment
331 */
332 @Test
333 public void test_TCM__boolean_removeContent_OrgJdomComment() {
334 Element element = new Element("element");
335 Comment comment = new Comment("comment");
336 ArrayList<Content> list = new ArrayList<Content>();
337
338 list.add(element);
339 list.add(comment);
340 Document doc = new Document(list);
341 assertTrue("incorrect comment removed",! doc.removeContent(new Comment("hi")));
342 assertTrue("didn't remove comment", doc.removeContent(comment));
343
344 assertTrue("comment not removed", doc.getContent().size() == 1);
345 }
346
347 /**
348 * Test removeContent with the supplied ProcessingInstruction.
349 */
350 @Test
351 public void test_TCM__boolean_removeContent_OrgJdomProcessingInstruction() {
352 Element element = new Element("element");
353 ProcessingInstruction pi = new ProcessingInstruction("test", "comment");
354 ArrayList<Content> list = new ArrayList<Content>();
355
356 list.add(element);
357 list.add(pi);
358 Document doc = new Document(list);
359 assertTrue("incorrect pi removed",! doc.removeContent(new ProcessingInstruction("hi", "there")));
360 assertTrue("didn't remove pi", doc.removeContent(pi));
361
362 assertTrue("PI not removed", doc.getContent().size() == 1);
363
364 }
365
366 /**
367 * Test hashcode function.
368 */
369 @Test
370 public void test_TCM__int_hashCode() {
371 Element element = new Element("test");
372 Document doc = new Document(element);
373
374 //only an exception would be a problem
375 int i = -1;
376 try {
377 i = doc.hashCode();
378 }
379 catch(Exception e) {
380 fail("bad hashCode");
381 }
382
383
384 Element element2 = new Element("test");
385 Document doc2 = new Document(element2);
386 //different Documents, same text
387 int x = doc2.hashCode();
388 assertTrue("Different Elements with same value have same hashcode", x != i);
389
390 }
391
392 /**
393 * Test code goes here. Replace this comment.
394 */
395 @Test
396 public void test_TCM__Object_clone() {
397 //do the content tests to 2 levels deep to verify recursion
398 Element element = new Element("el");
399 Namespace ns = Namespace.getNamespace("urn:hogwarts");
400 element.setAttribute(new Attribute("name", "anElement"));
401 Element child1 = new Element("child", ns);
402 child1.setAttribute(new Attribute("name", "first"));
403
404 Element child2 = new Element("firstChild", ns);
405 child2.setAttribute(new Attribute("name", "second"));
406 Element child3 = new Element("child", Namespace.getNamespace("ftp://wombat.stew"));
407 child1.addContent(child2);
408 element.addContent(child1);
409 element.addContent(child3);
410
411 //add mixed content to the nested child2 element
412 Comment comment = new Comment("hi");
413 child2.addContent(comment);
414 CDATA cdata = new CDATA("gotcha");
415 child2.addContent(cdata);
416 ProcessingInstruction pi = new ProcessingInstruction("tester", "do=something");
417 child2.addContent(pi);
418 EntityRef entity = new EntityRef("wizards");
419 child2.addContent(entity);
420 child2.addContent("finally a new wand!");
421
422 //a little more for the element
423 element.addContent("top level element text");
424 Comment topComment = new Comment("some comment");
425
426 Document doc = new Document(element);
427 doc.addContent(topComment);
428 Document docClone = doc.clone();
429 element = null;
430 child3 = null;
431 child2 = null;
432 child1 = null;
433
434 List<Content> list = docClone.getRootElement().getContent();
435
436 //finally the test
437 assertEquals("wrong comment", ((Comment)docClone.getContent().get(1)).getText(), "some comment");
438 assertEquals("wrong child element", ((Element)list.get(0)).getName(), "child" );
439 assertEquals("wrong child element", ((Element)list.get(1)).getName(), "child" );
440 Element deepClone = ((Element)list.get(0)).getChild("firstChild", Namespace.getNamespace("urn:hogwarts"));
441
442 assertEquals("wrong nested element","firstChild", deepClone.getName());
443 //comment
444 assertTrue("deep clone comment not a clone", deepClone.getContent().get(0) != comment);
445 comment = null;
446 assertEquals("incorrect deep clone comment", "hi", ((Comment)deepClone.getContent().get(0)).getText());
447 //CDATA
448
449 assertEquals("incorrect deep clone CDATA", "gotcha", ((CDATA)deepClone.getContent().get(1)).getText());
450 //PI
451 assertTrue("deep clone PI not a clone", deepClone.getContent().get(2) != pi);
452 pi = null;
453 assertEquals("incorrect deep clone PI", "do=something",((ProcessingInstruction)deepClone.getContent().get(2)).getData());
454 //entity
455 assertTrue("deep clone Entity not a clone", deepClone.getContent().get(3) != entity);
456 entity = null;
457 assertEquals("incorrect deep clone Entity", "wizards", ((EntityRef)deepClone.getContent().get(3)).getName());
458 //text
459 assertEquals("incorrect deep clone test", "finally a new wand!", ((Text)deepClone.getContent().get(4)).getText());
460
461
462 }
463
464 /**
465 * Test getDocType.
466 */
467 @Test
468 public void test_TCM__OrgJdomDocType_getDocType() {
469 Element element = new Element("element");
470 DocType docType = new DocType("element");
471
472 Document doc = new Document(element, docType);
473 assertEquals("incorrect root element returned", element, doc.getRootElement());
474 assertEquals("incorrect doc type returned", docType, doc.getDocType());
475
476 }
477
478 /**
479 * Test the addition of comments to Documents.
480 */
481 @Test
482 public void test_TCM__OrgJdomDocument_addContent_OrgJdomComment() {
483 Element element = new Element("element");
484 Comment comment = new Comment("comment");
485 Comment comment2 = new Comment("comment 2");
486
487 Document doc = new Document(element);
488 doc.addContent(comment);
489 doc.addContent(comment2);
490 List<Content> content = doc.getContent();
491
492 assertEquals("wrong number of comments in List", 3, content.size());
493 assertEquals("wrong comment", comment, content.get(1));
494 assertEquals("wrong comment", comment2, content.get(2));
495 }
496
497 /**
498 * Test the addition of ProcessingInstructions to Documents.
499 */
500 @Test
501 public void test_TCM__OrgJdomDocument_addContent_OrgJdomProcessingInstruction() {
502 Element element = new Element("element");
503 ProcessingInstruction pi = new ProcessingInstruction("test", "comment");
504 ProcessingInstruction pi2 = new ProcessingInstruction("test", "comment 2");
505
506 Document doc = new Document(element);
507 doc.addContent(pi);
508 doc.addContent(pi2);
509 List<Content> content = doc.getContent();
510
511 assertEquals("wrong number of PI's in List", 3, content.size());
512 assertEquals("wrong PI", pi, content.get(1));
513 assertEquals("wrong PI", pi2, content.get(2));
514 }
515
516 /**
517 * Test that setRootElement works as expected.
518 */
519 @Test
520 public void test_TCM__OrgJdomDocument_setRootElement_OrgJdomElement() {
521 Element element = new Element("element");
522
523 Document doc1 = new Document(element);
524 assertEquals("incorrect root element returned", element, doc1.getRootElement());
525 Document doc2 = new Document();
526 try {
527 doc2.setRootElement(element);
528 fail("didn't catch element already attached to another document");
529 }
530 catch(IllegalAddException e) {
531 // Do nothing
532 } catch (Exception e) {
533 fail("Unexpected exception " + e.getClass());
534 }
535 }
536
537 /**
538 * Test that setDocType works as expected.
539 */
540 @Test
541 public void test_TCM__OrgJdomDocument_setDocType_OrgJdomDocType() {
542 Element element = new Element("element");
543 DocType docType = new DocType("element");
544
545 Document doc = new Document(element);
546 doc.setDocType(docType);
547 assertEquals("incorrect root element returned", element, doc.getRootElement());
548 assertEquals("incorrect doc type returned", docType, doc.getDocType());
549 }
550
551 /**
552 * Test that a Document can return a root element.
553 */
554 @Test
555 public void test_TCM__OrgJdomElement_getRootElement() {
556 Element element = new Element("element");
557
558 Document doc = new Document(element);
559 assertEquals("incorrect root element returned", element, doc.getRootElement());
560 }
561
562 /**
563 * Test that the toString method returns the expected result.
564 */
565 @Test
566 public void test_TCM__String_toString() {
567 Element element = new Element("element");
568 DocType docType = new DocType("element");
569
570 Document doc = new Document(element, docType);
571 String buf = new String("[Document: [DocType: <!DOCTYPE element>], Root is [Element: <element/>]]");
572 assertEquals("incorrect root element returned", buf, doc.toString());
573
574 }
575
576 /**
577 * Test that an Element properly handles default namespaces
578 */
579 @Test
580 public void test_TCU__testSerialization() throws IOException {
581
582 //set up an element to test with
583 Element element= new Element("element", Namespace.getNamespace("http://foo"));
584 Element child1 = new Element("child1");
585 Element child2 = new Element("child2");
586
587 element.addContent(child1);
588 element.addContent(child2);
589
590 Document doc = new Document(element);
591
592
593
594 //here is what we expect in these two scenarios
595 //String bufWithNoNS = "<element xmlns=\"http://foo\"><child1 /><child2 /></element>";
596
597 String bufWithEmptyNS = "<element xmlns=\"http://foo\"><child1 xmlns=\"\" /><child2 xmlns=\"\" /></element>";
598
599 Document docIn = UnitTestUtil.deSerialize(doc);
600 element = docIn.getRootElement();
601
602 StringWriter sw = new StringWriter();
603 XMLOutputter2 op= new XMLOutputter2(Format.getRawFormat());
604 op.output(element, sw);
605 assertTrue("Incorrect data after serialization", sw.toString().equals(bufWithEmptyNS));
606
607 }
608
609 /**
610 * Test getContent
611 */
612 @Test
613 public void test_TCM__List_getContent() {
614 Element element = new Element("element");
615 Comment comment = new Comment("comment");
616 ArrayList<Content> list = new ArrayList<Content>();
617
618 list.add(element);
619 list.add(comment);
620 Document doc = new Document(list);
621 assertEquals("missing mixed content", list, doc.getContent());
622 assertEquals("wrong number of elements", 2, doc.getContent().size());
623 }
624
625 /**
626 * Test that setContent works according to specs.
627 */
628 @Test
629 public void test_TCM__OrgJdomDocument_setContent_List() {
630 Element element = new Element("element");
631 Element newElement = new Element("newEl");
632 Comment comment = new Comment("comment");
633 ProcessingInstruction pi = new ProcessingInstruction("foo", "bar");
634 ArrayList<Content> list = new ArrayList<Content>();
635
636 list.add(newElement);
637 list.add(comment);
638 list.add(pi);
639
640
641 Document doc = new Document(element);
642 doc.setContent(list);
643 assertEquals("wrong number of elements", 3, doc.getContent().size());
644 assertEquals("missing element", newElement, doc.getContent().get(0));
645 assertEquals("missing comment", comment, doc.getContent().get(1));
646 assertEquals("missing pi", pi, doc.getContent().get(2));
647 }
648
649 @Test
650 public void testDocumentAddDocType() {
651 try {
652 Document doc = new Document();
653 doc.addContent(new Element("tag"));
654 List<Content> list = doc.getContent();
655 list.add(new DocType("elementname"));
656 fail ("Should not be able to add DocType to a document after an Element");
657 } catch (IllegalAddException iae) {
658 // good!
659 } catch (Exception e) {
660 fail ("We expect an IllegalAddException, but got " + e.getClass().getName());
661 }
662 }
663
664 @Test
665 public void testDocType() {
666 Document doc = new Document();
667 assertTrue(doc == doc.setDocType(null));
668 DocType dta = new DocType("DocTypeA");
669 DocType dtb = new DocType("DocTypeB");
670 doc.setDocType(dta);
671 assertTrue(doc.getDocType() == dta);
672 assertTrue(dta.getParent() == doc);
673 assertTrue(dtb.getParent() == null);
674 doc.setDocType(dtb);
675 assertTrue(doc.getDocType() == dtb);
676 assertTrue(dta.getParent() == null);
677 assertTrue(dtb.getParent() == doc);
678 try {
679 doc.setDocType(dtb);
680 fail("Should not be able to add an already attached DocType");
681 } catch (IllegalAddException iae) {
682 // good.
683 }
684 assertTrue(doc.getDocType() == dtb);
685 assertTrue(dta.getParent() == null);
686 assertTrue(dtb.getParent() == doc);
687 doc.setDocType(null);
688 assertTrue(doc.getDocType() == null);
689 assertTrue(dta.getParent() == null);
690 assertTrue(dtb.getParent() == null);
691
692 }
693
694 @Test
695 public void testDocumentProperties() {
696 Document doc = new Document();
697 assertTrue(doc.getProperty("one") == null);
698 doc.setProperty("one", "one1");
699 assertTrue("one1" == doc.getProperty("one"));
700 doc.setProperty("two", "two2");
701 assertTrue("one1" == doc.getProperty("one"));
702 assertTrue("two2" == doc.getProperty("two"));
703 }
704
705 @Test
706 public void testDocumentContent() {
707 Document doc = new Document();
708 assertTrue(doc.getContentSize() == 0);
709 assertTrue(doc.getDocType() == null);
710 assertFalse(doc.hasRootElement());
711 assertTrue(doc.cloneContent().size() == 0);
712
713 final DocType doctype = new DocType("element");
714 final Comment comment1 = new Comment("comment1");
715 final Comment comment2 = new Comment("comment2");
716 final Element root = new Element("root");
717
718 doc.setDocType(doctype);
719 assertTrue(doc.getContentSize() == 1);
720 assertTrue(doc.getDocType() == doctype);
721 assertFalse(doc.hasRootElement());
722 assertTrue(doc.cloneContent().size() == 1);
723 assertTrue(doc.cloneContent().get(0) instanceof DocType);
724 assertTrue(doc.indexOf(doctype) == 0);
725
726 assertTrue(doctype.getParent() == doc);
727 assertTrue(doc.removeContent().get(0) == doctype);
728
729 assertTrue(doctype.getParent() == null);
730 assertTrue(doc.getContentSize() == 0);
731 assertTrue(doc.getDocType() == null);
732 assertFalse(doc.hasRootElement());
733 assertTrue(doc.cloneContent().size() == 0);
734
735 doc.addContent(comment1);
736 doc.addContent(comment2);
737 assertTrue(comment1.getParent() == doc);
738 assertTrue(comment2.getParent() == doc);
739 assertTrue(doctype.getParent() == null);
740 assertTrue(doc.getContentSize() == 2);
741 doc.setContent(1, doctype);
742 assertTrue(comment1.getParent() == doc);
743 assertTrue(comment2.getParent() == null);
744 assertTrue(doctype.getParent() == doc);
745 assertTrue(doc.getContentSize() == 2);
746
747 doc.setContent(comment2);
748 assertTrue(comment1.getParent() == null);
749 assertTrue(comment2.getParent() == doc);
750 assertTrue(doctype.getParent() == null);
751 assertTrue(doc.getContentSize() == 1);
752 assertTrue(comment2 == doc.removeContent(0));
753
754 doc.addContent(Collections.singleton(comment2));
755 assertTrue(comment1.getParent() == null);
756 assertTrue(comment2.getParent() == doc);
757 assertTrue(doctype.getParent() == null);
758 assertTrue(doc.getContentSize() == 1);
759
760 doc.addContent(0, Collections.singleton(comment1));
761 assertTrue(comment1.getParent() == doc);
762 assertTrue(comment2.getParent() == doc);
763 assertTrue(doctype.getParent() == null);
764 assertTrue(doc.getContentSize() == 2);
765
766 doc.addContent(2, Collections.singleton(doctype));
767 assertTrue(comment1.getParent() == doc);
768 assertTrue(comment2.getParent() == doc);
769 assertTrue(doctype.getParent() == doc);
770 assertTrue(doc.getContentSize() == 3);
771 assertTrue(doc.indexOf(comment1) == 0);
772 assertTrue(doc.indexOf(comment2) == 1);
773 assertTrue(doc.indexOf(doctype) == 2);
774
775 doc.setContent(2, Collections.singleton(doctype));
776 assertTrue(comment1.getParent() == doc);
777 assertTrue(comment2.getParent() == doc);
778 assertTrue(doctype.getParent() == doc);
779 assertTrue(doc.getContentSize() == 3);
780 assertTrue(doc.indexOf(comment1) == 0);
781 assertTrue(doc.indexOf(comment2) == 1);
782 assertTrue(doc.indexOf(doctype) == 2);
783
784 Set<Content> empty = Collections.emptySet();
785 doc.setContent(2, empty);
786 assertTrue(comment1.getParent() == doc);
787 assertTrue(comment2.getParent() == doc);
788 assertTrue(doctype.getParent() == null);
789 assertTrue(doc.getContentSize() == 2);
790 assertTrue(doc.indexOf(comment1) == 0);
791 assertTrue(doc.indexOf(comment2) == 1);
792 assertTrue(doc.indexOf(doctype) == -1);
793
794 doc.addContent(2, doctype);
795 assertTrue(comment1.getParent() == doc);
796 assertTrue(comment2.getParent() == doc);
797 assertTrue(doctype.getParent() == doc);
798 assertTrue(doc.getContentSize() == 3);
799 assertTrue(doc.indexOf(comment1) == 0);
800 assertTrue(doc.indexOf(comment2) == 1);
801 assertTrue(doc.indexOf(doctype) == 2);
802
803 doc.addContent(root);
804 assertTrue(doc.indexOf(root) == 3);
805 assertTrue(doc.getContentSize() == 4);
806 assertTrue(doc.getRootElement() == root);
807 assertTrue(root.getParent() == doc);
808 assertTrue(doc.getContent().size() == 4);
809 assertTrue(doc.getContent(new ElementFilter()).size() == 1);
810 assertTrue(doc.getContent(new ContentFilter(ContentFilter.COMMENT)).size() == 2);
811 assertTrue(root == doc.detachRootElement());
812 assertTrue(null == doc.detachRootElement());
813
814 try {
815 doc.getContent();
816 fail("Should not be able to get content when there's no root element");
817 } catch (IllegalStateException ise) {
818 // good
819 } catch (Exception e) {
820 fail ("Expected IllegalStateException , not " + e.getClass().getName());
821 }
822
823 try {
824 doc.getContent(new ElementFilter());
825 fail("Should not be able to get content when there's no root element");
826 } catch (IllegalStateException ise) {
827 // good
828 } catch (Exception e) {
829 fail ("Expected IllegalStateException , not " + e.getClass().getName());
830 }
831
832 assertTrue(doc.removeContent(new ContentFilter(ContentFilter.COMMENT)).size() == 2);
833
834 // at this point, all the Document has is a doctype
835 assertTrue(doc.getContentSize() == 1);
836 assertTrue(doc.getDocType() == doctype);
837
838 // time for more broken content.
839 try {
840 doc.addContent(0, root);
841 fail("Should not be able to put root element before the doctype");
842 } catch (IllegalAddException ise) {
843 // good
844 } catch (Exception e) {
845 fail ("Expected IllegalAddException , not " + e.getClass().getName());
846 }
847
848 doc.addContent(1, root);
849 doc.setDocType(null);
850 try {
851 doc.addContent(1, doctype);
852 fail("Should not be able to put doctype after the root");
853 } catch (IllegalAddException ise) {
854 // good
855 } catch (Exception e) {
856 fail ("Expected IllegalAddException , not " + e.getClass().getName());
857 }
858
859 doc.setDocType(doctype);
860
861 try {
862 doc.addContent(doc.indexOf(doctype) + 1, new DocType("anotherdup"));
863 fail("Should not be able to add second doctype");
864 } catch (IllegalAddException ise) {
865 // good
866 } catch (Exception e) {
867 fail ("Expected IllegalAddException , not " + e.getClass().getName());
868 }
869
870 doc.addContent(1, comment1);
871
872 try {
873 doc.setContent(1, new DocType("anotherdup"));
874 fail("Should not be able to set second doctype");
875 } catch (IllegalAddException ise) {
876 // good
877 } catch (Exception e) {
878 fail ("Expected IllegalAddException , not " + e.getClass().getName());
879 }
880
881 try {
882 doc.setContent(1, new Element("anotherdup"));
883 fail("Should not be able to set second root element");
884 } catch (IllegalAddException ise) {
885 // good
886 } catch (Exception e) {
887 fail ("Expected IllegalAddException , not " + e.getClass().getName());
888 }
889
890 // but you should be able to replace the root element
891 assertTrue(doc == doc.setContent(doc.indexOf(root), new Element("root2")));
892 // and you should be able to replace the doctype
893 assertTrue(doc == doc.setContent(doc.indexOf(doctype), new DocType("doctype2")));
894 // and you should be able to set the root element if there's no other root element.
895 assertTrue(doc.removeContent(doc.getRootElement()));
896 assertTrue(doc == doc.setContent(doc.indexOf(comment1), root));
897
898
899 try {
900 doc.addContent(new EntityRef("myref"));
901 fail("Should not be able to add EntityRef");
902 } catch (IllegalAddException ise) {
903 // good
904 } catch (Exception e) {
905 fail ("Expected IllegalAddException , not " + e.getClass().getName());
906 }
907
908 try {
909 doc.addContent(new CDATA("mycdata"));
910 fail("Should not be able to add CDATA");
911 } catch (IllegalAddException ise) {
912 // good
913 } catch (Exception e) {
914 fail ("Expected IllegalAddException , not " + e.getClass().getName());
915 }
916
917 try {
918 doc.addContent(new Text("text"));
919 fail("Should not be able to add Text");
920 } catch (IllegalAddException ise) {
921 // good
922 } catch (Exception e) {
923 fail ("Expected IllegalAddException , not " + e.getClass().getName());
924 }
925
926
927
928 }
929
930 @Test
931 public void testClone() {
932 Document doc = new Document();
933 final DocType doctype = new DocType("element");
934 final Comment comment1 = new Comment("comment1");
935 final Comment comment2 = new Comment("comment2");
936 final ProcessingInstruction pi = new ProcessingInstruction("tstpi", "pidata");
937 final Element root = new Element("root");
938
939 doc.setDocType(doctype);
940 doc.addContent(comment1);
941 doc.addContent(comment2);
942 doc.addContent(pi);
943 doc.addContent(root);
944
945 Document clone = doc.clone();
946 assertTrue(doc.equals(doc));
947 assertTrue(clone.equals(clone));
948 assertFalse(clone.equals(doc));
949 assertFalse(doc.equals(clone));
950
951 assertTrue(doc.getContent().get(0) instanceof DocType);
952 assertTrue(doc.getContent().get(1) instanceof Comment);
953 assertTrue(doc.getContent().get(2) instanceof Comment);
954 assertTrue(doc.getContent().get(3) instanceof ProcessingInstruction);
955 assertTrue(doc.getContent().get(4) instanceof Element);
956
957
958 }
959
960 @Test
961 public void testParent() {
962 Document doc = new Document();
963 assertTrue(null == doc.getParent());
964 doc.addContent(new Element("root"));
965 assertTrue(null == doc.getParent());
966 }
967
968 @Test
969 public void testToString() {
970 Document doc = new Document();
971 assertTrue(doc.toString() != null);
972 assertTrue(doc.toString().indexOf("Document") >= 0);
973 assertTrue(doc.toString().indexOf("root") >= 0);
974
975 doc.addContent(new Comment("tstcomment"));
976 assertTrue(doc.toString().indexOf("tstcomment") < 0);
977 assertTrue(doc.toString().indexOf("root") >= 0);
978
979 doc.addContent(new DocType("tstdoctype"));
980 assertTrue(doc.toString().indexOf("Document") >= 0);
981 assertTrue(doc.toString().indexOf("tstcomment") < 0);
982 assertTrue(doc.toString().indexOf("tstdoctype") >= 0);
983 assertTrue(doc.toString().indexOf("root") >= 0);
984
985 doc.addContent(new Element("tstelement"));
986 assertTrue(doc.toString().indexOf("Document") >= 0);
987 assertTrue(doc.toString().indexOf("tstcomment") < 0);
988 assertTrue(doc.toString().indexOf("tstdoctype") >= 0);
989 assertTrue(doc.toString().indexOf("root") < 0);
990 assertTrue(doc.toString().indexOf("tstelement") >= 0);
991 }
992
993 @Test
994 public void testSPaceInProlog() throws IOException {
995 Document doc = new Document();
996
997 doc.addContent(new Text(" "));
998 assertTrue(doc.getContentSize() == 1);
999 doc.addContent(new Element("root"));
1000 assertTrue(doc.getContentSize() == 2);
1001 doc.addContent(new Text("\n"));
1002 assertTrue(doc.getContentSize() == 3);
1003 doc.addContent(new Comment("foo"));
1004 assertTrue(doc.getContentSize() == 4);
1005 doc.addContent(new Comment("bar"));
1006 assertTrue(doc.getContentSize() == 5);
1007
1008 try {
1009 doc.addContent(new Text("bad"));
1010 fail("Expected an add of non-space content to fail, but it did not");
1011 } catch (IllegalArgumentException e) {
1012 // good
1013 }
1014
1015 XMLOutputter2 out = new XMLOutputter2();
1016 out.getFormat().setLineSeparator(LineSeparator.NL);
1017 StringWriter sw = new StringWriter();
1018 out.output(doc, sw);
1019
1020 //System.out.println(sw.toString());
1021
1022 assertEquals("Space-in-prolog output", "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <root />\n<!--foo--><!--bar-->\n", sw.toString());
1023 }
1024
1025 // @Test
1026 // public void testDocumentAddAttribute() {
1027 // try {
1028 // List<Content> list = (new Document(new Element("root")).getContent());
1029 // list.add(new Attribute("att", "value"));
1030 // fail ("Should not be able to add Attribute to an Document's ContentList");
1031 // } catch (IllegalAddException iae) {
1032 // // good!
1033 // } catch (Exception e) {
1034 // fail ("We expect an IllegalAddException, but got " + e.getClass().getName());
1035 // }
1036 // }
1037
1038 }
0 package org.jdom.test.cases;
1
2 /*--
3
4 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact license@jdom.org.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management (pm@jdom.org).
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Brett McLaughlin <brett@jdom.org> and
51 Jason Hunter <jhunter@jdom.org>. For more information on the
52 JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 /**
57 * Please put a description of your test here.
58 *
59 * @author unascribed
60 * @version 0.1
61 */
62
63 import static org.jdom.test.util.UnitTestUtil.checkException;
64 import static org.jdom.test.util.UnitTestUtil.failNoException;
65 import static org.junit.Assert.assertEquals;
66 import static org.junit.Assert.assertFalse;
67 import static org.junit.Assert.assertNotNull;
68 import static org.junit.Assert.assertNull;
69 import static org.junit.Assert.assertTrue;
70 import static org.junit.Assert.fail;
71
72 import java.io.IOException;
73 import java.io.StringWriter;
74 import java.net.URI;
75 import java.net.URISyntaxException;
76 import java.util.ArrayList;
77 import java.util.Collection;
78 import java.util.Collections;
79 import java.util.Comparator;
80 import java.util.LinkedList;
81 import java.util.List;
82 import java.util.Set;
83
84 import org.jdom.filter.ContentFilter;
85 import org.jdom.filter.ElementFilter;
86 import org.jdom.filter.Filters;
87 import org.junit.Test;
88 import org.junit.runner.JUnitCore;
89
90 import org.jdom.Attribute;
91 import org.jdom.AttributeType;
92 import org.jdom.CDATA;
93 import org.jdom.Comment;
94 import org.jdom.Content;
95 import org.jdom.DocType;
96 import org.jdom.Document;
97 import org.jdom.Element;
98 import org.jdom.EntityRef;
99 import org.jdom.IllegalAddException;
100 import org.jdom.IllegalNameException;
101 import org.jdom.Namespace;
102 import org.jdom.ProcessingInstruction;
103 import org.jdom.Text;
104 import org.jdom.Content.CType;
105 import org.jdom.output.Format;
106 import org.jdom.output.XMLOutputter2;
107 import org.jdom.test.util.UnitTestUtil;
108
109 @SuppressWarnings("javadoc")
110 public final class TestElement {
111
112 /**
113 * The main method runs all the tests in the text ui
114 */
115 public static void main(String args[]) {
116 JUnitCore.runClasses(TestElement.class);
117 }
118
119 /**
120 * Test the constructor for a subclass element
121 */
122 @Test
123 public void test_TCC() {
124 Element emt = new Element() {
125 // change nothing
126 private static final long serialVersionUID = 200L;
127 };
128 assertNull(emt.getName());
129 }
130
131 /**
132 * Test the constructor for an empty element
133 */
134 @Test
135 public void test_TCC___String() {
136
137 //create a new empty element
138 Element el = new Element("theElement");
139 assertTrue("wrong element name after constructor", el.getName().equals("theElement"));
140 assertTrue("expected NO_NAMESPACE", el.getNamespace().equals(Namespace.NO_NAMESPACE));
141 assertTrue("expected no child elements", el.getChildren().equals(Collections.EMPTY_LIST));
142 assertTrue("expected no attributes", el.getAttributes().equals(Collections.EMPTY_LIST));
143
144 //must have a name
145 try {
146 el = new Element("");
147 fail("allowed creation of an element with no name");
148 }
149 catch (IllegalNameException e) {
150 // Do nothing
151 } catch (Exception e) {
152 fail("Unexpected exception " + e.getClass());
153 }
154
155 //name can't be null
156 try {
157 el = new Element(null);
158 fail("allowed creation of an element with null name");
159 }
160 catch (IllegalNameException e) {
161 // Do nothing
162 } catch (Exception e) {
163 fail("Unexpected exception " + e.getClass());
164 }
165
166 //we can assume the Verifier has been called by now so we are done
167 }
168
169 /**
170 * Test the Element constructor with an name and namespace
171 */
172 @Test
173 public void test_TCC___String_OrgJdomNamespace() {
174 //create a new empty element with a namespace
175
176 Namespace ns = Namespace.getNamespace("urn:foo");
177 Element el = new Element("theElement", ns);
178 assertTrue("wrong element name after constructor", el.getName().equals("theElement"));
179 assertTrue("expected urn:foo namespace", el.getNamespace().equals(Namespace.getNamespace("urn:foo")));
180 assertTrue("expected no child elements", el.getChildren().equals(Collections.EMPTY_LIST));
181 assertTrue("expected no attributes", el.getAttributes().equals(Collections.EMPTY_LIST));
182
183 //must have a name
184 try {
185 el = new Element("", ns);
186 fail("allowed creation of an element with no name");
187 }
188 catch (IllegalNameException e) {
189 // Do nothing
190 } catch (Exception e) {
191 fail("Unexpected exception " + e.getClass());
192 }
193
194 //name can't be null
195 try {
196 el = new Element(null, ns);
197 fail("allowed creation of an element with null name");
198 }
199 catch (IllegalNameException e) {
200 // Do nothing
201 } catch (Exception e) {
202 fail("Unexpected exception " + e.getClass());
203 }
204
205 //we can assume the Verifier has been called by now so we are done
206 }
207
208 /**
209 * Test the Element constructor with a string default namespace
210 */
211 @Test
212 public void test_TCC___String_String() {
213 //create a new empty element with a namespace
214
215 Element el = new Element("theElement", "urn:foo");
216 assertTrue("wrong element name after constructor", el.getName().equals("theElement"));
217 assertTrue("expected urn:foo namespace", el.getNamespace().equals(Namespace.getNamespace("urn:foo")));
218 assertTrue("expected no child elements", el.getChildren().equals(Collections.EMPTY_LIST));
219 assertTrue("expected no attributes", el.getAttributes().equals(Collections.EMPTY_LIST));
220
221 //must have a name
222 try {
223 el = new Element("", "urn:foo");
224 fail("allowed creation of an element with no name");
225 }
226 catch (IllegalNameException e) {
227 // Do nothing
228 } catch (Exception e) {
229 fail("Unexpected exception " + e.getClass());
230 }
231
232 //name can't be null
233 try {
234 el = new Element(null, "urn:foo");
235 fail("allowed creation of an element with null name");
236 }
237 catch (IllegalNameException e) {
238 // Do nothing
239 } catch (Exception e) {
240 fail("Unexpected exception " + e.getClass());
241 }
242
243 //we can assume the Verifier has been called by now so we are done
244 }
245
246 /**
247 * Test the Element constructor with a namespace uri and prefix
248 */
249 @Test
250 public void test_TCC___String_String_String() {
251 //create a new empty element with a namespace
252
253
254 Element el = new Element("theElement", "x", "urn:foo");
255 assertTrue("wrong element name after constructor", el.getName().equals("theElement"));
256 assertTrue("expected urn:foo namespace", el.getNamespace().equals(Namespace.getNamespace("x", "urn:foo")));
257 assertTrue("expected no child elements", el.getChildren().equals(Collections.EMPTY_LIST));
258 assertTrue("expected no attributes", el.getAttributes().equals(Collections.EMPTY_LIST));
259
260 //must have a name
261 try {
262 el = new Element("", "x", "urn:foo");
263 fail("allowed creation of an element with no name");
264 }
265 catch (IllegalNameException e) {
266 // Do nothing
267 } catch (Exception e) {
268 fail("Unexpected exception " + e.getClass());
269 }
270
271 //name can't be null
272 try {
273 el = new Element(null, "x", "urn:foo");
274 fail("allowed creation of an element with null name");
275 }
276 catch (IllegalNameException e) {
277 // Do nothing
278 } catch (Exception e) {
279 fail("Unexpected exception " + e.getClass());
280 }
281
282 //we can assume the Verifier has been called by now so we are done
283
284 }
285
286 /**
287 * Test the equals compares only object instances
288 */
289 @Test
290 public void test_TCM__boolean_equals_Object() {
291 Element el = new Element("theElement", "x", "urn:foo");
292 Element el2 = new Element("theElement", "x", "urn:foo");
293
294 assertTrue("incorrect equals evaluation", ((Object) el).equals(el));
295 assertTrue("incorrect equals evaluation", !((Object) el2).equals(el));
296 }
297
298 /**
299 * Test that hasChildren only reports true for actual child elements.
300 */
301 /*
302 public void test_TCM__boolean_hasChildren() {
303 //set up an element to test with
304 Element element = new Element("element", Namespace.getNamespace("http://foo"));
305 assertTrue("reported children when there are none", !element.hasChildren());
306
307 Attribute att1 = new Attribute("anAttribute", "boo");
308 element.setAttribute(att1);
309 assertTrue("reported children when there are none", !element.hasChildren());
310
311 //add some text
312 element.addContent("the text");
313 assertTrue("reported children when there are none", !element.hasChildren());
314
315 //add some CDATA
316 element.addContent(new CDATA("the text"));
317 assertTrue("reported children when there are none", !element.hasChildren());
318
319 //add a PI
320 element.addContent(new ProcessingInstruction("pi", "the text"));
321 assertTrue("reported children when there are none", !element.hasChildren());
322
323 //add Comment
324 element.addContent(new Comment("the text"));
325 assertTrue("reported children when there are none", !element.hasChildren());
326
327 //finally a child element
328 Element child1 = new Element("child1");
329 element.addContent(child1);
330 assertTrue("reported no children when there is a child element", element.hasChildren());
331 }
332 */
333
334 /**
335 * Test that hasMixedContent works for varying types of possible
336 * child and other content
337 */
338 @Test
339 public void test_TCM__boolean_hasMixedContent() {
340 /** No op because the method is deprecated
341
342 //set up an element to test with
343 Element element= new Element("element", Namespace.getNamespace("http://foo"));
344 assertTrue("reported mixed content when there is none", ! element.hasMixedContent());
345
346
347 Attribute att1 = new Attribute("anAttribute", "boo");
348 element.setAttribute(att1);
349 assertTrue("reported mixed content when there is none", ! element.hasMixedContent());
350
351 //add some text
352 element.addContent("the text");
353 assertTrue("reported mixed content when there is none", ! element.hasMixedContent());
354
355 //add some CDATA
356 element.addContent(new CDATA("the text"));
357 assertTrue("reported no mixed content when there is", element.hasMixedContent());
358
359 element= new Element("element");
360 //add a PI
361 element.addContent(new ProcessingInstruction("pi", "the text"));
362 assertTrue("reported mixed content when there is none", ! element.hasMixedContent());
363
364 //add Comment
365 element.addContent(new Comment("the text"));
366 assertTrue("reported no mixed content when there is", element.hasMixedContent());
367
368 element= new Element("element");
369 //finally a child element
370 Element child1= new Element("child1");
371 element.addContent(child1);
372 assertTrue("reported mixed content when there is none", ! element.hasMixedContent());
373
374 element.addContent("some text");
375 assertTrue("reported no mixed content when there is", element.hasMixedContent());
376
377 */
378 }
379
380 /**
381 * Test that an Element can determine if it is a root element
382 */
383 @Test
384 public void test_TCM__boolean_isRootElement() {
385 Element element = new Element("element");
386 assertTrue("incorrectly identified element as root", !element.isRootElement());
387
388 new Document(element);
389 assertTrue("incorrectly identified element as non root", element.isRootElement());
390 }
391
392 /**
393 * Test than an Element can remove an Attribute by name
394 */
395 @Test
396 public void test_TCM__boolean_removeAttribute_String() {
397 Element element = new Element("test");
398 assertFalse(element.removeAttribute("att"));
399 Attribute att = new Attribute("anAttribute", "test");
400 element.setAttribute(att);
401
402 //make sure it's there
403 assertNotNull("attribute not found after add", element.getAttribute("anAttribute"));
404
405 //and remove it
406 assertTrue("attribute not removed", element.removeAttribute("anAttribute"));
407 //make sure it's not there
408 assertNull("attribute found after remove", element.getAttribute("anAttribute"));
409 assertFalse("non-existing attribute remove returned true", element.removeAttribute("anAttribute"));
410 }
411
412 /**
413 * Test than an Element can remove an Attribute by name
414 */
415 @Test
416 public void test_TCM__boolean_removeAttribute_Attribute() {
417 Element element = new Element("test");
418 Attribute att = new Attribute("anAttribute", "test");
419 assertFalse(element.removeAttribute(att));
420
421 element.setAttribute(att);
422
423 //make sure it's there
424 assertNotNull("attribute not found after add", element.getAttribute("anAttribute"));
425
426 //and remove it
427 assertTrue("attribute not removed", element.removeAttribute(att));
428 //make sure it's not there
429 assertNull("attribute found after remove", element.getAttribute("anAttribute"));
430 assertFalse("non-existing attribute remove returned true", element.removeAttribute(att));
431 }
432
433 /**
434 * Test removeAttribute with a namespace
435 */
436 @Test
437 public void test_TCM__boolean_removeAttribute_String_OrgJdomNamespace() {
438 Element element = new Element("test");
439 Namespace ns = Namespace.getNamespace("x", "urn:test");
440 assertFalse(element.removeAttribute("anAttribute", ns));
441
442 Attribute att = new Attribute("anAttribute", "test", ns);
443 element.setAttribute(att);
444
445 //make sure it's there
446 assertNotNull("attribute not found after add", element.getAttribute("anAttribute", ns));
447 //make sure we check namespaces - a different namespace
448 assertFalse("wrong attribute removed", element.removeAttribute("anAttribute", Namespace.NO_NAMESPACE));
449 //and remove it
450 assertTrue("attribute not removed", element.removeAttribute("anAttribute", ns));
451 //make sure it's not there
452 assertNull("attribute found after remove", element.getAttribute("anAttribute", ns));
453 }
454
455 /**
456 * Test removeAtttribute with a namespace uri.
457 */
458 @Test
459 public void test_TCM__boolean_removeAttribute_String_String() {
460 /** No op because the method is deprecated
461
462 Element element = new Element("test");
463 Namespace ns = Namespace.getNamespace("x", "urn:test");
464 Attribute att = new Attribute("anAttribute", "test", ns);
465 element.setAttribute(att);
466
467 //make sure it's there
468 assertNotNull("attribute not found after add", element.getAttribute("anAttribute", ns));
469 //and remove it
470 assertTrue("attribute not removed", element.removeAttribute("anAttribute", "urn:test"));
471 //make sure it's not there
472 assertNull("attribute found after remove", element.getAttribute("anAttribute", ns));
473 */
474 }
475
476 /**
477 * Test removeChild by name
478 */
479 @Test
480 public void test_TCM__boolean_removeChild_String() {
481 Element element = new Element("element");
482 Element child = new Element("child");
483 element.addContent(child);
484
485 assertTrue("couldn't remove child content", element.removeChild("child"));
486 assertNull("child not removed", element.getChild("child"));
487 }
488
489 /**
490 * Test removeChild by name and namespace
491 */
492 @Test
493 public void test_TCM__boolean_removeChild_String_OrgJdomNamespace() {
494 Namespace ns = Namespace.getNamespace("x", "urn:fudge");
495 Element element = new Element("element");
496 Element child = new Element("child", ns);
497 Element child2 = new Element("child", ns);
498 element.addContent(child);
499
500 assertTrue("couldn't remove child content", element.removeChild("child", ns));
501 assertNull("child not removed", element.getChild("child", ns));
502 //now test that only the first child is removed
503 element.addContent(child);
504 element.addContent(child2);
505 assertTrue("couldn't remove child content", element.removeChild("child", ns));
506 assertNotNull("child not removed", element.getChild("child", ns));
507
508 }
509
510 /**
511 * Test removeChildren which removes all child elements
512 */
513 /*
514 public void test_TCM__boolean_removeChildren() {
515 Namespace ns = Namespace.getNamespace("x", "urn:fudge");
516 Element element = new Element("element");
517
518 assertTrue("incorrectly returned true when deleting no content", element.removeChildren() == false);
519
520 Element child = new Element("child", ns);
521 Element child2 = new Element("child", ns);
522 element.addContent(child);
523 element.addContent(child2);
524
525 assertTrue("couldn't remove child content", element.removeChildren());
526 assertNull("child not removed", element.getContent("child", ns));
527 }
528 */
529
530 /**
531 * Test removeChildren by name.
532 */
533 /*
534 public void test_TCM__boolean_removeChildren_String() {
535 Element element = new Element("element");
536
537 assertTrue("incorrectly returned true when deleting no content", element.removeChildren() == false);
538
539 Element child = new Element("child");
540 Element child2 = new Element("child");
541 element.addContent(child);
542 element.addContent(child2);
543
544 assertTrue("incorrect return on bogus child", !element.removeChildren("test"));
545 assertNotNull("child incorrectly removed", element.getContent("child"));
546 assertTrue("couldn't remove child content", element.removeChildren("child"));
547 assertNull("children not removed", element.getContent("child"));
548 }
549 */
550
551 /**
552 * Test removeChildren with a name and namespace
553 */
554 /*
555 public void test_TCM__boolean_removeChildren_String_OrgJdomNamespace() {
556 Namespace ns = Namespace.getNamespace("x", "urn:fudge");
557 Element element = new Element("element");
558
559 assertTrue("incorrectly returned true when deleting no content", element.removeChildren() == false);
560
561 Element child = new Element("child", ns);
562 Element child2 = new Element("child", ns);
563 element.addContent(child);
564 element.addContent(child2);
565
566 assertTrue("incorrect return on bogus child", !element.removeChildren("child"));
567 assertNotNull("child incorrectly removed", element.getContent("child", ns));
568 assertTrue("couldn't remove child content", element.removeChildren("child", ns));
569 assertNull("children not removed", element.getContent("child", ns));
570 }
571 */
572
573 /**
574 * Test removeContent for a Comment
575 */
576 @Test
577 public void test_TCM__boolean_removeContent_OrgJdomComment() {
578 Element element = new Element("element");
579 Comment comm = new Comment("a comment");
580 element.addContent(comm);
581
582 assertTrue("couldn't remove comment content", element.removeContent(comm));
583 assertTrue("didn't remove comment content", element.getContent().equals(Collections.EMPTY_LIST));
584 }
585
586 /**
587 * Test removeContent for an Element.
588 */
589 @Test
590 public void test_TCM__boolean_removeContent_OrgJdomElement() {
591 Element element = new Element("element");
592 Element child = new Element("child");
593 element.addContent(child);
594
595 assertTrue("couldn't remove element content", element.removeContent(child));
596 assertTrue("didn't remove element content", element.getContent().equals(Collections.EMPTY_LIST));
597 }
598
599 /**
600 * Test removeContent for entities.
601 */
602 @Test
603 public void test_TCM__boolean_removeContent_OrgJdomEntity() {
604 Element element = new Element("element");
605 EntityRef ent = new EntityRef("anEntity");
606 element.addContent(ent);
607
608 assertTrue("couldn't remove entity content", element.removeContent(ent));
609 assertTrue("didn't remove entity content", element.getContent().equals(Collections.EMPTY_LIST));
610 }
611
612 /**
613 * Test removeContent for processing instructions.
614 */
615 @Test
616 public void test_TCM__boolean_removeContent_OrgJdomProcessingInstruction() {
617 Element element = new Element("element");
618 ProcessingInstruction pi = new ProcessingInstruction("aPi", "something");
619 element.addContent(pi);
620
621 assertTrue("couldn't remove entity content", element.removeContent(pi));
622 assertTrue("didn't remove entity content", element.getContent().equals(Collections.EMPTY_LIST));
623 }
624
625 /**
626 * Test hashcode functions.
627 */
628 @Test
629 public void test_TCM__int_hashCode() {
630 Element element = new Element("test");
631 //only an exception would be a problem
632 int i = -1;
633 try {
634 i = element.hashCode();
635 }
636 catch(Exception e) {
637 fail("bad hashCode");
638 }
639
640
641 Element element2 = new Element("test");
642 //different Elements, same text
643 int x = element2.hashCode();
644 assertTrue("Different Elements with same value have same hashcode", x != i);
645 Element element3 = new Element("test2");
646 //only an exception would be a problem
647 int y = element3.hashCode();
648 assertTrue("Different Elements have same hashcode", y != x);
649
650 }
651
652 /**
653 * Test that additionalNamespaces are returned.
654 */
655 @Test
656 public void test_TCM__List_getAdditionalNamespaces() {
657 Element element = new Element("element");
658 element.addNamespaceDeclaration(Namespace.getNamespace("x", "urn:foo"));
659 element.addNamespaceDeclaration(Namespace.getNamespace("y", "urn:bar"));
660 element.addNamespaceDeclaration(Namespace.getNamespace("z", "urn:baz"));
661
662 List<Namespace> list = element.getAdditionalNamespaces();
663
664 Namespace ns = list.get(0);
665 assertTrue("didn't return added namespace", ns.getURI().equals("urn:foo"));
666 ns = list.get(1);
667 assertTrue("didn't return added namespace", ns.getURI().equals("urn:bar"));
668 ns = list.get(2);
669 assertTrue("didn't return added namespace", ns.getURI().equals("urn:baz"));
670 }
671
672 /**
673 * Test that getAttribute returns all attributes of this element.
674 */
675 @Test
676 public void test_TCM__List_getAttributes() {
677 Element element = new Element("test");
678 Attribute att = new Attribute("anAttribute", "test");
679 Attribute att2 = new Attribute("anotherAttribute", "test");
680 Attribute att3 = new Attribute("anotherAttribute", "test", Namespace.getNamespace("x", "urn:JDOM"));
681 element.setAttribute(att);
682 element.setAttribute(att2);
683 element.setAttribute(att3);
684
685 List<Attribute> list = element.getAttributes();
686
687 assertEquals("incorrect size returned", list.size(), 3);
688 assertEquals("incorrect attribute returned", list.get(0), att);
689 assertEquals("incorrect attribute returned", list.get(1), att2);
690 }
691
692 /**
693 * Test getChildren to return all children from all namespaces.
694 */
695 @Test
696 public void test_TCM__List_getChildren() {
697 Element element = new Element("el");
698 assertEquals("did not return Collections.EMPTY_LIST on empty element", Collections.EMPTY_LIST, element.getChildren("child"));
699 Element child1 = new Element("child");
700 child1.setAttribute(new Attribute("name", "first"));
701
702 Element child2 = new Element("child");
703 child2.setAttribute(new Attribute("name", "second"));
704 Element child3 = new Element("child", Namespace.getNamespace("ftp://wombat.stew"));
705
706 element.addContent(child1);
707 element.addContent(child2);
708 element.addContent(child3);
709
710 //should only get the child elements in NO_NAMESPACE
711 List<Element> list = element.getChildren();
712 assertEquals("incorrect number of children returned", list.size(), 3);
713 assertEquals("incorrect child returned", list.get(0), child1);
714 assertEquals("incorrect child returned", list.get(1), child2);
715 assertEquals("incorrect child returned", list.get(2), child3);
716 }
717
718 /**
719 * Test that Element returns a List of children by name
720 */
721 @Test
722 public void test_TCM__List_getChildren_String() {
723 Element element = new Element("el");
724 assertEquals("did not return Collections.EMPTY_LIST on empty element", Collections.EMPTY_LIST, element.getChildren("child"));
725 Element child1 = new Element("child");
726 child1.setAttribute(new Attribute("name", "first"));
727
728 Element child2 = new Element("child");
729 child2.setAttribute(new Attribute("name", "second"));
730 Element child3 = new Element("child", Namespace.getNamespace("ftp://wombat.stew"));
731
732 element.addContent(child1);
733 element.addContent(child2);
734 element.addContent(child3);
735
736 //should only get the child elements in NO_NAMESPACE
737 List<Element> list = element.getChildren("child");
738 assertEquals("incorrect number of children returned", list.size(), 2);
739 assertEquals("incorrect child returned", list.get(0).getAttribute("name").getValue(), "first");
740 assertEquals("incorrect child returned", list.get(1).getAttribute("name").getValue(), "second");
741 }
742
743 /**
744 * Test that Element returns a List of children by name and namespace
745 */
746 @Test
747 public void test_TCM__List_getChildren_String_OrgJdomNamespace() {
748 Element element = new Element("el");
749 assertEquals("did not return Collections.EMPTY_LIST on empty element", Collections.EMPTY_LIST, element.getChildren("child"));
750 Namespace ns = Namespace.getNamespace("urn:hogwarts");
751 Element child1 = new Element("child", ns);
752 child1.setAttribute(new Attribute("name", "first"));
753
754 Element child2 = new Element("child", ns);
755 child2.setAttribute(new Attribute("name", "second"));
756 Element child3 = new Element("child", Namespace.getNamespace("ftp://wombat.stew"));
757
758 element.addContent(child1);
759 element.addContent(child2);
760 element.addContent(child3);
761
762 //should only get the child elements in the hogwarts namespace
763 List<Element> list = element.getChildren("child", ns);
764 assertEquals("incorrect number of children returned", list.size(), 2);
765 assertEquals("incorrect child returned", list.get(0).getAttribute("name").getValue(), "first");
766 assertEquals("incorrect child returned", list.get(1).getAttribute("name").getValue(), "second");
767 }
768
769 /**
770 * Test that getContent returns all the content for the element
771 */
772 @Test
773 public void test_TCM__List_getContent() {
774 Element element = new Element("el");
775 assertEquals("did not return Collections.EMPTY_LIST on empty element", Collections.EMPTY_LIST, element.getContent());
776 Namespace ns = Namespace.getNamespace("urn:hogwarts");
777 Element child1 = new Element("child", ns);
778 child1.setAttribute(new Attribute("name", "first"));
779
780 Element child2 = new Element("child", ns);
781 child2.setAttribute(new Attribute("name", "second"));
782 Element child3 = new Element("child", Namespace.getNamespace("ftp://wombat.stew"));
783
784 element.addContent(child1);
785 element.addContent(child2);
786 element.addContent(child3);
787
788 Comment comment = new Comment("hi");
789 element.addContent(comment);
790 CDATA cdata = new CDATA("gotcha");
791 element.addContent(cdata);
792 ProcessingInstruction pi = new ProcessingInstruction("tester", "do=something");
793 element.addContent(pi);
794 EntityRef entity = new EntityRef("wizards");
795 element.addContent(entity);
796 Text text = new Text("finally a new wand!");
797 element.addContent(text);
798
799 List<Content> list = element.getContent();
800
801 assertEquals("incorrect number of content items", 8, list.size());
802 assertEquals("wrong child element", child1, list.get(0));
803 assertEquals("wrong child element", child2, list.get(1));
804 assertEquals("wrong child element", child3, list.get(2));
805 assertEquals("wrong comment", comment, list.get(3));
806 assertEquals("wrong CDATA", cdata, list.get(4));
807 assertEquals("wrong ProcessingInstruction", pi, list.get(5));
808 assertEquals("wrong EntityRef", entity, list.get(6));
809 assertEquals("wrong text", text, list.get(7));
810 }
811
812 /**
813 * Test that clone returns a disconnected copy of the original element.
814 * Since clone is a deep copy, that must be tested also
815 */
816 @Test
817 public void test_TCM__Object_clone() {
818
819 //first the simple case
820 Element element = new Element("simple");
821 Element clone = element.clone();
822
823 assertTrue("clone should not be the same object", element != clone);
824 assertEquals("clone should not have a parent", null, clone.getParent());
825 assertEquals("names do not match", element.getName(), clone.getName());
826
827 //now do the content tests to 2 levels deep to verify recursion
828 element = new Element("el");
829 Namespace ns = Namespace.getNamespace("urn:hogwarts");
830 element.setAttribute(new Attribute("name", "anElement"));
831 Element child1 = new Element("child", ns);
832 child1.setAttribute(new Attribute("name", "first"));
833
834 Element child2 = new Element("firstChild", ns);
835 child2.setAttribute(new Attribute("name", "second"));
836 Element child3 = new Element("child", Namespace.getNamespace("ftp://wombat.stew"));
837 child1.addContent(child2);
838 element.addContent(child1);
839 element.addContent(child3);
840
841 element.addNamespaceDeclaration(Namespace.getNamespace("foo", "http://test1"));
842 element.addNamespaceDeclaration(Namespace.getNamespace("bar", "http://test2"));
843
844 //add mixed content to the nested child2 element
845 Comment comment = new Comment("hi");
846 child2.addContent(comment);
847 CDATA cdata = new CDATA("gotcha");
848 child2.addContent(cdata);
849 ProcessingInstruction pi = new ProcessingInstruction("tester", "do=something");
850 child2.addContent(pi);
851 EntityRef entity = new EntityRef("wizards");
852 child2.addContent(entity);
853 child2.addContent("finally a new wand!");
854
855 //a little more for the element
856 element.addContent("top level element text");
857
858 clone = element.clone();
859 element = null;
860 child3 = null;
861 child2 = null;
862 child1 = null;
863
864 // additional namespaces
865 List<Namespace> additional = clone.getAdditionalNamespaces();
866 assertEquals("incorrect deep clone additional namespace",
867 additional.get(0),
868 Namespace.getNamespace("foo", "http://test1"));
869 assertEquals("incorrect deep clone additional namespace",
870 additional.get(1),
871 Namespace.getNamespace("bar", "http://test2"));
872
873 List<Content> list = clone.getContent();
874
875 //finally the test
876
877 assertEquals("wrong child element", ((Element) list.get(0)).getName(), "child");
878 assertEquals("wrong child element", ((Element) list.get(1)).getName(), "child");
879 Element deepClone = ((Element) list.get(0)).getChild("firstChild", Namespace.getNamespace("urn:hogwarts"));
880
881 assertEquals("wrong nested element", "firstChild", deepClone.getName());
882 //comment
883 assertTrue("deep clone comment not a clone", deepClone.getContent().get(0) != comment);
884 comment = null;
885 assertEquals("incorrect deep clone comment", "hi", ((Comment) deepClone.getContent().get(0)).getText());
886 //CDATA
887 assertTrue("deep clone CDATA not a clone", ((CDATA) deepClone.getContent().get(1)).getText().equals(cdata.getText()));
888 cdata = null;
889 assertEquals("incorrect deep clone CDATA", "gotcha", ((CDATA) deepClone.getContent().get(1)).getText());
890 //PI
891 assertTrue("deep clone PI not a clone", deepClone.getContent().get(2) != pi);
892 pi = null;
893 assertEquals("incorrect deep clone PI", "do=something", ((ProcessingInstruction) deepClone.getContent().get(2)).getData());
894 //entity
895 assertTrue("deep clone Entity not a clone", deepClone.getContent().get(3) != entity);
896 entity = null;
897 assertEquals("incorrect deep clone EntityRef", "wizards", ((EntityRef) deepClone.getContent().get(3)).getName());
898 //text
899 assertEquals("incorrect deep clone test", "finally a new wand!", ((Text) deepClone.getContent().get(4)).getText());
900 }
901
902 /**
903 * Test getAttribute by name
904 */
905 @Test
906 public void test_TCM__OrgJdomAttribute_getAttribute_String() {
907 Element element = new Element("el");
908 Attribute att = new Attribute("name", "first");
909 element.setAttribute(att);
910 assertEquals("incorrect Attribute returned", element.getAttribute("name"), att);
911 }
912
913 /**
914 * Test getAttribute by name and namespace
915 */
916 @Test
917 public void test_TCM__OrgJdomAttribute_getAttribute_String_OrgJdomNamespace() {
918 Element element = new Element("el");
919 Namespace ns = Namespace.getNamespace("x", "urn:foo");
920 Attribute att = new Attribute("name", "first", ns);
921 element.setAttribute(att);
922 element.setAttribute(new Attribute("name", "first"));
923 assertEquals("incorrect Attribute returned", element.getAttribute("name", ns), att);
924
925 }
926
927 /**
928 * Test that an element returns the reference to it's enclosing document
929 */
930 @Test
931 public void test_TCM__OrgJdomDocument_getDocument() {
932 Element element = new Element("element");
933
934 assertNull("incorrectly returned document before there is one", element.getDocument());
935
936 Element child = new Element("child");
937 Element child2 = new Element("child");
938 element.addContent(child);
939 element.addContent(child2);
940
941 Document doc = new Document(element);
942
943 assertEquals("didn't return correct Document", element.getDocument(), doc);
944 assertEquals("didn't return correct Document", child.getDocument(), doc);
945 }
946
947 /**
948 * Test addContent for CDATA.
949 */
950 @Test
951 public void test_TCM__OrgJdomElement_addContent_OrgJdomCDATA() {
952 //positive test is covered in test__List_getContent()
953
954 //test with null
955 Element element = new Element("element");
956 CDATA cdata = null;
957 try {
958 element.addContent(cdata);
959 fail("didn't catch null CDATA element");
960 }
961 catch (NullPointerException e) {
962 // this is what List interface expects
963 }
964 catch (Exception e) {
965 fail("Expect NPE, not Exception " + e.getClass().getName()
966 + ": " + e.getMessage());
967 }
968 }
969
970 /**
971 * Test adding comment content.
972 */
973 @Test
974 public void test_TCM__OrgJdomElement_addContent_OrgJdomComment() {
975 Element element = new Element("element");
976 Comment comm = new Comment("a comment");
977 element.addContent(comm);
978
979 assertEquals("didn't add comment content", element.getContent().get(0), comm);
980 try {
981 comm = null;
982 element.addContent(comm);
983 fail("didn't catch null Comment");
984 }
985 catch (NullPointerException e) {
986 // OK
987 } catch (Exception e) {
988 fail("Unexpected exception " + e.getClass());
989 }
990 }
991
992 /**
993 * Test addContent for Element.
994 */
995 @Test
996 public void test_TCM__OrgJdomElement_addContent_OrgJdomElement() {
997 //positive test is covered in test__List_getContent()
998
999 //test with null
1000 Element element = new Element("element");
1001 try {
1002 Element el = null;
1003 element.addContent(el);
1004 fail("didn't catch null Element");
1005 }
1006 catch (NullPointerException e) {
1007 // OK
1008 } catch (Exception e) {
1009 fail("Unexpected exception " + e.getClass());
1010 }
1011 }
1012
1013 /**
1014 * Test addContent for Entity
1015 */
1016 @Test
1017 public void test_TCM__OrgJdomElement_addContent_OrgJdomEntityRef() {
1018 //positive test is covered in test__List_getContent()
1019
1020 //try with null
1021 Element element = new Element("element");
1022 try {
1023 EntityRef entity = null;
1024 element.addContent(entity);
1025 fail("didn't catch null EntityRef");
1026 }
1027 catch (NullPointerException e) {
1028 // Do nothing
1029 } catch (Exception e) {
1030 fail("Unexpected exception " + e.getClass());
1031 }
1032 }
1033
1034 /**
1035 * Test addContent for ProcessingInstruction.
1036 */
1037 @Test
1038 public void test_TCM__OrgJdomElement_addContent_OrgJdomProcessingInstruction() {
1039 //positive test is covered in test__List_getContent()
1040
1041 //try with null data
1042 Element element = new Element("element");
1043 try {
1044 ProcessingInstruction pi = null;
1045 element.addContent(pi);
1046 fail("didn't catch null ProcessingInstruction");
1047 }
1048 catch (NullPointerException e) {
1049 // Do nothing
1050 } catch (Exception e) {
1051 fail("Unexpected exception " + e.getClass());
1052 }
1053 }
1054
1055 /**
1056 * Test that string based content is added correctly to an Element.
1057 */
1058 @Test
1059 public void test_TCM__OrgJdomElement_addContent_String() {
1060 Element element = new Element("element");
1061 element.addContent("the first part");
1062 assertEquals("incorrect string value", "the first part", element.getText());
1063 element.addContent("the second part");
1064 assertEquals("incorrect string value", "the first partthe second part", element.getText());
1065 //make sure it still works with mixed content
1066 element.addContent(new Element("child"));
1067 element.addContent("the third part");
1068 assertEquals("incorrect string value", "the first partthe second partthe third part", element.getText());
1069
1070 // RolfL: I'v tried not to mess with the 'original' JUnit tests, but the
1071 // following comment does not match the code, or the tests.
1072 // vvvvvvvvvv
1073 //test that add content null clears the content
1074 // ^^^^^^^^^^
1075 // Adding a null String appears to have always had the effect of adding
1076 // a new 'empty' Text content...: new Text("")
1077 // I am updating this test to match the current reality.
1078 try {
1079 // we expect addContent(null) to add a new Empty Text element.
1080 // thus 'last' will be accurate after the add.
1081 int last = element.getContentSize();
1082
1083 String data = null;
1084 element.addContent(data);
1085
1086 // ensure there is a new content at 'last', and that it is an empty string.
1087 assertEquals("", element.getContent().get(last).getValue());
1088 }
1089 catch (IllegalAddException e) {
1090 fail("didn't handle null String content");
1091 }
1092 catch (NullPointerException e) {
1093 fail("didn't handle null String content");
1094 }
1095
1096 }
1097
1098 /**
1099 * Test getContent by child name.
1100 */
1101 @Test
1102 public void test_TCM__OrgJdomElement_getChild_String() {
1103 Element element = new Element("element");
1104 Element child = new Element("child");
1105 Element childNS = new Element("child", Namespace.getNamespace("urn:foo"));
1106 element.addContent(child);
1107 element.addContent(childNS);
1108 assertEquals("incorrect child returned", element.getChild("child"), child);
1109 }
1110
1111 /**
1112 * Test getContent by child name and namespace.
1113 */
1114 @Test
1115 public void test_TCM__OrgJdomElement_getChild_String_OrgJdomNamespace() {
1116 Element element = new Element("element");
1117 Element child = new Element("child");
1118 Namespace ns = Namespace.getNamespace("urn:foo");
1119 Element childNS = new Element("child", ns);
1120 element.addContent(child);
1121 element.addContent(childNS);
1122 assertEquals("incorrect child returned", element.getChild("child", ns), childNS);
1123 }
1124
1125 /**
1126 * Test getCopy with only the name argument. Since the copy is just a clone,
1127 * the clone test covers most of the testing.
1128 */
1129 @Test
1130 public void test_TCM__OrgJdomElement_getCopy_String() {
1131 /** No op because the method is deprecated
1132
1133 Element element = new Element("element", Namespace.getNamespace("urn:foo"));
1134 element.addContent("text");
1135
1136 Element newElement = element.getCopy("new");
1137 assertEquals("incorrect name", "new", newElement.getName());
1138 assertEquals("incorrect namespace", Namespace.NO_NAMESPACE, newElement.getNamespace());
1139 assertEquals("incorrect content", "text", newElement.getText());
1140 */
1141 }
1142
1143 /**
1144 * Test getCopy with the name and namespace arguments.
1145 * Since the copy is just a clone, the clone test
1146 * covers most of the testing.
1147 */
1148 @Test
1149 public void test_TCM__OrgJdomElement_getCopy_String_OrgJdomNamespace() {
1150 /** No op because the method is deprecated
1151
1152 Element element = new Element("element", Namespace.getNamespace("urn:foo"));
1153 element.addContent("text");
1154 Namespace ns = Namespace.getNamespace("urn:test:new");
1155 Element newElement = element.getCopy("new", ns);
1156 assertEquals("incorrect name", "new", newElement.getName());
1157 assertEquals("incorrect namespace", ns, newElement.getNamespace());
1158 assertEquals("incorrect content", "text", newElement.getText());
1159 */
1160 }
1161
1162 /**
1163 * Test test that a child element can return it's parent.
1164 */
1165 @Test
1166 public void test_TCM__OrgJdomElement_getParent() {
1167 Element element = new Element("el");
1168 Element child = new Element("child");
1169 element.addContent(child);
1170
1171 assertEquals("parent not found", element, child.getParent());
1172 }
1173
1174 /**
1175 * Test addAttribute with an Attribute
1176 */
1177 @Test
1178 public void test_TCM__OrgJdomElement_setAttribute_OrgJdomAttribute() {
1179 Element element = new Element("el");
1180 Attribute att = new Attribute("name", "first");
1181 element.setAttribute(att);
1182 assertEquals("incorrect Attribute returned", element.getAttribute("name"), att);
1183
1184 //update the value
1185 Attribute att2 = new Attribute("name", "replacefirst");
1186 element.setAttribute(att2);
1187 assertEquals("incorrect Attribute value returned", "replacefirst", element.getAttribute("name").getValue());
1188
1189 //test with bad data
1190 try {
1191 element.setAttribute(null);
1192 fail("didn't catch null attribute");
1193 }
1194 catch (NullPointerException e) {
1195 // Do nothing
1196 } catch (Exception e) {
1197 fail("Unexpected exception " + e.getClass());
1198 }
1199
1200 try {
1201 Element emt = new Element("dummy");
1202 Attribute ma = new Attribute("hi", "there");
1203 emt.setAttribute(ma);
1204 element.setAttribute(ma);
1205 fail("Should not be able to add already added Attribute.");
1206 } catch (IllegalAddException iae) {
1207 // good
1208 } catch (Exception e) {
1209 fail("Expect IllegalAddException, not " + e.getClass().getName());
1210 }
1211 }
1212
1213 /**
1214 * Test addAttribute with a supplied name and value
1215 */
1216 @Test
1217 public void test_TCM__OrgJdomElement_setAttribute_String_String__invalidCharacters() {
1218 final Element element = new Element("el");
1219
1220 //try with null name
1221 try {
1222 element.setAttribute(null, "value");
1223 fail("didn't catch null attribute name");
1224 }
1225 catch (NullPointerException ignore) {
1226 // Do nothing
1227 } catch (Exception e) {
1228 fail("Unexpected exception " + e.getClass());
1229 }
1230
1231 //try with null value
1232 try {
1233 element.setAttribute("name2", null);
1234 fail("didn't catch null attribute value");
1235 }
1236 catch (NullPointerException e) {
1237 // Do nothing
1238 } catch (Exception e) {
1239 fail("Unexpected exception " + e.getClass());
1240 }
1241
1242 //try with bad characters
1243 try {
1244 element.setAttribute("\n", "value");
1245 fail("didn't catch bad characters in attribute name");
1246 }
1247 catch (IllegalArgumentException e) {
1248 // Do nothing
1249 } catch (Exception e) {
1250 fail("Unexpected exception " + e.getClass());
1251 }
1252
1253 try {
1254 element.setAttribute("name2", "" + (char) 0x01);
1255 fail("didn't catch bad characters in attribute value");
1256 }
1257 catch (IllegalArgumentException e) {
1258 // Do nothing
1259 } catch (Exception e) {
1260 fail("Unexpected exception " + e.getClass());
1261 }
1262 }
1263
1264 /**
1265 * Test addAttribute with a supplied name and value
1266 */
1267 @Test
1268 public void test_setAttribute_String_String__attributeTypes() {
1269 helper_setAttribute_String_String__attributeType(Attribute.UNDECLARED_TYPE);
1270 helper_setAttribute_String_String__attributeType(Attribute.CDATA_TYPE);
1271 helper_setAttribute_String_String__attributeType(Attribute.ID_TYPE);
1272 helper_setAttribute_String_String__attributeType(Attribute.IDREF_TYPE);
1273 helper_setAttribute_String_String__attributeType(Attribute.IDREFS_TYPE);
1274 helper_setAttribute_String_String__attributeType(Attribute.ENTITY_TYPE);
1275 helper_setAttribute_String_String__attributeType(Attribute.ENTITIES_TYPE);
1276 helper_setAttribute_String_String__attributeType(Attribute.NMTOKEN_TYPE);
1277 helper_setAttribute_String_String__attributeType(Attribute.NMTOKENS_TYPE);
1278 helper_setAttribute_String_String__attributeType(Attribute.NOTATION_TYPE);
1279 helper_setAttribute_String_String__attributeType(Attribute.ENUMERATED_TYPE);
1280 }
1281
1282 /**
1283 * Test setAttribute with a supplied name and value
1284 */
1285 private void helper_setAttribute_String_String__attributeType(final AttributeType attributeType) {
1286 final Element element = new Element("el");
1287
1288 final String attributeName = "name";
1289 final String attributeValue = "value";
1290 final String attributeNewValue = "newValue";
1291
1292 final Attribute attribute = new Attribute(attributeName, attributeValue, attributeType);
1293
1294 // add attribute to element
1295 element.setAttribute(attribute);
1296
1297 final Attribute foundAttribute = element.getAttribute(attributeName);
1298 assertNotNull("no Attribute found", foundAttribute);
1299
1300 assertEquals("incorrect Attribute name returned", attributeName, foundAttribute.getName());
1301 assertEquals("incorrect Attribute value returned", attributeValue, foundAttribute.getValue());
1302 assertEquals("incorrect Attribute type returned", attributeType, foundAttribute.getAttributeType());
1303
1304 //update the value
1305 element.setAttribute(attributeName, attributeNewValue);
1306
1307 final Attribute changedAttribute = element.getAttribute(attributeName);
1308 assertNotNull("no Attribute found", changedAttribute);
1309
1310 assertEquals("incorrect Attribute name returned", attributeName, changedAttribute.getName());
1311 assertEquals("incorrect Attribute value returned", attributeNewValue, changedAttribute.getValue());
1312 assertEquals("incorrect Attribute type returned", attributeType, changedAttribute.getAttributeType());
1313 }
1314
1315 /**
1316 * Test addAttribute with a supplied name and value
1317 */
1318 @Test
1319 public void test_setAttribute_String_String_String__attributeTypes() {
1320 helper_setAttribute_String_String_String__attributeType(Attribute.UNDECLARED_TYPE);
1321 helper_setAttribute_String_String_String__attributeType(Attribute.CDATA_TYPE);
1322 helper_setAttribute_String_String_String__attributeType(Attribute.ID_TYPE);
1323 helper_setAttribute_String_String_String__attributeType(Attribute.IDREF_TYPE);
1324 helper_setAttribute_String_String_String__attributeType(Attribute.IDREFS_TYPE);
1325 helper_setAttribute_String_String_String__attributeType(Attribute.ENTITY_TYPE);
1326 helper_setAttribute_String_String_String__attributeType(Attribute.ENTITIES_TYPE);
1327 helper_setAttribute_String_String_String__attributeType(Attribute.NMTOKEN_TYPE);
1328 helper_setAttribute_String_String_String__attributeType(Attribute.NMTOKENS_TYPE);
1329 helper_setAttribute_String_String_String__attributeType(Attribute.NOTATION_TYPE);
1330 helper_setAttribute_String_String_String__attributeType(Attribute.ENUMERATED_TYPE);
1331 }
1332
1333 /**
1334 * Test setAttribute with a supplied name and value
1335 *
1336 * @author Victor Toni
1337 */
1338 private void helper_setAttribute_String_String_String__attributeType(final AttributeType attributeType) {
1339 try {
1340 final Namespace defaultNamespace = Namespace.getNamespace(null, "http://test.org/default");
1341 helper_setAttribute_String_String_String__attributeType(defaultNamespace, attributeType);
1342 fail("didn't catch empty prefix for attribute ");
1343 }
1344 catch( final IllegalNameException ignore) {
1345 // Do nothing
1346 } catch (Exception e) {
1347 fail("Unexpected exception " + e.getClass());
1348 }
1349
1350 final Namespace testNamespace = Namespace.getNamespace("test", "http://test.org/test");
1351 helper_setAttribute_String_String_String__attributeType(testNamespace, attributeType);
1352 }
1353
1354 /**
1355 * Test setAttribute with a supplied name, namespace and value
1356 *
1357 * @author Victor Toni
1358 */
1359 private void helper_setAttribute_String_String_String__attributeType(final Namespace namespace, final AttributeType attributeType) {
1360 final Element element = new Element("el");
1361
1362 final String attributeName = "name";
1363 final String attributeValue = "value";
1364 final String attributeNewValue = "newValue";
1365
1366 final Attribute attribute = new Attribute(attributeName, attributeValue, attributeType, namespace);
1367
1368 // add attribute to element
1369 element.setAttribute(attribute);
1370
1371 final Attribute foundAttribute = element.getAttribute(attributeName, namespace);
1372 assertNotNull("no Attribute found", foundAttribute);
1373
1374 assertEquals("incorrect Attribute name returned", attributeName, foundAttribute.getName());
1375 assertEquals("incorrect Attribute value returned", attributeValue, foundAttribute.getValue());
1376 assertEquals("incorrect Attribute type returned", attributeType, foundAttribute.getAttributeType());
1377
1378 //update the value
1379 element.setAttribute(attributeName, attributeNewValue, namespace);
1380
1381 final Attribute changedAttribute = element.getAttribute(attributeName, namespace);
1382 assertNotNull("no Attribute found", changedAttribute);
1383
1384 assertEquals("incorrect Attribute name returned", attributeName, changedAttribute.getName());
1385 assertEquals("incorrect Attribute value returned", attributeNewValue, changedAttribute.getValue());
1386 assertEquals("incorrect Attribute type returned", attributeType, changedAttribute.getAttributeType());
1387 }
1388
1389 /**
1390 * Test that attributes are added correctly as a list
1391 */
1392 @Test
1393 public void test_TCM__OrgJdomElement_setAttributes_List() {
1394 Element element = new Element("element");
1395 Attribute one = new Attribute("one", "value");
1396 Attribute two = new Attribute("two", "value");
1397 Attribute three = new Attribute("three", "value");
1398 ArrayList<Attribute> list = new ArrayList<Attribute>();
1399 list.add(one);
1400 list.add(two);
1401 list.add(three);
1402
1403 //put in an attribute that will get blown away later
1404 element.setAttribute(new Attribute("type", "test"));
1405 element.setAttributes(list);
1406 assertEquals("attribute not found", one, element.getAttribute("one"));
1407 assertEquals("attribute not found", two, element.getAttribute("two"));
1408 assertEquals("attribute not found", three, element.getAttribute("three"));
1409 assertNull("attribute should not have been found", element.getAttribute("type"));
1410
1411
1412 //now try to add something that isn't an attribute which should still add those
1413 //attributes added before the mistake.
1414 // Element bogus = new Element("bogus");
1415 // Attribute four = new Attribute("four", "value");
1416 //
1417 // ArrayList<Object> newList = new ArrayList<Object>();
1418 // newList.add(four);
1419 // newList.add(bogus);
1420 // try {
1421 // element.setAttributes(newList);
1422 // fail("didn't catch bad data in list");
1423 // }
1424 // catch (ClassCastException e) {
1425 // }
1426 //should be an atomic operation so the original state should be preserved
1427 assertEquals("wrong number of attributes after failed add", 3, element.getAttributes().size());
1428 assertEquals("attribute not found", one, element.getAttribute("one"));
1429 assertEquals("attribute not found", two, element.getAttribute("two"));
1430 assertEquals("attribute not found", three, element.getAttribute("three"));
1431
1432 try {
1433 element.setAttributes(null);
1434 List<?> attList = element.getAttributes();
1435 assertTrue("null didn't clear attributes", attList.size() == 0);
1436 }
1437 catch (IllegalArgumentException e) {
1438 fail("didn't handle null String content");
1439 }
1440 catch (NullPointerException e) {
1441 fail("didn't handle null String content");
1442 }
1443 }
1444
1445 /**
1446 * Test setting child elements in a list.
1447 */
1448 /*
1449 public void test_TCM__OrgJdomElement_setChildren_List() {
1450 Element element = new Element("el");
1451 assertEquals("did not return Collections.EMPTY_LIST on empty element", Collections.EMPTY_LIST, element.getChildren("child"));
1452 Element child1 = new Element("child");
1453 child1.setAttribute(new Attribute("name", "first"));
1454
1455 Element child2 = new Element("child");
1456 child2.setAttribute(new Attribute("name", "second"));
1457 Element child3 = new Element("child", Namespace.getNamespace("ftp://wombat.stew"));
1458
1459 ArrayList list = new ArrayList();
1460 list.add(child1);
1461 list.add(child2);
1462 list.add(child3);
1463
1464 element.setChildren(list);
1465
1466 //should only get the child elements in all namespaces
1467 List contentList = element.getChildren();
1468 assertEquals("incorrect number of children returned", 3, contentList.size());
1469 assertEquals("incorrect child returned", contentList.get(0), child1);
1470 assertEquals("incorrect child returned", contentList.get(1), child2);
1471 assertEquals("incorrect child returned", contentList.get(2), child3);
1472
1473 ArrayList newList = new ArrayList();
1474 newList.add(child1);
1475 newList.add(new Attribute("name", "bogus"));
1476
1477 try {
1478 element.setChildren(newList);
1479 fail("didn't catch a bad object in list");
1480 }
1481 catch (IllegalArgumentException e) {
1482 }
1483 //should be an atomic operation
1484 contentList = element.getChildren();
1485 assertEquals("wrong number of children after failed add", 3, contentList.size());
1486 assertEquals("incorrect child returned after failed add", contentList.get(0), child1);
1487 assertEquals("incorrect child returned after failed add", contentList.get(1), child2);
1488 assertEquals("incorrect child returned after failed add", contentList.get(2), child3);
1489
1490
1491 //nulls should reset the list
1492 element.setContent(null);
1493 assertTrue("didn't reset children List", element.getContent().isEmpty());
1494 }
1495 */
1496
1497 /**
1498 * Test adding mixed content in a List
1499 */
1500 @Test
1501 public void test_TCM__OrgJdomElement_setContent_List() {
1502 Element element = new Element("el");
1503 assertEquals("did not return Collections.EMPTY_LIST on empty element", Collections.EMPTY_LIST, element.getContent());
1504 Namespace ns = Namespace.getNamespace("urn:hogwarts");
1505 Element child1 = new Element("child", ns);
1506
1507 Element child2 = new Element("child", ns);
1508 Element child3 = new Element("child", Namespace.getNamespace("ftp://wombat.stew"));
1509
1510 LinkedList<Content> list = new LinkedList<Content>();
1511 list.add(child1);
1512 list.add(child2);
1513 list.add(child3);
1514
1515 Comment comment = new Comment("hi");
1516 list.add(comment);
1517 CDATA cdata = new CDATA("gotcha");
1518 list.add(cdata);
1519 ProcessingInstruction pi = new ProcessingInstruction("tester", "do=something");
1520 list.add(pi);
1521 EntityRef entity = new EntityRef("wizards");
1522 list.add(entity);
1523 Text text = new Text("finally a new wand!");
1524 list.add(text);
1525
1526 element.setContent(list);
1527 List<Content> contentList = element.getContent();
1528
1529 assertEquals("incorrect number of content items", 8, contentList.size());
1530 assertEquals("wrong child element", child1, contentList.get(0));
1531 assertEquals("wrong child element", child2, contentList.get(1));
1532 assertEquals("wrong child element", child3, contentList.get(2));
1533 assertEquals("wrong comment", comment, contentList.get(3));
1534 assertEquals("wrong CDATA", cdata, contentList.get(4));
1535 assertEquals("wrong ProcessingInstruction", pi, contentList.get(5));
1536 assertEquals("wrong EntityRef", entity, contentList.get(6));
1537 assertEquals("wrong text", text, contentList.get(7));
1538
1539 ArrayList<Content> newList = new ArrayList<Content>();
1540 //test adding a bad object type in the list
1541 newList.add(child1);
1542 addBrokenContent(newList, new Integer(7));
1543
1544 try {
1545 // this is a sensitive test.
1546 // The first member in the newList is already in the element, so,
1547 // normally adding it would cause anissue with the child already
1548 // having a parent, and thus an IllegalAddException, so, we could
1549 // expect that, but, setContent first detaches the previous content
1550 // so, in this case, the child element first gets detached, and then
1551 // re-added... so, the effect is that we get a ClassCastException
1552 // by adding the Integer...
1553 element.setContent(newList);
1554 failNoException(ClassCastException.class);
1555 } catch (Exception e) {
1556 checkException(ClassCastException.class, e);
1557 }
1558
1559 //should add no content... if setContent fails it should restore previous
1560 // content.
1561 contentList = element.getContent();
1562 assertEquals("wrong child element after failed add", child1, contentList.get(0));
1563 assertEquals("wrong child element after failed add", child2, contentList.get(1));
1564 assertEquals("wrong child element after failed add", child3, contentList.get(2));
1565 assertEquals("wrong comment after failed add", comment, contentList.get(3));
1566 assertEquals("wrong CDATA after failed add", cdata, contentList.get(4));
1567 assertEquals("wrong ProcessingInstruction after failed add", pi, contentList.get(5));
1568 assertEquals("wrong EntityRef after failed add", entity, contentList.get(6));
1569 assertEquals("wrong text after failed add", text, contentList.get(7));
1570
1571
1572 //nulls should reset the list
1573 element.removeContent();
1574 assertTrue("didn't reset mixed content List", element.getContent().isEmpty());
1575 assertNull(child1.getParent());
1576 assertNull(child2.getParent());
1577 assertNull(child3.getParent());
1578 assertNull(comment.getParent());
1579 assertNull(cdata.getParent());
1580 assertNull(pi.getParent());
1581 assertNull(entity.getParent());
1582 assertNull(text.getParent());
1583
1584 // test an empty list clears....
1585 newList.clear();
1586 assertTrue(element == element.setContent(newList));
1587 assertTrue(element.getContent().isEmpty());
1588 assertTrue(element == element.setContent(list));
1589 assertTrue(element.getContentSize() == list.size());
1590 // test a null list clears.
1591 newList = null;
1592 assertTrue(element == element.setContent(newList));
1593 assertTrue(element.getContent().isEmpty());
1594 assertTrue(element == element.setContent(list));
1595 assertTrue(element.getContentSize() == list.size());
1596
1597 // get a 1-sized list.
1598 for (int i = list.size() - 1; i >= 1; i--) {
1599 list.remove(i);
1600 }
1601 assertTrue(element == element.setContent(list));
1602 assertTrue(element.getContentSize() == 1);
1603 }
1604
1605 /**
1606 * Test setting the content of the Element with just a string
1607 * This should wipe out all other content the element has
1608 */
1609 @Test
1610 public void test_TCM__OrgJdomElement_setText_String() {
1611 Element element = new Element("el");
1612 Element child = new Element("child");
1613 element.addContent(child);
1614
1615 element.setText("it's all gone");
1616 assertEquals("incorrect text returned", "it's all gone", element.getText());
1617 assertEquals("incorrect number of content items found", 1, element.getContent().size());
1618
1619
1620 element.setText(null);
1621 assertTrue("didn't clear content with null text", element.getContent().isEmpty());
1622
1623 //bad string test
1624
1625 /** skip this test unless we determine that it is required
1626 to check textual content for validity. We have the means to do
1627 it in the validator but don't have it turned on right now for
1628 performance reasons where the parser has already checked this
1629 in the majority of cases.
1630
1631
1632 try {
1633 element.setText("test" + (char)0x01);
1634 fail("didn't catch text with invalid character");
1635 } catch (IllegalArgumentException e) {
1636 } catch (NullPointerException e) {
1637 fail("NullPointerException");
1638 }
1639
1640 */
1641 }
1642
1643 /**
1644 * Test that the Element returns it's primary namespace
1645 */
1646 @Test
1647 public void test_TCM__OrgJdomNamespace_getNamespace() {
1648 Namespace ns = Namespace.getNamespace("urn:test:foo");
1649 Element element = new Element("element", ns);
1650
1651 assertEquals("wrong namespace returned", ns, element.getNamespace());
1652 }
1653
1654 /**
1655 * Test that Element can return a namespace given a uri
1656 */
1657 @Test
1658 public void test_TCM__OrgJdomNamespace_getNamespace_String() {
1659 Namespace ns = Namespace.getNamespace("x", "urn:test:foo");
1660 Element element = new Element("element", ns);
1661
1662 assertEquals("wrong namespace returned", ns, element.getNamespace("x"));
1663 assertNull("no namespace should have been found", element.getNamespace("bogus"));
1664
1665 //now make sure it can return the namespace from the additional namespaces
1666 Namespace newNs = Namespace.getNamespace("y", "urn:test:new");
1667 element.addNamespaceDeclaration(newNs);
1668 assertEquals("wrong namespace returned", newNs, element.getNamespace("y"));
1669
1670 //now make sure the same thing works from a child
1671 Element child = new Element("child");
1672 element.addContent(child);
1673
1674 assertEquals("wrong namespace returned", ns, child.getNamespace("x"));
1675 assertNull("no namespace should have been found", child.getNamespace("bogus"));
1676 assertEquals("wrong namespace returned", newNs, child.getNamespace("y"));
1677
1678 //Now make sure we can pick up namespaces on attributes too that are not
1679 //explicitly added with addAdditionalNamespace()
1680 assertNull(child.getNamespace("attns"));
1681 child.setAttribute("att", "value", Namespace.getNamespace("attns", "atturi"));
1682 assertEquals("atturi", child.getNamespace("attns").getURI());
1683 child.setAttribute("att", "value", Namespace.getNamespace("attnt", "atturt"));
1684 assertEquals("atturt", child.getNamespace("attnt").getURI());
1685
1686 assertNull(element.getNamespace("attns"));
1687 }
1688
1689 /**
1690 * Test getAttributeValue by attribute name.
1691 */
1692 @Test
1693 public void test_TCM__String_getAttributeValue_String() {
1694 Element element = new Element("el");
1695 assertEquals("incorrect value returned", element.getAttributeValue("name"), null);
1696 element.setAttribute(new Attribute("name", "first"));
1697 assertEquals("incorrect value returned", element.getAttributeValue("name"), "first");
1698 }
1699
1700 /**
1701 * Test getAttributeValue by attribute name.
1702 */
1703 @Test
1704 public void test_TCM__String_getAttributeValue_String_String() {
1705 Element element = new Element("el");
1706 assertEquals("incorrect value returned", element.getAttributeValue("name", ""), "");
1707 element.setAttribute(new Attribute("name", "first"));
1708 assertEquals("incorrect value returned", element.getAttributeValue("name", ""), "first");
1709 assertEquals("incorrect value returned", element.getAttributeValue("namex", ""), "");
1710 }
1711
1712 /**
1713 * Test getAttributeValue with name and namespace
1714 */
1715 @Test
1716 public void test_TCM__String_getAttributeValue_String_OrgJdomNamespace() {
1717 Element element = new Element("el");
1718 assertEquals("incorrect value returned", element.getAttributeValue("name", Namespace.getNamespace("x", "urn:WombatsRUS")), null);
1719 element.setAttribute(new Attribute("name", "first", Namespace.getNamespace("x", "urn:WombatsRUS")));
1720 assertEquals("incorrect value returned", element.getAttributeValue("name", Namespace.getNamespace("x", "urn:WombatsRUS")), "first");
1721 assertEquals("incorrect value returned", element.getAttributeValue("name", Namespace.getNamespace("y", "urn:WombatsRUS2")), null);
1722 }
1723
1724 /**
1725 * Test getAttributeValue with name and namespace
1726 */
1727 @Test
1728 public void test_TCM__String_getAttributeValue_String_OrgJdomNamespace_String() {
1729 Element element = new Element("el");
1730 assertEquals("incorrect value returned", element.getAttributeValue("name", Namespace.getNamespace("x", "urn:WombatsRUS"), ""), "");
1731 element.setAttribute(new Attribute("name", "first", Namespace.getNamespace("x", "urn:WombatsRUS")));
1732 assertEquals("incorrect value returned", element.getAttributeValue("name", Namespace.getNamespace("x", "urn:WombatsRUS"), ""), "first");
1733 assertEquals("incorrect value returned", element.getAttributeValue("name", Namespace.getNamespace("y", "urn:WombatsRUS2"), "x"), "x");
1734 }
1735
1736 /**
1737 * Test the convience method for retrieving child text.
1738 */
1739 @Test
1740 public void test_TCM__String_getChildText_String() {
1741 Element element = new Element("element");
1742 Element child = new Element("child");
1743 child.addContent(" some text \nboo ");
1744 element.addContent(child);
1745
1746 assertEquals("incorrect text returned", " some text \nboo ", element.getChildText("child"));
1747 }
1748
1749 /**
1750 * Test the convience method for retrieving child text for a child
1751 * retrieved by name and namespace
1752 */
1753 @Test
1754 public void test_TCM__String_getChildText_String_OrgJdomNamespace() {
1755 Element element = new Element("element");
1756 Namespace ns = Namespace.getNamespace("urn:test:foo");
1757 Element child = new Element("child", ns);
1758 child.addContent(" some text \nboo ");
1759 element.addContent(child);
1760
1761 assertEquals("incorrect text returned", " some text \nboo ", element.getChildText("child", ns));
1762
1763 }
1764
1765 /**
1766 * Test the convience method for retrieving trimmed child text.
1767 */
1768 @Test
1769 public void test_TCM__String_getChildTextTrim_String() {
1770 Element element = new Element("element");
1771 Element child = new Element("child");
1772 child.addContent(" some text \n ");
1773 element.addContent(child);
1774
1775 assertEquals("incorrect text returned", "some text", element.getChildTextTrim("child"));
1776 }
1777
1778 /**
1779 * Test the convience method for retrieving trimmed child text for the
1780 * child in the given namespace
1781 */
1782 @Test
1783 public void test_TCM__String_getChildTextTrim_String_OrgJdomNamespace() {
1784 Element element = new Element("element");
1785 Namespace ns = Namespace.getNamespace("urn:test:foo");
1786 Element child = new Element("child", ns);
1787 child.addContent(" some text \n ");
1788 element.addContent(child);
1789
1790 assertEquals("incorrect text returned", "some text", element.getChildTextTrim("child", ns));
1791 }
1792
1793 /**
1794 * Test getName.
1795 */
1796 @Test
1797 public void test_TCM__String_getName() {
1798 Element element = new Element("element", Namespace.getNamespace("x", "ftp://wombat.stew"));
1799 assertEquals("incorrect name", element.getName(), "element");
1800 }
1801
1802 /**
1803 * Test getNamespacePrefix.
1804 */
1805 @Test
1806 public void test_TCM__String_getNamespacePrefix() {
1807 Element element = new Element("element", Namespace.getNamespace("x", "ftp://wombat.stew"));
1808 assertEquals("incorrect namespace prefix", element.getNamespacePrefix(), "x");
1809 }
1810
1811 /**
1812 * Test code goes here. Replace this comment.
1813 */
1814 @Test
1815 public void test_TCM__String_getNamespaceURI() {
1816 Element element = new Element("element", Namespace.getNamespace("x", "ftp://wombat.stew"));
1817 assertEquals("incorrect uri", element.getNamespaceURI(), "ftp://wombat.stew");
1818 }
1819
1820 /**
1821 * Test that Element returns the correct qualified name.
1822 */
1823 @Test
1824 public void test_TCM__String_getQualifiedName() {
1825 Element element = new Element("element", Namespace.getNamespace("x", "ftp://wombat.stew"));
1826 assertEquals("incorrect qualified name", element.getQualifiedName(), "x:element");
1827 }
1828
1829 /**
1830 * Test getSerializedForm
1831 */
1832 @Test
1833 public void test_TCM__String_getSerializedForm() {
1834 // fail("method not implemented");
1835 }
1836
1837 /**
1838 * Test getText returns that full text of the element
1839 */
1840 @Test
1841 public void test_TCM__String_getText() {
1842 Element element = new Element("element");
1843 element.addContent(" some text \nboo ");
1844
1845 assertEquals("incorrect text returned", " some text \nboo ", element.getText());
1846 }
1847
1848 /**
1849 * Test getTextTrim.
1850 */
1851 @Test
1852 public void test_TCM__String_getTextTrim() {
1853 Element element = new Element("element");
1854 element.addContent(" some text \n ");
1855
1856 assertEquals("incorrect text returned", "some text", element.getTextTrim());
1857 }
1858
1859 /**
1860 * Test the toString method which should return a useful string
1861 * for debugging purposes only
1862 */
1863 @Test
1864 public void test_TCM__String_toString() {
1865 Element element = new Element("element", Namespace.getNamespace("urn:foo"));
1866 element.setAttribute(new Attribute("name", "aName"));
1867
1868 assertEquals("wrong toString text found", "[Element: <element [Namespace: urn:foo]/>]", element.toString());
1869 }
1870
1871 /**
1872 * Test addNamespaceDeclaration for prefix and uri.
1873 */
1874 @Test
1875 public void test_TCM__void_addNamespaceDeclaration_OrgJdomNamespace() {
1876 Element element = new Element("element");
1877 element.addNamespaceDeclaration(Namespace.getNamespace("x", "urn:foo"));
1878 List<Namespace> list = element.getAdditionalNamespaces();
1879
1880 Namespace ns = list.get(0);
1881 assertTrue("didn't return added namespace", ns.getURI().equals("urn:foo"));
1882 assertTrue("didn't return added namespace prefix", ns.getPrefix().equals("x"));
1883 }
1884
1885 /**
1886 * Test that attributes will be added and retrieved according
1887 * to specs. with namespaces and prefixes intact
1888 *
1889 */
1890 @Test
1891 public void test_TCU__testAttributeNamespaces() {
1892
1893 //set up an element and namespaces to test with
1894
1895 Element el = new Element("test");
1896 Namespace one = Namespace.getNamespace("test", "http://foo");
1897 Namespace two = Namespace.getNamespace("test2", "http://foo");
1898
1899 Attribute att = new Attribute("first", "first", one);
1900 Attribute att2 = new Attribute("first", "second", two);
1901
1902 //should overwrite attributes with same names even if prefixes are different
1903 try {
1904 el.setAttribute(att);
1905 el.setAttribute(att2);
1906 assertTrue("didn't catch duplicate setAttribute with different prefixes",
1907 el.getAttribute("first", one).getValue().equals("second"));
1908 assertTrue("didn't catch duplicate setAttribute with different prefixes",
1909 el.getAttribute("first", two).getNamespace().equals(two));
1910 }
1911 catch (IllegalAddException e) {
1912 // Do nothing
1913 } catch (Exception e) {
1914 fail("Unexpected exception " + e.getClass());
1915 }
1916
1917 //set up some unique namespaces for later tests
1918 Namespace testDefault = Namespace.getNamespace("http://bar");
1919 Namespace testNS = Namespace.getNamespace("test", "http://foo");
1920 Namespace testNS2 = Namespace.getNamespace("test2", "http://foo2");
1921
1922 //this should cause an error since the prefix will be discarded
1923 Namespace testNS3;
1924 try {
1925 testNS3 = Namespace.getNamespace("test", "");
1926 fail("didn't catch bad \"\" uri name");
1927 }
1928 catch (IllegalNameException e) {
1929 // Do nothing
1930 } catch (Exception e) {
1931 fail("Unexpected exception " + e.getClass());
1932 }
1933
1934 //show how you can have an empty namespace with the current scheme
1935 testNS3 = Namespace.getNamespace("");
1936
1937 el = new Element("test", testDefault);
1938 el.addNamespaceDeclaration(testNS2);
1939 try {
1940
1941 el.addNamespaceDeclaration(testNS3);
1942 }
1943 catch (IllegalAddException e) {
1944 // Do nothing
1945 } catch (Exception e) {
1946 fail("Unexpected exception " + e.getClass());
1947 }
1948
1949 att = new Attribute("prefixNS", "test");
1950
1951 //Test for default namespace check for attribute
1952 att2 = new Attribute("prefixNS", "empty namespace");
1953
1954
1955 //test prefixes with same name but different namespaces
1956 Attribute att3 = new Attribute("prefixNS", "test", testNS);
1957 Attribute att4 = new Attribute("prefixNS", "test2", testNS2);
1958 el.setAttribute(att2);
1959 el.setAttribute(att3);
1960 el.setAttribute(att4);
1961
1962 Attribute attback = el.getAttribute("prefixNS");
1963 assertTrue(
1964 "failed to get attribute from empty default namespace",
1965 attback.getNamespaceURI().equals(""));
1966 attback = el.getAttribute("prefixNS", testNS3);
1967 assertTrue(
1968 "failed to get attribute from http://bar namespace",
1969 attback.getNamespaceURI().equals(""));
1970 attback = el.getAttribute("prefixNS", testNS);
1971 assertTrue(
1972 "failed to get attribute from http://foo namespace",
1973 attback.getNamespaceURI().equals("http://foo"));
1974 attback = el.getAttribute("prefixNS", testNS2);
1975 assertTrue(
1976 "failed to get attribute from http://foo2 namespace",
1977 attback.getNamespaceURI().equals("http://foo2"));
1978 }
1979
1980 /**
1981 * Test that an Element properly handles default namespaces
1982 *
1983 */
1984 @Test
1985 public void test_TCU__testDefaultNamespaces() throws IOException {
1986
1987 //set up an element to test with
1988 Element element = new Element("element", Namespace.getNamespace("http://foo"));
1989 Element child1 = new Element("child1", Namespace.getNamespace("http://foo"));
1990 Element child2 = new Element("child2", Namespace.getNamespace("http://foo"));
1991
1992 element.addContent(child1);
1993 element.addContent(child2);
1994
1995 //here is what we expect in these two scenarios
1996 String bufWithNoNS = "<element xmlns=\"http://foo\"><child1 /><child2 /></element>";
1997
1998 String bufWithEmptyNS = "<element xmlns=\"http://foo\"><child1 xmlns=\"\" /><child2 xmlns=\"\" /></element>";
1999
2000 StringWriter sw = new StringWriter();
2001 XMLOutputter2 op = new XMLOutputter2();
2002 op.output(element, sw);
2003 assertEquals("Incorrect output for NO_NAMESPACE in a default namespace", bufWithNoNS, sw.toString());
2004
2005 //new try setting a new empty default namespace for children
2006 element = new Element("element", Namespace.getNamespace("http://foo"));
2007 child1 = new Element("child1");
2008 child2 = new Element("child2");
2009
2010 element.addContent(child1);
2011 element.addContent(child2);
2012 sw = new StringWriter();
2013 op = new XMLOutputter2();
2014 op.output(element, sw);
2015 assertTrue("Incorrect output for empty default namespace", sw.toString().equals(bufWithEmptyNS));
2016
2017
2018 //this code tests where multiple default namespaces disallowed
2019 try {
2020 Element el = new Element("test");
2021 el.addNamespaceDeclaration(Namespace.getNamespace("", "foo:bar"));
2022 el.addNamespaceDeclaration(Namespace.getNamespace("", "foo2:bar"));
2023 el.addNamespaceDeclaration(Namespace.NO_NAMESPACE);
2024 fail("didn't catch multiple default namespaces added to an element");
2025
2026 }
2027 catch (IllegalAddException e) {
2028 // Do nothing
2029 } catch (Exception e) {
2030 fail("Unexpected exception " + e.getClass());
2031 }
2032 }
2033
2034 /**
2035 * Test that Element serialization works, including with namespaces
2036 * @throws IOException
2037 *
2038 */
2039 @Test
2040 public void test_TCU__testSerialization() throws IOException {
2041
2042 //set up an element to test with
2043 Element element = new Element("element", Namespace.getNamespace("http://foo"));
2044 Element child1 = new Element("child1");
2045 child1.setAttribute(new Attribute("anAttribute", "no namespace"));
2046 Element child2 = new Element("child2");
2047 Attribute att1 = new Attribute("anAttribute", "with namespace", Namespace.getNamespace("x", "http://foo"));
2048 child2.setAttribute(att1);
2049 //add another child level deep
2050 Element descendent = new Element("descendent");
2051 child2.addContent(descendent);
2052 element.addContent(child1);
2053 element.addContent(child2);
2054
2055
2056
2057 //here is what we expect back after serialization
2058 String bufWithEmptyNS =
2059 "<element xmlns=\"http://foo\"><child1 xmlns=\"\" anAttribute=\"no namespace\" /><child2 xmlns=\"\" xmlns:x=\"http://foo\" x:anAttribute=\"with namespace\"><descendent /></child2></element>";
2060
2061 Element elIn = UnitTestUtil.deSerialize(element);
2062
2063 StringWriter sw = new StringWriter();
2064 XMLOutputter2 op = new XMLOutputter2();
2065 op.output(elIn, sw);
2066 assertEquals("Incorrect data after serialization", sw.toString(), bufWithEmptyNS);
2067
2068 //set up an element to test with
2069 Element element2 = new Element("element", Namespace.getNamespace("http://foo"));
2070 element2.addNamespaceDeclaration(Namespace.getNamespace("foo", "http://test1"));
2071 element2.addNamespaceDeclaration(Namespace.getNamespace("bar", "http://test2"));
2072 Element child21 = new Element("child1");
2073 child21.setAttribute(new Attribute("anAttribute", "no namespace"));
2074 Element child22 = new Element("child2");
2075 Attribute att21 = new Attribute("anAttribute", "with namespace", Namespace.getNamespace("x", "http://foo"));
2076 child22.setAttribute(att21);
2077 //add another child level deep
2078 Element descendent2 = new Element("descendent");
2079 child22.addContent(descendent2);
2080 element2.addContent(child21);
2081 element2.addContent(child22);
2082
2083 //here is what we expect back after serialization
2084 String bufWithEmptyNS2 =
2085 "<element xmlns=\"http://foo\" xmlns:bar=\"http://test2\" xmlns:foo=\"http://test1\"><child1 xmlns=\"\" anAttribute=\"no namespace\" /><child2 xmlns=\"\" xmlns:x=\"http://foo\" x:anAttribute=\"with namespace\"><descendent /></child2></element>";
2086
2087 Element elIn2 = UnitTestUtil.deSerialize(element2);
2088
2089 StringWriter sw2 = new StringWriter();
2090 XMLOutputter2 op2 = new XMLOutputter2();
2091 op2.output(elIn2, sw2);
2092 assertTrue("Incorrect data after serialization", sw2.toString().equals(bufWithEmptyNS2));
2093 }
2094
2095 // @Test
2096 // public void test_AddingString() {
2097 // Vector<Object> v = new Vector<Object>();
2098 // v.add("one");
2099 // Element e = new Element("e");
2100 // try {
2101 // e.setContent(v);
2102 // fail("Should not be avle to add String content");
2103 // } catch (ClassCastException cce) {
2104 // // good.
2105 // } catch (Exception ex) {
2106 // fail("Expected ClassCastException, not " + ex.getClass());
2107 // }
2108 // }
2109
2110 @Test
2111 public void testElementAddDocType() {
2112 try {
2113 List<Content> list = (new Element("tag").getContent());
2114 list.add(new DocType("elementname"));
2115 fail ("Should not be able to add DocType to an Element");
2116 } catch (IllegalAddException iae) {
2117 // good!
2118 } catch (Exception e) {
2119 fail ("We expect an IllegalAddException, but got " + e.getClass().getName());
2120 }
2121 }
2122
2123 // @Test
2124 // public void testElementAddAttribute() {
2125 // try {
2126 // List<Content> list = (new Element("tag").getContent());
2127 // list.add(new Attribute("att", "value"));
2128 // fail ("Should not be able to add Attribute to an Element's ContentList");
2129 // } catch (IllegalAddException iae) {
2130 // // good!
2131 // } catch (Exception e) {
2132 // fail ("We expect an IllegalAddException, but got " + e.getClass().getName());
2133 // }
2134 // }
2135
2136 @Test
2137 public void testGetNamespace() {
2138 Element emt = new Element("mine");
2139 Namespace nsa = Namespace.getNamespace("tstada", "uri");
2140 emt.setAttribute("name", "value", nsa);
2141 assertTrue(Namespace.NO_NAMESPACE == emt.getNamespace());
2142 assertTrue(emt.getNamespace(null) == null);
2143 assertTrue(emt.getNamespace("none") == null);
2144 assertTrue(emt.getNamespace("xml") == Namespace.XML_NAMESPACE);
2145 assertTrue(emt.getNamespace("tstada") == nsa);
2146 }
2147
2148 @Test
2149 public void testSetNamespaceAdditional() {
2150 Namespace nsa = Namespace.getNamespace("pfx","URIA");
2151 Namespace nsb = Namespace.getNamespace("pfx","URIB");
2152 Namespace nsc = Namespace.getNamespace("pfx","URIC");
2153
2154 Element emt = new Element("emt", nsa);
2155 try {
2156 // cannot add a second namespace with the same prefix as the Element.
2157 emt.addNamespaceDeclaration(nsb);
2158 fail("Expected Namespace Collision Exception.");
2159 } catch (IllegalAddException iae) {
2160 // good
2161 } catch (Exception e) {
2162 e.printStackTrace();
2163 fail("Expected IllegalAddException, but got " + e.getClass());
2164 }
2165
2166 // and we can change the Element's Namespace to nsc
2167 emt.setNamespace(nsc);
2168 // and back again.
2169 emt.setNamespace(nsa);
2170
2171 // further we can add nsa as an additional namespace because it is the
2172 // same as the Element's namespace.
2173 emt.addNamespaceDeclaration(nsa);
2174
2175 try {
2176 // but, now we can't change the Element's Namespace.
2177 emt.setNamespace(nsb);
2178 fail("Expected Namespace Collision Exception.");
2179 } catch (IllegalAddException iae) {
2180 // good
2181 } catch (Exception e) {
2182 e.printStackTrace();
2183 fail("Expected IllegalAddException, but got " + e.getClass());
2184 }
2185
2186 emt.addNamespaceDeclaration(nsa);
2187 }
2188
2189 @Test
2190 public void testSetNamespaceAttribute() {
2191 Namespace nsa = Namespace.getNamespace("pfx","URIA");
2192 Namespace nsb = Namespace.getNamespace("pfx","URIB");
2193 Namespace nsc = Namespace.getNamespace("pfx","URIC");
2194 Namespace nsd = Namespace.getNamespace("pfy","URID");
2195
2196 Element emt = new Element("emt", nsa);
2197 try {
2198 // cannot add a second namespace with the same prefix as the Element.
2199 emt.setAttribute("att", "val", nsb);
2200 fail("Expected Namespace Collision Exception.");
2201 } catch (IllegalAddException iae) {
2202 // good
2203 } catch (Exception e) {
2204 e.printStackTrace();
2205 fail("Expected IllegalAddException, but got " + e.getClass());
2206 }
2207
2208 // and we can change the Element's Namespace to nsc
2209 emt.setNamespace(nsc);
2210 assertTrue(nsc == emt.getNamespace());
2211 // and back again.
2212 emt.setNamespace(nsa);
2213 assertTrue(nsa == emt.getNamespace());
2214
2215 // further we can add nsa as an additional namespace because it is the
2216 // same as the Element's namespace.
2217 assertTrue(emt == emt.setAttribute("att", "value", nsa));
2218
2219 try {
2220 // but, now we can't change the Element's Namespace.
2221 emt.setNamespace(nsb);
2222 fail("Expected Namespace Collision Exception.");
2223 } catch (IllegalAddException iae) {
2224 // good
2225 } catch (Exception e) {
2226 e.printStackTrace();
2227 fail("Expected IllegalAddException, but got " + e.getClass());
2228 }
2229
2230 // but we can change it to something with a different prefix:
2231 emt.setNamespace(nsd);
2232 assertTrue(nsd == emt.getNamespace());
2233
2234 assertTrue(emt.setAttribute("tst", "val1", null) == emt);
2235 assertEquals("val1", emt.getAttributeValue("tst"));
2236 assertEquals("val1", emt.getAttributeValue("tst", (Namespace)null));
2237 assertEquals("val1", emt.getAttributeValue("tst", Namespace.NO_NAMESPACE));
2238 assertTrue(emt.setAttribute("tst", "val2", Namespace.NO_NAMESPACE) == emt);
2239 assertEquals("val2", emt.getAttributeValue("tst"));
2240 assertEquals("val2", emt.getAttributeValue("tst", (Namespace)null));
2241 assertEquals("val2", emt.getAttributeValue("tst", Namespace.NO_NAMESPACE));
2242
2243
2244 }
2245
2246 @Test
2247 public void testRemoveNamespace() {
2248 Element emt = new Element("mine");
2249 Namespace myuri = Namespace.getNamespace("pfx", "myuri");
2250 assertTrue(emt.getNamespace("pfx") == null);
2251 emt.removeNamespaceDeclaration(myuri);
2252 emt.addNamespaceDeclaration(myuri);
2253 assertTrue(emt.getNamespace("pfx") == myuri);
2254 emt.removeNamespaceDeclaration(myuri);
2255 assertTrue(emt.getNamespace("pfx") == null);
2256 }
2257
2258 @Test
2259 public void testGetValue() {
2260 Element emt = new Element("root");
2261 emt.addContent("See ");
2262 assertTrue("See ".equals(emt.getValue()));
2263 emt.addContent(new Element("k1").addContent("Spot "));
2264 assertTrue("See Spot ".equals(emt.getValue()));
2265 emt.addContent(new Comment("skip "));
2266 assertTrue("See Spot ".equals(emt.getValue()));
2267 emt.addContent(new CDATA("run!"));
2268 assertTrue("See Spot run!".equals(emt.getValue()));
2269 }
2270
2271 @Test
2272 public void testGetText() {
2273 Element emt = new Element("root");
2274 assertTrue("".equals(emt.getText()));
2275 emt.addContent(new Comment("skip "));
2276 assertTrue("".equals(emt.getText()));
2277 emt.addContent(new ProcessingInstruction("dummy", "nodata"));
2278 assertTrue("".equals(emt.getText()));
2279 emt.removeContent();
2280 assertTrue("".equals(emt.getText()));
2281 emt.addContent(" See ");
2282 assertTrue(" See ".equals(emt.getText()));
2283 emt.addContent(new Element("k1").addContent(" Spot the \n dog "));
2284 assertTrue(" See ".equals(emt.getText()));
2285 emt.addContent(new CDATA(" run! "));
2286 assertTrue(" See run! ".equals(emt.getText()));
2287 assertTrue("See run!".equals(emt.getTextTrim()));
2288 assertTrue("See run!".equals(emt.getTextNormalize()));
2289
2290 assertTrue(" Spot the \n dog ".equals(emt.getChildText("k1")));
2291 assertTrue("Spot the \n dog".equals(emt.getChildTextTrim("k1")));
2292 assertTrue("Spot the dog".equals(emt.getChildTextNormalize("k1")));
2293
2294 assertTrue(" Spot the \n dog ".equals(emt.getChildText("k1", Namespace.NO_NAMESPACE)));
2295 assertTrue("Spot the \n dog".equals(emt.getChildTextTrim("k1", Namespace.NO_NAMESPACE)));
2296 assertTrue("Spot the dog".equals(emt.getChildTextNormalize("k1", Namespace.NO_NAMESPACE)));
2297
2298 assertTrue(null == emt.getChildText("x1"));
2299 assertTrue(null == emt.getChildTextTrim("x1"));
2300 assertTrue(null == emt.getChildTextNormalize("x1"));
2301
2302 assertTrue(null == emt.getChildText("x1", Namespace.NO_NAMESPACE));
2303 assertTrue(null == emt.getChildTextTrim("x1", Namespace.NO_NAMESPACE));
2304 assertTrue(null == emt.getChildTextNormalize("x1", Namespace.NO_NAMESPACE));
2305
2306 Namespace xx = Namespace.getNamespace("nouri");
2307 assertTrue(null == emt.getChildText("k1", xx));
2308 assertTrue(null == emt.getChildTextTrim("k1", xx));
2309 assertTrue(null == emt.getChildTextNormalize("k1", xx));
2310 }
2311
2312 @Test
2313 public void testElementContent() {
2314 Document doc = new Document();
2315 Element root = new Element("root");
2316 assertTrue(root.getContentSize() == 0);
2317 assertFalse(root.isRootElement());
2318 doc.addContent(root);
2319 assertTrue(root.isRootElement());
2320
2321 assertTrue(root.cloneContent().size() == 0);
2322
2323 final Text text = new Text("text");
2324 final Comment comment1 = new Comment("comment1");
2325 final Comment comment2 = new Comment("comment2");
2326 final Element child = new Element("child");
2327
2328 root.addContent(text);
2329 assertTrue(root.getContentSize() == 1);
2330 assertTrue(root.getText().equals(text.getText()));
2331 assertTrue(root.cloneContent().size() == 1);
2332 assertTrue(root.cloneContent().get(0) instanceof Text);
2333 assertTrue(root.indexOf(text) == 0);
2334
2335 assertTrue(text.getParent() == root);
2336 assertTrue(root.removeContent().get(0) == text);
2337
2338 assertTrue(text.getParent() == null);
2339 assertTrue(root.getContentSize() == 0);
2340 assertTrue(root.cloneContent().size() == 0);
2341
2342 root.addContent(comment1);
2343 root.addContent(comment2);
2344 assertTrue(comment1.getParent() == root);
2345 assertTrue(comment2.getParent() == root);
2346 assertTrue(text.getParent() == null);
2347 assertTrue(root.getContentSize() == 2);
2348 root.setContent(1, text);
2349 assertTrue(comment1.getParent() == root);
2350 assertTrue(comment2.getParent() == null);
2351 assertTrue(text.getParent() == root);
2352 assertTrue(root.getContentSize() == 2);
2353
2354 root.setContent(comment2);
2355 assertTrue(comment1.getParent() == null);
2356 assertTrue(comment2.getParent() == root);
2357 assertTrue(text.getParent() == null);
2358 assertTrue(root.getContentSize() == 1);
2359 assertTrue(comment2 == root.removeContent(0));
2360
2361 root.addContent(Collections.singleton(comment2));
2362 assertTrue(comment1.getParent() == null);
2363 assertTrue(comment2.getParent() == root);
2364 assertTrue(text.getParent() == null);
2365 assertTrue(root.getContentSize() == 1);
2366
2367 root.addContent(0, Collections.singleton(comment1));
2368 assertTrue(comment1.getParent() == root);
2369 assertTrue(comment2.getParent() == root);
2370 assertTrue(text.getParent() == null);
2371 assertTrue(root.getContentSize() == 2);
2372
2373 root.addContent(2, Collections.singleton(text));
2374 assertTrue(comment1.getParent() == root);
2375 assertTrue(comment2.getParent() == root);
2376 assertTrue(text.getParent() == root);
2377 assertTrue(root.getContentSize() == 3);
2378 assertTrue(root.indexOf(comment1) == 0);
2379 assertTrue(root.indexOf(comment2) == 1);
2380 assertTrue(root.indexOf(text) == 2);
2381
2382 root.setContent(2, Collections.singleton(text));
2383 assertTrue(comment1.getParent() == root);
2384 assertTrue(comment2.getParent() == root);
2385 assertTrue(text.getParent() == root);
2386 assertTrue(root.getContentSize() == 3);
2387 assertTrue(root.indexOf(comment1) == 0);
2388 assertTrue(root.indexOf(comment2) == 1);
2389 assertTrue(root.indexOf(text) == 2);
2390
2391 Set<Content> empty = Collections.emptySet();
2392 root.setContent(2, empty);
2393 assertTrue(comment1.getParent() == root);
2394 assertTrue(comment2.getParent() == root);
2395 assertTrue(text.getParent() == null);
2396 assertTrue(root.getContentSize() == 2);
2397 assertTrue(root.indexOf(comment1) == 0);
2398 assertTrue(root.indexOf(comment2) == 1);
2399 assertTrue(root.indexOf(text) == -1);
2400
2401 root.addContent(2, text);
2402 assertTrue(comment1.getParent() == root);
2403 assertTrue(comment2.getParent() == root);
2404 assertTrue(text.getParent() == root);
2405 assertTrue(root.getContentSize() == 3);
2406 assertTrue(root.indexOf(comment1) == 0);
2407 assertTrue(root.indexOf(comment2) == 1);
2408 assertTrue(root.indexOf(text) == 2);
2409
2410 root.addContent(child);
2411 assertTrue(root.indexOf(child) == 3);
2412 assertTrue(root.getContentSize() == 4);
2413 assertTrue(child.getParent() == root);
2414 assertTrue(child.getParentElement() == root);
2415 assertTrue(root.getContent().size() == 4);
2416 assertTrue(root.getContent(new ElementFilter()).size() == 1);
2417 assertTrue(root.getContent(new ContentFilter(ContentFilter.COMMENT)).size() == 2);
2418 assertFalse(root.removeChild("child", Namespace.XML_NAMESPACE));
2419 assertTrue(root.removeChild("child", Namespace.NO_NAMESPACE));
2420
2421 assertTrue(root.getContentSize() == 3);
2422 assertTrue(root.getContent(new ElementFilter()).isEmpty());
2423
2424 assertTrue(root.removeContent(new ContentFilter(ContentFilter.COMMENT)).size() == 2);
2425
2426 assertTrue(root.getContentSize() == 1);
2427 assertTrue(root == root.addContent(child));
2428 assertTrue(root.getContentSize() == 2);
2429 assertFalse(root.removeChildren("nothing"));
2430 assertFalse(root.removeChildren("child", Namespace.getNamespace("nothing")));
2431 assertTrue(root.removeChildren("child"));
2432 assertTrue(root.getContentSize() == 1);
2433
2434 // some negative cases not yet covered....
2435 try {
2436 Element n = null;
2437 root.addContent(0, n);
2438 fail("Should not be able to add null Element content.");
2439 } catch (NullPointerException npe) {
2440 // good
2441 } catch (Exception e) {
2442 fail("Expected NullPointerException, but got " + e.getClass().getName());
2443 }
2444
2445 try {
2446 // try to add ourself.
2447 child.addContent(0, child);
2448 fail("Should not be able to add ourself as Element content.");
2449 } catch (IllegalAddException npe) {
2450 // good
2451 } catch (Exception e) {
2452 fail("Expected NullPointerException, but got " + e.getClass().getName());
2453 }
2454
2455 root.detach();
2456 root.addContent(child);
2457
2458 try {
2459 // try to add ourself.
2460 child.addContent(0, root);
2461 fail("Should not be able to add circular Element content.");
2462 } catch (IllegalAddException npe) {
2463 // good
2464 } catch (Exception e) {
2465 fail("Expected NullPointerException, but got " + e.getClass().getName());
2466 }
2467 }
2468
2469 @Test
2470 public void testAttributes() {
2471 Element emt = new Element("element");
2472 Namespace myns = Namespace.getNamespace("pfxa", "attns");
2473 Namespace mynsz = Namespace.getNamespace("pfxz", "attns");
2474 assertTrue(emt.getAttributes().isEmpty());
2475 assertTrue(emt.getAttribute("att") == null);
2476 assertTrue(emt.getAttributeValue("att") == null);
2477 assertTrue(emt.getAttributeValue("att", Namespace.NO_NAMESPACE) == null);
2478 assertTrue(emt.getAttributeValue("att", (Namespace)null) == null);
2479 assertTrue(emt.getAttributeValue("att", myns) == null);
2480 assertTrue("def".equals(emt.getAttributeValue("att", "def")));
2481 assertTrue("def".equals(emt.getAttributeValue("att", myns, "def")));
2482 assertTrue(emt.getAdditionalNamespaces().isEmpty());
2483
2484 emt.setAttribute(new Attribute("att", "val"));
2485 assertFalse(emt.getAttributes().isEmpty());
2486 assertTrue(emt.getAttribute("att") != null);
2487 assertTrue("val".equals(emt.getAttributeValue("att")));
2488 assertTrue("val".equals(emt.getAttributeValue("att", Namespace.NO_NAMESPACE)));
2489 assertTrue("val".equals(emt.getAttributeValue("att", (Namespace)null)));
2490 assertTrue(emt.getAttributeValue("att", myns) == null);
2491 assertTrue("val".equals(emt.getAttributeValue("att", "def")));
2492 assertTrue("val".equals(emt.getAttributeValue("att", Namespace.NO_NAMESPACE, "def")));
2493 assertTrue("val".equals(emt.getAttributeValue("att", null, "def")));
2494 assertTrue("def".equals(emt.getAttributeValue("att", myns, "def")));
2495 assertTrue(emt.getAdditionalNamespaces().isEmpty());
2496
2497 emt.setAttribute(new Attribute("att", "nsval", myns));
2498 assertFalse(emt.getAttributes().isEmpty());
2499 assertTrue(emt.getAttribute("att") != null);
2500 assertTrue(emt.getAttribute("att", myns) != null);
2501 assertTrue(emt.getAttribute("att") != emt.getAttribute("att", myns));
2502 assertTrue("val".equals(emt.getAttributeValue("att")));
2503 assertTrue("val".equals(emt.getAttributeValue("att", Namespace.NO_NAMESPACE)));
2504 assertTrue("val".equals(emt.getAttributeValue("att", (Namespace)null)));
2505 assertTrue("nsval".equals(emt.getAttributeValue("att", myns)));
2506 assertTrue("nsval".equals(emt.getAttributeValue("att", mynsz)));
2507 assertTrue("val".equals(emt.getAttributeValue("att", "def")));
2508 assertTrue("nsval".equals(emt.getAttributeValue("att", myns, "def")));
2509 assertTrue("def".equals(emt.getAttributeValue("att", Namespace.XML_NAMESPACE, "def")));
2510
2511 assertTrue(emt.getAdditionalNamespaces().isEmpty());
2512
2513 Attribute att = emt.getAttribute("att");
2514 Attribute na = new Attribute("xx", "xval");
2515 assertFalse(emt.removeAttribute(na));
2516 assertTrue(emt.removeAttribute(att));
2517 assertTrue(att.getParent() == null);
2518 emt.setAttribute(att);
2519 assertTrue(att.getParent() == emt);
2520 assertTrue(emt.setAttribute("att", "nval") == emt);
2521 assertTrue(att.getParent() == emt);
2522 assertTrue("nval".equals(att.getValue()));
2523 assertTrue("nval".equals(emt.getAttributeValue("att")));
2524 assertTrue(emt.setAttribute(new Attribute("att", "zval")) == emt);
2525 assertTrue(att.getParent() == null);
2526 assertTrue("nval".equals(att.getValue()));
2527 assertTrue("zval".equals(emt.getAttributeValue("att")));
2528 assertTrue(emt.setAttribute(att) == emt);
2529 assertTrue(att.getParent() == emt);
2530
2531
2532 att = emt.getAttribute("att", myns);
2533 na = new Attribute("xx", "xval", myns);
2534 assertFalse(emt.removeAttribute(na));
2535 assertTrue(emt.removeAttribute(att));
2536 assertTrue(emt.setAttribute("att", "aval", myns) == emt);
2537 assertTrue("nsval".equals(att.getValue()));
2538 assertTrue("aval".equals(emt.getAttributeValue("att", myns)));
2539 assertTrue(att.getParent() == null);
2540 emt.setAttribute(att);
2541 assertTrue(att.getParent() == emt);
2542 assertTrue(emt.setAttribute("att", "nval", myns) == emt);
2543 assertTrue(att.getParent() == emt);
2544 assertTrue("nval".equals(att.getValue()));
2545 assertTrue("nval".equals(emt.getAttributeValue("att", myns)));
2546 assertTrue(emt.setAttribute(new Attribute("att", "zval", myns)) == emt);
2547 assertTrue(att.getParent() == null);
2548 assertTrue("nval".equals(att.getValue()));
2549 assertTrue("zval".equals(emt.getAttributeValue("att", myns)));
2550 assertTrue(emt.setAttribute(att) == emt);
2551 assertTrue(att.getParent() == emt);
2552 assertTrue("nval".equals(emt.getAttributeValue("att", myns)));
2553
2554 }
2555
2556 @SuppressWarnings("unchecked")
2557 private final void addBrokenContent(Collection<?> cn, Object val) {
2558 // this method is intentionally broken.
2559 Collection<Object> ocn = (Collection<Object>)cn;
2560 ocn.add(val);
2561 }
2562
2563 @Test
2564 public void testCloneDetatchParentElement() {
2565 Element parent = new Element("root");
2566 Element content = new Element("val");
2567 parent.addContent(content);
2568 Element clone = content.detach().clone();
2569 assertEquals(content.getValue(), clone.getValue());
2570 assertNull(content.getParent());
2571 assertNull(clone.getParent());
2572 }
2573
2574 @Test
2575 public void testContentCType() {
2576 assertTrue(Content.CType.Element == new Element("root").getCType());
2577 }
2578
2579 private final Comparator<Text> alphaText = new Comparator<Text>() {
2580 @Override
2581 public int compare(Text o1, Text o2) {
2582 return o1.getText().compareTo(o2.getText());
2583 }
2584 };
2585
2586 private final Comparator<Content> alphaContent = new Comparator<Content>() {
2587 @Override
2588 public int compare(Content o1, Content o2) {
2589 final int ctd = o1.getCType().ordinal() - o2.getCType().ordinal();
2590 if (ctd != 0) {
2591 return ctd;
2592 }
2593 final CType ct = o1.getCType();
2594 switch (ct) {
2595 case Comment:
2596 return ((Comment)o1).getText().compareTo(((Comment)o2).getText());
2597 case CDATA:
2598 return ((CDATA)o1).getText().compareTo(((CDATA)o2).getText());
2599 case DocType:
2600 return ((DocType)o1).getElementName()
2601 .compareTo(((DocType)o2).getElementName());
2602 case Element:
2603 return ((Element)o1).getName()
2604 .compareTo(((Element)o2).getName());
2605 case ProcessingInstruction:
2606 return ((ProcessingInstruction)o1).getTarget()
2607 .compareTo(((ProcessingInstruction)o2).getTarget());
2608 case EntityRef:
2609 return ((EntityRef)o1).getName()
2610 .compareTo(((EntityRef)o2).getName());
2611 case Text:
2612 return ((Text)o1).getText().compareTo(((Text)o2).getText());
2613 }
2614 return 0;
2615 }
2616 };
2617
2618 @Test
2619 public void testSort() {
2620 Element emt = new Element("root");
2621 emt.addContent(new Text("d"));
2622 emt.addContent(new Text("c"));
2623 emt.addContent(new Text("b"));
2624 emt.addContent(new Text("a"));
2625 assertEquals("dcba", emt.getText());
2626
2627 emt.sortContent(Filters.text(), alphaText);
2628
2629 assertEquals("abcd", emt.getText());
2630 }
2631
2632 @Test
2633 public void testSortOnlyContent() {
2634 Element emt = new Element("root");
2635 emt.addContent(new Text("a"));
2636 assertEquals("a", emt.getText());
2637 emt.sortContent(alphaContent);
2638 assertEquals("a", emt.getText());
2639 }
2640
2641 @Test
2642 public void testSortOnlyFiltered() {
2643 Element emt = new Element("root");
2644 emt.addContent(new Text("a"));
2645 assertEquals("a", emt.getText());
2646 emt.sortContent(Filters.text(), alphaText);
2647 assertEquals("a", emt.getText());
2648 }
2649
2650 @Test
2651 public void testSortAllSameContent() {
2652 Element emt = new Element("root");
2653 emt.addContent(new Text("a"));
2654 emt.addContent(new Text("a"));
2655 emt.addContent(new Text("a"));
2656 emt.addContent(new Text("a"));
2657 assertEquals("aaaa", emt.getText());
2658 emt.sortContent(alphaContent);
2659 assertEquals("aaaa", emt.getText());
2660 }
2661
2662 @Test
2663 public void testSortAllSameFiltered() {
2664 Element emt = new Element("root");
2665 emt.addContent(new Text("a"));
2666 emt.addContent(new Text("a"));
2667 emt.addContent(new Text("a"));
2668 emt.addContent(new Text("a"));
2669 assertEquals("aaaa", emt.getText());
2670 emt.sortContent(Filters.text(), alphaText);
2671 assertEquals("aaaa", emt.getText());
2672 }
2673
2674 @Test
2675 public void testSortContent() {
2676 Element emt = new Element("root");
2677 CDATA cdata = new CDATA("XXX");
2678 emt.addContent(new Text("d"));
2679 emt.addContent(cdata);
2680 emt.addContent(new Text("c"));
2681 emt.addContent(new Text("b"));
2682 emt.addContent(new Text("a"));
2683 assertEquals("dXXXcba", emt.getText());
2684
2685 emt.sortContent(alphaContent);
2686
2687 assertEquals("abcdXXX", emt.getText());
2688 assertEquals(cdata, emt.getContent(4));
2689 }
2690
2691 @Test
2692 public void testSortContentNullComp() {
2693 Element emt = new Element("root");
2694 CDATA cdata = new CDATA("XXX");
2695 emt.addContent(new Text("d"));
2696 emt.addContent(cdata);
2697 emt.addContent(new Text("c"));
2698 emt.addContent(new Text("b"));
2699 emt.addContent(new Text("a"));
2700 assertEquals("dXXXcba", emt.getText());
2701
2702 emt.sortContent(null);
2703
2704 assertEquals("dXXXcba", emt.getText());
2705 assertEquals(cdata, emt.getContent(1));
2706 }
2707
2708 @Test
2709 public void testSortElementContent() {
2710 final Element emt = new Element("root");
2711 final CDATA cdata = new CDATA("XXX");
2712 final Element a = new Element("a");
2713 final Element b = new Element("b");
2714 final Element c = new Element("c");
2715 final Element d = new Element("d");
2716
2717 emt.addContent(d);
2718 emt.addContent(cdata);
2719 emt.addContent(c);
2720 emt.addContent(b);
2721 emt.addContent(a);
2722
2723 assertTrue(emt.getContent(0) == d);
2724 assertTrue(emt.getContent(1) == cdata);
2725 assertTrue(emt.getContent(2) == c);
2726 assertTrue(emt.getContent(3) == b);
2727 assertTrue(emt.getContent(4) == a);
2728
2729 emt.sortChildren(alphaContent);
2730 assertTrue(emt.getContent(0) == a);
2731 assertTrue(emt.getContent(1) == cdata);
2732 assertTrue(emt.getContent(2) == b);
2733 assertTrue(emt.getContent(3) == c);
2734 assertTrue(emt.getContent(4) == d);
2735
2736 emt.sortContent(alphaContent);
2737
2738 assertTrue(emt.getContent(0) == a);
2739 assertTrue(emt.getContent(1) == b);
2740 assertTrue(emt.getContent(2) == c);
2741 assertTrue(emt.getContent(3) == d);
2742 assertTrue(emt.getContent(4) == cdata);
2743 }
2744
2745 @Test
2746 public void testSortEqualsContent() {
2747 Element emt = new Element("root");
2748 final CDATA cdata = new CDATA("XXX");
2749 final Text t1 = new Text("a");
2750 final Text t2 = new Text("a");
2751 final Text t3 = new Text("a");
2752 final Text t4 = new Text("a");
2753 emt.addContent(t1);
2754 emt.addContent(cdata);
2755 emt.addContent(t2);
2756 emt.addContent(t3);
2757 emt.addContent(t4);
2758 assertEquals("aXXXaaa", emt.getText());
2759
2760 emt.sortContent(alphaContent);
2761
2762 assertEquals("aaaaXXX", emt.getText());
2763 assertEquals(t1, emt.getContent(0));
2764 assertEquals(t2, emt.getContent(1));
2765 assertEquals(t3, emt.getContent(2));
2766 assertEquals(t4, emt.getContent(3));
2767 assertEquals(cdata, emt.getContent(4));
2768 }
2769
2770 @Test
2771 public void testSortInterleavedContent() {
2772 Element emt = new Element("root");
2773 emt.addContent(new Text("d"));
2774 emt.addContent(new CDATA("ZZZ"));
2775 emt.addContent(new Text("c"));
2776 emt.addContent(new CDATA("YYY"));
2777 emt.addContent(new Text("b"));
2778 emt.addContent(new CDATA("XXX"));
2779 emt.addContent(new Text("a"));
2780 assertEquals("dZZZcYYYbXXXa", emt.getText());
2781
2782 // we can use Text comparator for CDATA too.
2783 emt.sortContent(Filters.cdata(), alphaText);
2784 assertEquals("dXXXcYYYbZZZa", emt.getText());
2785
2786 // we can use Text comparator for CDATA too.
2787 emt.sortContent(new ContentFilter(ContentFilter.TEXT), alphaContent);
2788 assertEquals("aXXXbYYYcZZZd", emt.getText());
2789
2790 // we can use Text comparator for CDATA too.... and Filters.text() does Text and CDATA
2791 emt.sortContent(Filters.text(), alphaText);
2792 assertEquals("XXXYYYZZZabcd", emt.getText());
2793 }
2794
2795 @Test
2796 public void testSortInterleavedEqualContent() {
2797 Element emt = new Element("root");
2798 final CDATA cd1 = new CDATA("ZZZ");
2799 final CDATA cd2 = new CDATA("ZZZ");
2800 final CDATA cd3 = new CDATA("ZZZ");
2801 emt.addContent(new Text("d"));
2802 emt.addContent(cd1);
2803 emt.addContent(new Text("c"));
2804 emt.addContent(cd2);
2805 emt.addContent(new Text("b"));
2806 emt.addContent(cd3);
2807 emt.addContent(new Text("a"));
2808 assertEquals("dZZZcZZZbZZZa", emt.getText());
2809
2810 assertTrue(emt.getContent(1) == cd1);
2811 assertTrue(emt.getContent(3) == cd2);
2812 assertTrue(emt.getContent(5) == cd3);
2813
2814 // we can use Text comparator for CDATA too.
2815 // check sort does not reorder comp==0 content
2816 emt.sortContent(Filters.cdata(), alphaText);
2817 assertEquals("dZZZcZZZbZZZa", emt.getText());
2818 assertTrue(emt.getContent(1) == cd1);
2819 assertTrue(emt.getContent(3) == cd2);
2820 assertTrue(emt.getContent(5) == cd3);
2821
2822
2823 // we can use Text comparator for CDATA too.
2824 emt.sortContent(new ContentFilter(ContentFilter.TEXT), alphaContent);
2825 assertEquals("aZZZbZZZcZZZd", emt.getText());
2826 assertTrue(emt.getContent(1) == cd1);
2827 assertTrue(emt.getContent(3) == cd2);
2828 assertTrue(emt.getContent(5) == cd3);
2829
2830 // we can use Text comparator for CDATA too.... and Filters.text() does Text and CDATA
2831 emt.sortContent(Filters.text(), alphaText);
2832 assertEquals("ZZZZZZZZZabcd", emt.getText());
2833 assertTrue(emt.getContent(0) == cd1);
2834 assertTrue(emt.getContent(1) == cd2);
2835 assertTrue(emt.getContent(2) == cd3);
2836 }
2837
2838 @Test
2839 public void testSortAttributes() {
2840 final Element emt = new Element("root");
2841 final Attribute att1 = new Attribute("one", "001", Namespace.getNamespace("z", "uri1"));
2842 final Attribute att2 = new Attribute("two", "002", Namespace.getNamespace("y", "uri1"));
2843 final Attribute att3 = new Attribute("three", "003", Namespace.getNamespace("x", "uri1"));
2844 final Attribute att4 = new Attribute("four", "004", Namespace.getNamespace("w", "uri2"));
2845 final Attribute att5 = new Attribute("five", "005", Namespace.getNamespace("v", "uri2"));
2846
2847 final Attribute att6 = new Attribute("six", "006", Namespace.getNamespace("x", "uri1"));
2848
2849 emt.setAttribute(att5);
2850 emt.setAttribute(att4);
2851 emt.setAttribute(att3);
2852 emt.setAttribute(att2);
2853 emt.setAttribute(att1);
2854
2855 checkAttOrder(emt.getAttributes(), att5, att4, att3, att2, att1);
2856
2857 emt.sortAttributes(new Comparator<Attribute>() {
2858 @Override
2859 public int compare(Attribute o1, Attribute o2) {
2860 return o1.getName().compareTo(o2.getName());
2861 }
2862 });
2863
2864 // alphabetic by string name.
2865 checkAttOrder(emt.getAttributes(), att5, att4, att1, att3, att2);
2866
2867 emt.sortAttributes(new Comparator<Attribute>() {
2868 @Override
2869 public int compare(Attribute o1, Attribute o2) {
2870 return o1.getNamespacePrefix().compareTo(o2.getNamespacePrefix());
2871 }
2872 });
2873
2874 // Namespace Prefixes's are reverse order
2875 checkAttOrder(emt.getAttributes(), att5, att4, att3, att2, att1);
2876
2877 emt.sortAttributes(new Comparator<Attribute>() {
2878 @Override
2879 public int compare(Attribute o1, Attribute o2) {
2880 return o1.getValue().compareTo(o2.getValue());
2881 }
2882 });
2883
2884 // Values are in order
2885 checkAttOrder(emt.getAttributes(), att1, att2, att3, att4, att5);
2886
2887 // Namespace URI's have some common items.... and are in same order
2888 // as a result, we should have no change at all.
2889 emt.sortAttributes(new Comparator<Attribute>() {
2890 @Override
2891 public int compare(Attribute o1, Attribute o2) {
2892 return o1.getNamespaceURI().compareTo(o2.getNamespaceURI());
2893 }
2894 });
2895
2896 // Values are in order
2897 checkAttOrder(emt.getAttributes(), att1, att2, att3, att4, att5);
2898
2899 // Namespace URI's have some common items.... and are in same order
2900 // as a result, we should have no change at all.... except, this time
2901 // we do the inverse of the result... so, this moves 4&5 to the front
2902 // but relative order is maintained for equal values....
2903 emt.sortAttributes(new Comparator<Attribute>() {
2904 @Override
2905 public int compare(Attribute o1, Attribute o2) {
2906 return - o1.getNamespaceURI().compareTo(o2.getNamespaceURI());
2907 }
2908 });
2909
2910 // Values are in order
2911 checkAttOrder(emt.getAttributes(), att4, att5, att1, att2, att3);
2912
2913 // use null sort on attributes... which sorts alphabetically by pfx:name
2914 emt.sortAttributes(null);
2915
2916 // Values are in order
2917 checkAttOrder(emt.getAttributes(), att5, att4, att3, att2, att1);
2918
2919 emt.setAttribute(att6);
2920
2921 checkAttOrder(emt.getAttributes(), att5, att4, att3, att2, att1, att6);
2922
2923 // alpha should sort att6 to before att3 (same prefix, six comes before three)
2924 emt.sortAttributes(null);
2925
2926 checkAttOrder(emt.getAttributes(), att5, att4, att6, att3, att2, att1);
2927
2928 }
2929
2930 @Test
2931 public void testSortAttributesNone() {
2932 Element emt = new Element("root");
2933 emt.sortAttributes(new Comparator<Attribute>() {
2934 @Override
2935 public int compare(Attribute o1, Attribute o2) {
2936 return - o1.getNamespaceURI().compareTo(o2.getNamespaceURI());
2937 }
2938 });
2939 // this ends up creating the Attribute array inside the Element.
2940 checkAttOrder(emt.getAttributes());
2941 }
2942
2943 private void checkAttOrder(List<Attribute> attributes, Attribute...atts) {
2944 assertTrue(atts.length == attributes.size());
2945 for (int i = atts.length - 1; i >= 0; i--) {
2946 assertTrue(atts[i] == attributes.get(i));
2947 }
2948
2949 }
2950
2951 private String getTestString() {
2952 return " this has space ";
2953 }
2954
2955 private String getComp() {
2956 return Format.compact(getTestString());
2957 }
2958
2959 private String getTrim() {
2960 return Format.trimBoth(getTestString());
2961 }
2962
2963 private String getPlain() {
2964 return getTestString();
2965 }
2966
2967 private Namespace getNamespace() {
2968 return Namespace.getNamespace("jdomtest");
2969 }
2970
2971 public Element getTextHelperRoot() {
2972 final Namespace ns = getNamespace();
2973
2974 final Element root = new Element("root");
2975 final Element childa = new Element("child");
2976 final Element childb = new Element("child", ns);
2977 final Element childc = new Element("child");
2978 final Element childd = new Element("child", ns);
2979 final Element childe = new Element("kid");
2980 final Element childf = new Element("kid", ns);
2981
2982 childa.setText(getTestString());
2983 childb.setText(getTestString());
2984 childc.setText(getTestString());
2985 childd.setText(getTestString());
2986 root.addContent(childa);
2987 root.addContent(childb);
2988 root.addContent(childc);
2989 root.addContent(childd);
2990 root.addContent(childe);
2991 root.addContent(childf);
2992
2993 return root;
2994 }
2995
2996 @Test
2997 public void testGetChildTextElementString() {
2998 Element root = getTextHelperRoot();
2999 assertEquals(getPlain(), root.getChildText("child"));
3000 assertEquals(null, root.getChildText("dummy"));
3001 assertEquals("", root.getChildText("kid"));
3002 }
3003
3004 @Test
3005 public void testGetChildTextElementStringNamespace() {
3006 Element root = getTextHelperRoot();
3007 Namespace ns = getNamespace();
3008 assertEquals(getPlain(), root.getChildText("child", ns));
3009 assertEquals(null, root.getChildText("dummy", ns));
3010 assertEquals("", root.getChildText("kid", ns));
3011 }
3012
3013 @Test
3014 public void testGetChildTextTrimElementString() {
3015 Element root = getTextHelperRoot();
3016 assertEquals(getTrim(), root.getChildTextTrim("child"));
3017 assertEquals(null, root.getChildTextTrim("dummy"));
3018 assertEquals("", root.getChildTextTrim("kid"));
3019 }
3020
3021 @Test
3022 public void testGetChildTextTrimElementStringNamespace() {
3023 Element root = getTextHelperRoot();
3024 Namespace ns = getNamespace();
3025 assertEquals(getTrim(), root.getChildTextTrim("child", ns));
3026 assertEquals(null, root.getChildTextTrim("dummy", ns));
3027 assertEquals("", root.getChildTextTrim("kid", ns));
3028 }
3029
3030 @Test
3031 public void testGetChildTextNormalizeElementString() {
3032 Element root = getTextHelperRoot();
3033 assertEquals(getComp(), root.getChildTextNormalize("child"));
3034 assertEquals(null, root.getChildTextNormalize("dummy"));
3035 assertEquals("", root.getChildTextNormalize("kid"));
3036 }
3037
3038 @Test
3039 public void testGetChildTextNormalizeElementStringNamespace() {
3040 Element root = getTextHelperRoot();
3041 Namespace ns = getNamespace();
3042 assertEquals(getComp(), root.getChildTextNormalize("child", ns));
3043 assertEquals(null, root.getChildTextNormalize("dummy", ns));
3044 assertEquals("", root.getChildTextNormalize("kid", ns));
3045 }
3046
3047
3048 @Test
3049 public void testCoalesceTextSimple() {
3050 Element root = new Element("root");
3051 root.addContent("one");
3052 root.addContent(" ");
3053 root.addContent("two");
3054 root.addContent(" ");
3055 root.addContent("three");
3056 assertTrue(5 == root.getContentSize());
3057 assertEquals("one two three", root.getText());
3058
3059 assertTrue(root.coalesceText(false));
3060 assertTrue(1 == root.getContentSize());
3061 assertEquals("one two three", root.getText());
3062 assertFalse(root.coalesceText(false));
3063 assertEquals("one two three", root.getText());
3064 }
3065
3066 @Test
3067 public void testCoalesceTextCDATA() {
3068 Element root = new Element("root");
3069 root.addContent("one");
3070 root.addContent(" ");
3071 root.addContent(new CDATA("two"));
3072 root.addContent(" ");
3073 root.addContent("three");
3074 assertTrue(5 == root.getContentSize());
3075 assertEquals("one two three", root.getText());
3076
3077 assertTrue(root.coalesceText(false));
3078 assertTrue(3 == root.getContentSize());
3079 assertEquals("one two three", root.getText());
3080 assertFalse(root.coalesceText(false));
3081 assertEquals("one two three", root.getText());
3082 }
3083
3084 @Test
3085 public void testCoalesceTextNested() {
3086 Element root = new Element("root");
3087 root.addContent("one");
3088 root.addContent(" ");
3089 Element kid = new Element("kid");
3090 root.addContent(kid);
3091 kid.addContent("two");
3092 root.addContent(" ");
3093 root.addContent("three");
3094 assertTrue(5 == root.getContentSize());
3095 assertEquals("one three", root.getText());
3096
3097 assertTrue(root.coalesceText(false));
3098 assertTrue(3 == root.getContentSize());
3099 assertEquals("one three", root.getText());
3100 assertFalse(root.coalesceText(false));
3101 assertEquals("one three", root.getText());
3102 }
3103
3104 @Test
3105 public void testCoalesceTextEmpty() {
3106 Element root = new Element("root");
3107 root.addContent("");
3108 root.addContent("one");
3109 root.addContent("");
3110 root.addContent(" ");
3111 root.addContent("");
3112
3113 root.addContent("two");
3114
3115 root.addContent("");
3116 root.addContent(" ");
3117 root.addContent("");
3118 root.addContent("three");
3119 root.addContent("");
3120 assertTrue(11 == root.getContentSize());
3121 assertEquals("one two three", root.getText());
3122
3123 assertTrue(root.coalesceText(false));
3124 assertTrue(1 == root.getContentSize());
3125 assertEquals("one two three", root.getText());
3126 assertFalse(root.coalesceText(false));
3127 assertEquals("one two three", root.getText());
3128 }
3129
3130 @Test
3131 public void testCoalesceTextSingle() {
3132 Element root = new Element("root");
3133 root.addContent("");
3134 assertEquals("", root.getText());
3135
3136 assertTrue(root.coalesceText(false));
3137 assertTrue(0 == root.getContentSize());
3138 assertEquals("", root.getText());
3139 assertFalse(root.coalesceText(false));
3140 assertEquals("", root.getText());
3141 }
3142
3143
3144 @Test
3145 public void testCoalesceTextSimpleRec() {
3146 Element root = new Element("root");
3147 root.addContent("one");
3148 root.addContent(" ");
3149 root.addContent("two");
3150 root.addContent(" ");
3151 root.addContent("three");
3152 assertTrue(5 == root.getContentSize());
3153 assertEquals("one two three", root.getText());
3154
3155 assertTrue(root.coalesceText(true));
3156 assertTrue(1 == root.getContentSize());
3157 assertEquals("one two three", root.getText());
3158 assertFalse(root.coalesceText(true));
3159 assertEquals("one two three", root.getText());
3160 }
3161
3162 @Test
3163 public void testCoalesceTextCDATARec() {
3164 Element root = new Element("root");
3165 root.addContent("one");
3166 root.addContent(" ");
3167 root.addContent(new CDATA("two"));
3168 root.addContent(" ");
3169 root.addContent("three");
3170 assertTrue(5 == root.getContentSize());
3171 assertEquals("one two three", root.getText());
3172
3173 assertTrue(root.coalesceText(true));
3174 assertTrue(3 == root.getContentSize());
3175 assertEquals("one two three", root.getText());
3176 assertFalse(root.coalesceText(true));
3177 assertEquals("one two three", root.getText());
3178 }
3179
3180 @Test
3181 public void testCoalesceTextNestedRec() {
3182 Element root = new Element("root");
3183 root.addContent("one");
3184 root.addContent(" ");
3185 Element kid = new Element("kid");
3186 root.addContent(kid);
3187 kid.addContent("two");
3188 root.addContent(" ");
3189 root.addContent("three");
3190 assertTrue(5 == root.getContentSize());
3191 assertEquals("one three", root.getText());
3192
3193 assertTrue(root.coalesceText(true));
3194 assertTrue(3 == root.getContentSize());
3195 assertEquals("one three", root.getText());
3196 assertFalse(root.coalesceText(true));
3197 assertEquals("one three", root.getText());
3198 }
3199
3200 @Test
3201 public void testCoalesceTextEmptyRec() {
3202 Element root = new Element("root");
3203 root.addContent("");
3204 root.addContent("one");
3205 root.addContent("");
3206 root.addContent(" ");
3207 root.addContent("");
3208
3209 root.addContent("two");
3210
3211 root.addContent("");
3212 root.addContent(" ");
3213 root.addContent("");
3214 root.addContent("three");
3215 root.addContent("");
3216 assertTrue(11 == root.getContentSize());
3217 assertEquals("one two three", root.getText());
3218
3219 assertTrue(root.coalesceText(true));
3220 assertTrue(1 == root.getContentSize());
3221 assertEquals("one two three", root.getText());
3222 assertFalse(root.coalesceText(true));
3223 assertEquals("one two three", root.getText());
3224 }
3225
3226 @Test
3227 public void testCoalesceTextSingleRec() {
3228 Element root = new Element("root");
3229 root.addContent("");
3230 assertEquals("", root.getText());
3231
3232 assertTrue(root.coalesceText(true));
3233 assertTrue(0 == root.getContentSize());
3234 assertEquals("", root.getText());
3235 assertFalse(root.coalesceText(true));
3236 assertEquals("", root.getText());
3237 }
3238
3239
3240 @Test
3241 public void testXmlBaseNone() throws URISyntaxException {
3242 Document doc = new Document();
3243 Element root = new Element("root");
3244 doc.setRootElement(root);
3245 assertTrue(null == root.getXMLBaseURI());
3246 }
3247
3248 @Test
3249 public void testXmlBaseDocument() throws URISyntaxException {
3250 Document doc = new Document();
3251 doc.setBaseURI("http://jdom.org/");
3252 Element root = new Element("root");
3253 doc.setRootElement(root);
3254 URI uri = root.getXMLBaseURI();
3255 assertTrue(uri != null);
3256 assertEquals("http://jdom.org/", uri.toASCIIString());
3257 }
3258
3259 @Test
3260 public void testXmlBaseRelative() throws URISyntaxException {
3261 Document doc = new Document();
3262 Element root = new Element("root");
3263 doc.setRootElement(root);
3264 root.setAttribute("base", "./sub/", Namespace.XML_NAMESPACE);
3265 URI uri = root.getXMLBaseURI();
3266 assertTrue(uri != null);
3267 assertEquals("./sub/", uri.toASCIIString());
3268 }
3269
3270 @Test
3271 public void testXmlBaseRelativeToDoc() throws URISyntaxException {
3272 Document doc = new Document();
3273 doc.setBaseURI("http://jdom.org/");
3274 Element root = new Element("root");
3275 doc.setRootElement(root);
3276 root.setAttribute("base", "./sub/", Namespace.XML_NAMESPACE);
3277 URI uri = root.getXMLBaseURI();
3278 assertTrue(uri != null);
3279 assertEquals("http://jdom.org/sub/", uri.toASCIIString());
3280 }
3281
3282 @Test
3283 public void testXmlBaseAbsolute() throws URISyntaxException {
3284 Document doc = new Document();
3285 doc.setBaseURI("http://jdom.org/some/path/to/low/level");
3286 Element root = new Element("root");
3287 doc.setRootElement(root);
3288 root.setAttribute("base", "/sub/", Namespace.XML_NAMESPACE);
3289 URI uri = root.getXMLBaseURI();
3290 assertTrue(uri != null);
3291 assertEquals("http://jdom.org/sub/", uri.toASCIIString());
3292 }
3293
3294 @Test
3295 public void testXmlBaseSubAbsolute() throws URISyntaxException {
3296 Document doc = new Document();
3297 doc.setBaseURI("http://jdom.org/some/path/to/low/level");
3298 Element root = new Element("root");
3299 doc.setRootElement(root);
3300 root.setAttribute("base", "http://jdom2.org/sub/", Namespace.XML_NAMESPACE);
3301 URI uri = root.getXMLBaseURI();
3302 assertTrue(uri != null);
3303 assertEquals("http://jdom2.org/sub/", uri.toASCIIString());
3304 }
3305
3306 @Test
3307 public void testXmlBaseBroken() {
3308 Document doc = new Document();
3309 doc.setBaseURI("http://jdom.org/");
3310 Element root = new Element("root");
3311 doc.setRootElement(root);
3312 root.setAttribute("base", "../ /sub/", Namespace.XML_NAMESPACE);
3313 try {
3314 root.getXMLBaseURI();
3315 UnitTestUtil.failNoException(URISyntaxException.class);
3316 } catch (Exception e) {
3317 UnitTestUtil.checkException(URISyntaxException.class, e);
3318 }
3319 }
3320
3321 }
0 package org.jdom.test.cases;
1
2 import java.util.List;
3
4 import org.jdom.Content;
5 import org.jdom.Element;
6 import org.jdom.filter.ElementFilter;
7 import org.jdom.test.util.AbstractTestList;
8 import org.junit.Before;
9
10 @SuppressWarnings("javadoc")
11 public class TestElementFilterList extends AbstractTestList<Element> {
12
13 private static final Element base = new Element("dummy");
14 private static final Element parent = new Element("parent").addContent(base);
15
16
17 public TestElementFilterList() {
18 super(Element.class, false);
19 }
20
21 @Override
22 public List<Element> buildEmptyList() {
23 base.getContent().clear();
24 return base.getContent(new ElementFilter());
25 }
26
27 @Override
28 public Element[] buildSampleContent() {
29 return new Element[]{ new Element("zero"),
30 new Element("one"), new Element("two"),
31 new Element("three"), new Element("four"),
32 new Element("five"), new Element("six")};
33 }
34
35 @Override
36 public Element[] buildAdditionalContent() {
37 return new Element[]{ new Element("seven"),
38 new Element("eight")};
39 }
40
41 @Override
42 public Object[] buildIllegalClassContent() {
43 Object[] ret = new Object[] {};
44 return ret;
45 }
46
47 @Override
48 public Element[] buildIllegalArgumentContent() {
49 return new Element[]{base, parent};
50 }
51
52 @Before
53 public void detatchAll () {
54 // make sure all content is detatched before each test.
55 for (Content c : buildSampleContent()) {
56 c.detach();
57 }
58 }
59
60 }
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertNull;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.fail;
6
7 import org.jdom.Element;
8 import org.jdom.EntityRef;
9 import org.jdom.IllegalDataException;
10 import org.jdom.IllegalNameException;
11 import org.jdom.test.util.UnitTestUtil;
12 import org.junit.Test;
13
14 @SuppressWarnings("javadoc")
15 public class TestEntityRef {
16
17 @Test
18 public void testEntityRef() {
19 EntityRef er = new EntityRef() {
20 // nothing
21 private static final long serialVersionUID = 200L;
22 };
23 assertTrue(null == er.getPublicID());
24 assertTrue(null == er.getSystemID());
25 assertTrue(null == er.getName());
26 }
27
28 @Test
29 public void testEntityRefString() {
30 EntityRef er = new EntityRef("name");
31 assertTrue("name".equals(er.getName()));
32 assertTrue(null == er.getSystemID());
33 assertTrue(null == er.getPublicID());
34 assertTrue(null == er.getParent());
35 assertTrue(null == er.getParentElement());
36 assertTrue(null == er.getDocument());
37 assertTrue(null != er.toString());
38 }
39
40 @Test
41 public void testEntityRefStringString() {
42 EntityRef er = new EntityRef("name", "systemid");
43 assertTrue("name".equals(er.getName()));
44 assertTrue("systemid".equals(er.getSystemID()));
45 assertTrue(null == er.getPublicID());
46 assertTrue(null == er.getParent());
47 assertTrue(null == er.getParentElement());
48 assertTrue(null == er.getDocument());
49 assertTrue(null != er.toString());
50 }
51
52 @Test
53 public void testEntityRefStringStringString() {
54 EntityRef er = new EntityRef("name", "publicid", "systemid");
55 assertTrue("name".equals(er.getName()));
56 assertTrue("systemid".equals(er.getSystemID()));
57 assertTrue("publicid".equals(er.getPublicID()));
58 assertTrue(null == er.getParent());
59 assertTrue(null == er.getParentElement());
60 assertTrue(null == er.getDocument());
61 assertTrue(null != er.toString());
62 }
63
64 @Test
65 public void testGetValue() {
66 assertTrue("".equals(new EntityRef("name").getValue()));
67 assertTrue("".equals(new EntityRef("name", "systemid").getValue()));
68 assertTrue("".equals(new EntityRef("name", "publicid", "systemid").getValue()));
69 }
70
71 @Test
72 public void testSetName() {
73 EntityRef er = new EntityRef("name", "publicid", "systemid");
74 assertTrue("name".equals(er.getName()));
75 assertTrue("systemid".equals(er.getSystemID()));
76 assertTrue("publicid".equals(er.getPublicID()));
77 assertTrue(er == er.setName("myname"));
78 assertTrue("myname".equals(er.getName()));
79 assertTrue("systemid".equals(er.getSystemID()));
80 assertTrue("publicid".equals(er.getPublicID()));
81 }
82
83 @Test
84 public void testSetPublicID() {
85 EntityRef er = new EntityRef("name", "publicid", "systemid");
86 assertTrue("name".equals(er.getName()));
87 assertTrue("systemid".equals(er.getSystemID()));
88 assertTrue("publicid".equals(er.getPublicID()));
89 assertTrue(er == er.setPublicID("mypublicid"));
90 assertTrue("name".equals(er.getName()));
91 assertTrue("systemid".equals(er.getSystemID()));
92 assertTrue("mypublicid".equals(er.getPublicID()));
93 }
94
95 @Test
96 public void testSetSystemID() {
97 EntityRef er = new EntityRef("name", "publicid", "systemid");
98 assertTrue("name".equals(er.getName()));
99 assertTrue("systemid".equals(er.getSystemID()));
100 assertTrue("publicid".equals(er.getPublicID()));
101 assertTrue(er == er.setSystemID("mysystemid"));
102 assertTrue("name".equals(er.getName()));
103 assertTrue("mysystemid".equals(er.getSystemID()));
104 assertTrue("publicid".equals(er.getPublicID()));
105 }
106
107 @Test
108 public void testToString() {
109 EntityRef er = new EntityRef("name", "publicid", "systemid");
110 assertTrue("name".equals(er.getName()));
111 assertTrue("systemid".equals(er.getSystemID()));
112 assertTrue("publicid".equals(er.getPublicID()));
113 assertTrue(er.toString() != null);
114 }
115
116 @Test
117 public void setIllegals() {
118 EntityRef er = new EntityRef("name", "publicid", "systemid");
119
120 try {
121 er.setName("1234");
122 fail("Should throw Exception");
123 } catch (IllegalNameException ine) {
124 // good
125 } catch (Exception e) {
126 fail("Expeced IllegalNameException, but got " + e.getClass().getName());
127 }
128
129 try {
130 er.setPublicID("1!2!" + (char)0x0c + "3!4");
131 fail("Should throw Exception");
132 } catch (IllegalDataException ine) {
133 // good
134 } catch (Exception e) {
135 fail("Expeced IllegalNameException, but got " + e.getClass().getName());
136 }
137
138 try {
139 er.setSystemID("12" + (char)0x0c + "34");
140 UnitTestUtil.failNoException(IllegalDataException.class);
141 } catch (Exception e) {
142 UnitTestUtil.checkException(IllegalDataException.class, e);
143 }
144 }
145
146 @Test
147 public void testCloneDetatchParentEntityRef() {
148 Element parent = new Element("root");
149 EntityRef content = new EntityRef("val");
150 parent.addContent(content);
151 EntityRef clone = content.detach().clone();
152 assertEquals(content.getValue(), clone.getValue());
153 assertNull(content.getParent());
154 assertNull(clone.getParent());
155 }
156
157 }
0 package org.jdom.test.cases;
1
2 /*--
3
4 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact license@jdom.org.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management (pm@jdom.org).
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Brett McLaughlin <brett@jdom.org> and
51 Jason Hunter <jhunter@jdom.org>. For more information on the
52 JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 /**
57 * Please put a description of your test here.
58 *
59 * @author unascribed
60 * @version 0.1
61 */
62 import static org.junit.Assert.*;
63 import static org.jdom.test.util.UnitTestUtil.*;
64
65 import org.jdom.*;
66 import org.junit.Before;
67 import org.junit.Test;
68 import org.junit.runner.JUnitCore;
69
70 import java.util.*;
71
72 @SuppressWarnings("javadoc")
73 public final class TestFilterList {
74 Element foo;
75 Element bar;
76 Element baz;
77 Element quux;
78 Comment comment;
79 Comment comment2;
80 Comment comment3;
81 Text text1;
82 Text text2;
83 Text text3;
84 Text text4;
85
86 /**
87 * This method is called before a test is executed.
88 */
89 @Before
90 public void setUp() {
91 foo = new Element("foo");
92 bar = new Element("bar");
93 baz = new Element("baz");
94 quux = new Element("quux");
95 comment = new Comment("comment");
96 comment2 = new Comment("comment2");
97 comment3 = new Comment("comment3");
98 text1 = new Text("\n");
99 text2 = new Text("\n");
100 text3 = new Text("\n");
101 text4 = new Text("\n");
102
103 foo.addContent(text1);
104 foo.addContent(bar);
105 foo.addContent(text2);
106 foo.addContent(baz);
107 foo.addContent(text3);
108 foo.addContent(comment);
109 foo.addContent(quux);
110 foo.addContent(text4);
111
112 // Contents of foo are now:
113 // \n, bar, \n, baz, \n, comment, quux, \n
114 }
115
116 /**
117 * The main method runs all the tests in the text ui
118 */
119 public static void main (String args[])
120 {
121 JUnitCore.runClasses(TestFilterList.class);
122 }
123
124 @Test
125 public void test_TCM__int_hashCode() {
126 List<Content> content = foo.getContent();
127 List<Content> content2 = new ArrayList<Content>();
128 content2.addAll(content);
129 assertEquals("bad hashcode", content2.hashCode(), content.hashCode());
130 }
131
132 @Test
133 public void test_TCM__boolean_equals_Object() {
134 List<Content> content = foo.getContent();
135 List<Content> content2 = new ArrayList<Content>();
136 content2.addAll(content);
137 assertTrue("bad equals", content.equals(content2));
138
139 List<Element> children = foo.getChildren();
140 List<Element> children2 = foo.getChildren();
141 assertTrue("bad equals", children.equals(children2));
142 }
143
144 @Test
145 public void test_TCM__int_indexOf_Object() {
146 List<Element> children = foo.getChildren();
147 assertEquals("wrong result from indexOf", 0, children.indexOf(bar));
148 assertEquals("wrong result from indexOf", 1, children.indexOf(baz));
149 assertEquals("wrong result from indexOf", 2, children.indexOf(quux));
150 assertEquals("wrong result from indexOf", -1, children.indexOf(foo));
151 assertEquals("wrong result from indexOf", -1, children.indexOf(text1));
152
153 List<Content> content = foo.getContent();
154 assertEquals("wrong result from indexOf", 0, content.indexOf(text1));
155 assertEquals("wrong result from indexOf", 1, content.indexOf(bar));
156 assertEquals("wrong result from indexOf", 2, content.indexOf(text2));
157 assertEquals("wrong result from indexOf", 3, content.indexOf(baz));
158 assertEquals("wrong result from indexOf", 4, content.indexOf(text3));
159 assertEquals("wrong result from indexOf", 5, content.indexOf(comment));
160 assertEquals("wrong result from indexOf", 6, content.indexOf(quux));
161 assertEquals("wrong result from indexOf", 7, content.indexOf(text4));
162 assertEquals("wrong result from indexOf", -1, content.indexOf(comment2));
163 assertEquals("wrong result from indexOf", -1, content.indexOf(new Integer(17)));
164 }
165
166 @Test
167 public void test_TCM__int_lastIndexOf_Object() {
168 List<Element> children = foo.getChildren();
169 assertEquals("wrong result from lastIndexOf", 0, children.lastIndexOf(bar));
170 assertEquals("wrong result from lastIndexOf", 1, children.lastIndexOf(baz));
171 assertEquals("wrong result from lastIndexOf", 2, children.lastIndexOf(quux));
172 assertEquals("wrong result from lastIndexOf", -1, children.lastIndexOf(text3));
173 assertEquals("wrong result from lastIndexOf", -1, children.lastIndexOf(new Integer(17)));
174
175 List<Content> content = foo.getContent();
176 assertEquals("wrong result from lastIndexOf", 0, content.lastIndexOf(text1));
177 assertEquals("wrong result from lastIndexOf", 1, content.lastIndexOf(bar));
178 assertEquals("wrong result from lastIndexOf", 2, content.lastIndexOf(text2));
179 assertEquals("wrong result from lastIndexOf", 3, content.lastIndexOf(baz));
180 assertEquals("wrong result from lastIndexOf", 4, content.lastIndexOf(text3));
181 assertEquals("wrong result from lastIndexOf", 5, content.lastIndexOf(comment));
182 assertEquals("wrong result from lastIndexOf", 6, content.lastIndexOf(quux));
183 assertEquals("wrong result from lastIndexOf", 7, content.lastIndexOf(text4));
184 assertEquals("wrong result from lastIndexOf", -1, content.lastIndexOf(comment2));
185 assertEquals("wrong result from lastIndexOf", -1, content.lastIndexOf(new Integer(17)));
186 }
187
188 @Test
189 public void test_TCM__Object_get_int() {
190 List<Element> children = foo.getChildren();
191 assertEquals("wrong element from get", bar, children.get(0));
192 assertEquals("wrong element from get", baz, children.get(1));
193 assertEquals("wrong element from get", quux, children.get(2));
194
195 List<Content> content = foo.getContent();
196 assertEquals("wrong element from get", text1, content.get(0));
197 assertEquals("wrong element from get", bar, content.get(1));
198 assertEquals("wrong element from get", text2, content.get(2));
199 assertEquals("wrong element from get", baz, content.get(3));
200 assertEquals("wrong element from get", text3, content.get(4));
201 assertEquals("wrong element from get", comment, content.get(5));
202 assertEquals("wrong element from get", quux, content.get(6));
203 assertEquals("wrong element from get", text4, content.get(7));
204
205 try {
206 children.get(48);
207 fail("Should have thrown an IndexOutOfBoundsException");
208 } catch(IndexOutOfBoundsException ex) {
209 // Do nothing
210 } catch (Exception e) {
211 fail("Unexpected exception " + e.getClass());
212 }
213 try {
214 children.get(-3);
215 fail("Should have thrown an IndexOutOfBoundsException");
216 } catch(IndexOutOfBoundsException ex) {
217 // Do nothing
218 } catch (Exception e) {
219 fail("Unexpected exception " + e.getClass());
220 }
221 try {
222 content.get(48);
223 fail("Should have thrown an IndexOutOfBoundsException");
224 } catch(IndexOutOfBoundsException ex) {
225 // Do nothing
226 } catch (Exception e) {
227 fail("Unexpected exception " + e.getClass());
228 }
229 try {
230 content.get(-3);
231 fail("Should have thrown an IndexOutOfBoundsException");
232 } catch(IndexOutOfBoundsException ex) {
233 // Do nothing
234 } catch (Exception e) {
235 fail("Unexpected exception " + e.getClass());
236 }
237 }
238
239 @Test
240 public void test_TCM__Object_set_int_Object() {
241 List<Element> children = foo.getChildren();
242 List<Content> content = foo.getContent();
243
244 Element blah = new Element("blah");
245 Text text5 = new Text("this was bar");
246 content.set(1, text5);
247 children.set(1, blah);
248
249 assertTrue("parent is not correct", blah.getParent() == foo);
250
251 assertEquals("wrong size", 2, children.size());
252 assertEquals("wrong element from set", baz, children.get(0));
253 assertEquals("wrong element from set", blah, children.get(1));
254
255 assertEquals("wrong size", 8, content.size());
256 assertEquals("wrong element from set", text1, content.get(0));
257 assertEquals("wrong element from set", text5, content.get(1));
258 assertEquals("wrong element from set", text2, content.get(2));
259 assertEquals("wrong element from set", baz, content.get(3));
260 assertEquals("wrong element from set", text3, content.get(4));
261 assertEquals("wrong element from set", comment, content.get(5));
262 assertEquals("wrong element from set", blah, content.get(6));
263 assertEquals("wrong element from set", text4, content.get(7));
264
265 try {
266 children.set(48, new Element("test"));
267 fail("Should have thrown an IndexOutOfBoundsException");
268 } catch(IndexOutOfBoundsException ex) {
269 // Do nothing
270 } catch (Exception e) {
271 fail("Unexpected exception " + e.getClass());
272 }
273 try {
274 children.set(-3, new Element("test"));
275 fail("Should have thrown an IndexOutOfBoundsException");
276 } catch(IndexOutOfBoundsException ex) {
277 // Do nothing
278 } catch (Exception e) {
279 fail("Unexpected exception " + e.getClass());
280 }
281 try {
282 // Jump through hoops to defeat Generics
283 @SuppressWarnings("cast")
284 List<?> tmpa = (List<?>)children;
285 @SuppressWarnings("unchecked")
286 List<Comment> tmpb = (List<Comment>)tmpa;
287 tmpb.set(1, new Comment("test"));
288 failNoException(IllegalAddException.class);
289 } catch (Exception e) {
290 checkException(IllegalAddException.class, e);
291 }
292 try {
293 content.set(48, new Element("test"));
294 fail("Should have thrown an IndexOutOfBoundsException");
295 } catch(IndexOutOfBoundsException ex) {
296 // Do nothing
297 } catch (Exception e) {
298 fail("Unexpected exception " + e.getClass());
299 }
300 try {
301 content.set(-3, new Element("test"));
302 fail("Should have thrown an IndexOutOfBoundsException");
303 } catch(IndexOutOfBoundsException ex) {
304 // Do nothing
305 } catch (Exception e) {
306 fail("Unexpected exception " + e.getClass());
307 }
308
309 try {
310 // Jump through hoops to defeat Generics
311 @SuppressWarnings("cast")
312 List<?> tmpa = (List<?>)content;
313 @SuppressWarnings("unchecked")
314 List<Object> tmpb = (List<Object>)tmpa;
315 tmpb.set(1, new Integer(17));
316 fail("Should have thrown an IllegalArgumentException");
317 } catch(ClassCastException ex) {
318 // Do nothing
319 } catch (Exception e) {
320 fail("Unexpected exception " + e.getClass());
321 }
322 }
323
324 @Test
325 public void test_TCM__void_add_int_Object() {
326 List<Element> children = foo.getChildren();
327 List<Content> content = foo.getContent();
328
329 Element blah = new Element("blah");
330 Text text5 = new Text("this is before bar");
331 content.add(1, text5);
332 children.add(1, blah);
333
334 assertTrue("parent is not correct", blah.getParent() == foo);
335
336 assertEquals("wrong size", 4, children.size());
337 assertEquals("wrong element from add", bar, children.get(0));
338 assertEquals("wrong element from add", blah, children.get(1));
339 assertEquals("wrong element from add", baz, children.get(2));
340 assertEquals("wrong element from add", quux, children.get(3));
341
342 assertEquals("wrong size", 10, content.size());
343 assertEquals("wrong element from add", text1, content.get(0));
344 assertEquals("wrong element from add", text5, content.get(1));
345 assertEquals("wrong element from add", bar, content.get(2));
346 assertEquals("wrong element from add", text2, content.get(3));
347 assertEquals("wrong element from add", blah, content.get(4));
348 assertEquals("wrong element from add", baz, content.get(5));
349 assertEquals("wrong element from add", text3, content.get(6));
350 assertEquals("wrong element from add", comment, content.get(7));
351 assertEquals("wrong element from add", quux, content.get(8));
352 assertEquals("wrong element from add", text4, content.get(9));
353
354 try {
355 children.add(48, new Element("test"));
356 fail("Should have thrown an IndexOutOfBoundsException");
357 } catch(IndexOutOfBoundsException ex) {
358 // Do nothing
359 } catch (Exception e) {
360 fail("Unexpected exception " + e.getClass());
361 }
362 try {
363 children.add(-3, new Element("test"));
364 fail("Should have thrown an IndexOutOfBoundsException");
365 } catch(IndexOutOfBoundsException ex) {
366 // Do nothing
367 } catch (Exception e) {
368 fail("Unexpected exception " + e.getClass());
369 }
370 try {
371 // Jump through hoops to defeat Generics
372 @SuppressWarnings("cast")
373 List<?> tmpa = (List<?>)children;
374 @SuppressWarnings("unchecked")
375 List<Comment> tmpb = (List<Comment>)tmpa;
376 tmpb.add(1, new Comment("test"));
377 failNoException(IllegalAddException.class);
378 } catch (Exception e) {
379 checkException(IllegalAddException.class, e);
380 }
381 try {
382 content.add(48, new Element("test"));
383 fail("Should have thrown an IndexOutOfBoundsException");
384 } catch(IndexOutOfBoundsException ex) {
385 // Do nothing
386 } catch (Exception e) {
387 fail("Unexpected exception " + e.getClass());
388 }
389 try {
390 content.add(-3, new Element("test"));
391 fail("Should have thrown an IndexOutOfBoundsException");
392 } catch(IndexOutOfBoundsException ex) {
393 // Do nothing
394 } catch (Exception e) {
395 fail("Unexpected exception " + e.getClass());
396 }
397 try {
398 // Jump through hoops to defeat Generics
399 @SuppressWarnings("cast")
400 List<?> tmpa = (List<?>)content;
401 @SuppressWarnings("unchecked")
402 List<Integer> tmpb = (List<Integer>)tmpa;
403 tmpb.add(1, new Integer(17));
404 fail("Should have thrown an ClassCastException");
405 } catch(ClassCastException ex) {
406 // Do nothing
407 } catch (Exception e) {
408 fail("Unexpected exception " + e.getClass());
409 }
410 }
411
412 @Test
413 public void test_TCM__boolean_add_Object() {
414 List<Element> children = foo.getChildren();
415 List<Content> content = foo.getContent();
416
417 Element blah = new Element("blah");
418 Text text5 = new Text("this is last");
419 content.add(text5);
420 children.add(blah);
421
422 assertTrue("parent is not correct", blah.getParent() == foo);
423
424 assertEquals("wrong size", 4, children.size());
425 assertEquals("wrong element from add", bar, children.get(0));
426 assertEquals("wrong element from add", baz, children.get(1));
427 assertEquals("wrong element from add", quux, children.get(2));
428 assertEquals("wrong element from add", blah, children.get(3));
429
430 assertEquals("wrong size", 10, content.size());
431 assertEquals("wrong element from add", text1, content.get(0));
432 assertEquals("wrong element from add", bar, content.get(1));
433 assertEquals("wrong element from add", text2, content.get(2));
434 assertEquals("wrong element from add", baz, content.get(3));
435 assertEquals("wrong element from add", text3, content.get(4));
436 assertEquals("wrong element from add", comment, content.get(5));
437 assertEquals("wrong element from add", quux, content.get(6));
438 assertEquals("wrong element from add", text4, content.get(7));
439 assertEquals("wrong element from add", text5, content.get(8));
440 assertEquals("wrong element from add", blah, content.get(9));
441 assertTrue("parent is not correct", comment.getParent() == foo);
442
443 try {
444 // Jump through hoops to defeat Generics
445 @SuppressWarnings("cast")
446 List<?> tmpa = (List<?>)children;
447 @SuppressWarnings("unchecked")
448 List<Comment> tmpb = (List<Comment>)tmpa;
449 tmpb.add(new Comment("test"));
450 failNoException(IllegalAddException.class);
451 } catch (Exception e) {
452 checkException(IllegalAddException.class, e);
453 }
454 try {
455 // Jump through hoops to defeat Generics
456 @SuppressWarnings("cast")
457 List<?> tmpa = (List<?>)content;
458 @SuppressWarnings("unchecked")
459 List<Integer> tmpb = (List<Integer>)tmpa;
460 tmpb.add(new Integer(17));
461 fail("Should have thrown an ClassCastException");
462 } catch(ClassCastException ex) {
463 // Do nothing
464 } catch (Exception e) {
465 fail("Unexpected exception " + e.getClass());
466 }
467 }
468
469 @Test
470 public void testModification() {
471 List<Element> children = foo.getChildren();
472 List<Content> content = foo.getContent();
473
474 modifyFoo();
475
476 // New contents of foo:
477 // \n, comment2, comment3, \n, \n, comment, quux, \n
478
479 assertEquals("wrong size", 1, children.size());
480 assertEquals("wrong element", quux, children.get(0));
481
482 assertEquals("wrong size", 7, content.size());
483 assertEquals("wrong element", text1, content.get(0));
484 assertEquals("wrong element", comment2, content.get(1));
485 assertEquals("wrong element", comment3, content.get(2));
486 assertEquals("wrong element", text3, content.get(3));
487 assertEquals("wrong element", comment, content.get(4));
488 assertEquals("wrong element", quux, content.get(5));
489 assertEquals("wrong element", text4, content.get(6));
490
491 // Make sure that parentage was adjusted correctly.
492 assertNull("parent is not correct", bar.getParent());
493 assertNull("parent is not correct", baz.getParent());
494 assertTrue("parent is not correct", comment.getParent() == foo);
495 assertTrue("parent is not correct", comment2.getParent() == foo);
496 assertTrue("parent is not correct", comment3.getParent() == foo);
497 assertTrue("parent is not correct", quux.getParent() == foo);
498 }
499
500
501 @Test
502 public void test_TCM__int_size() {
503 // Test size on lists.
504 List<Element> children = foo.getChildren();
505 assertEquals("wrong size", 3, children.size());
506 List<Content> content = foo.getContent();
507 assertEquals("wrong size", 8, content.size());
508
509 // Modify
510 modifyFoo();
511
512 // New contents of foo:
513 // \n, comment2, comment3, \n, \n, comment, quux, \n
514
515 // Test size on already-created lists.
516 assertEquals("wrong size", 1, children.size());
517 assertEquals("wrong size", 7, content.size());
518
519 // Test size on newly-created lists.
520 children = foo.getChildren();
521 assertEquals("wrong size", 1, children.size());
522 content = foo.getContent();
523 assertEquals("wrong size", 7, content.size());
524
525 }
526
527 @Test
528 public void testConcurrentModification() {
529 // Get lists.
530 List<Element> children = foo.getChildren();
531 List<Content> content = foo.getContent();
532 // Get iterators.
533 Iterator<Element> iter = children.iterator();
534 Iterator<Content> iter2 = content.iterator();
535
536 // Modify
537 modifyFoo();
538
539 // Try to access an already-existing iterator.
540
541 // Actual List implementations do not throw concurrentmod on the
542 // hasNext/nextIndx methods, only next()
543 // try {
544 // iter.hasNext();
545 // fail("No concurrent modification exception.");
546 // } catch(ConcurrentModificationException ex) {
547 // // Do nothing
548 // } catch (Exception e) {
549 // fail("Unexpected exception " + e.getClass());
550 // }
551
552 // Try to access an already-existing iterator.
553 try {
554 iter2.next();
555 fail("No concurrent modification exception.");
556 } catch(ConcurrentModificationException ex) {
557 // Do nothing
558 } catch (Exception e) {
559 fail("Unexpected exception " + e.getClass());
560 }
561
562 // Try to access a newly-created iterator.
563 iter = children.iterator();
564 iter.hasNext();
565 iter2 = content.iterator();
566 iter2.next();
567
568 assertEquals("wrong size", 1, children.size());
569 assertEquals("wrong size", 7, content.size());
570
571 // Test iterator.remove().
572 Iterator<Element> iter3 = children.iterator();
573 while(iter3.hasNext()) {
574 iter3.next();
575 iter3.remove();
576 }
577
578 assertEquals("wrong size", 0, children.size());
579 assertEquals("wrong size", 6, content.size());
580
581 // Test iterator.remove().
582 iter2 = content.iterator();
583 while(iter2.hasNext()) {
584 iter2.next();
585 iter2.remove();
586 }
587
588 assertEquals("wrong size", 0, children.size());
589 assertEquals("wrong size", 0, content.size());
590 }
591
592 // Modify "foo" a bit.
593 private void modifyFoo() {
594 List<Element> children = foo.getChildren();
595 List<Content> content = foo.getContent();
596 // \n, bar, \n, baz, \n, comment, quux, \n
597
598 children.remove(1); // remove baz
599 assertEquals("wrong size", 2, children.size());
600 assertEquals("wrong size", 7, content.size());
601 // \n, bar, \n, \n, comment, quux, \n
602
603 content.add(1, comment2);
604 assertEquals("wrong size", 2, children.size());
605 assertEquals("wrong size", 8, content.size());
606 // \n, comment2, bar, \n, \n, comment, quux, \n
607
608 content = foo.getContent();
609
610 content.remove(3); // remove \n
611 assertEquals("wrong size", 2, children.size());
612 assertEquals("wrong size", 7, content.size());
613 // \n, comment2, bar, \n, comment, quux, \n
614
615
616 content.set(2, comment3);
617 assertEquals("wrong size", 1, children.size());
618 assertEquals("wrong size", 7, content.size());
619 // \n, comment2, comment3, \n, comment, quux, \n
620 }
621
622 @Test
623 public void test_TCM__ArrayObject_toArray() {
624 List<Element> children = foo.getChildren();
625 List<Content> content = foo.getContent();
626
627 Object[] childrenArray = children.toArray();
628 Object[] contentArray = content.toArray();
629
630 // Make sure they're not live.
631 children.remove(1);
632 content.remove(comment);
633
634 assertArrays(childrenArray, contentArray);
635 }
636
637 @Test
638 public void test_TCM__ArrayObject_toArray_ArrayObject() {
639 List<Element> children = foo.getChildren();
640 List<Content> content = foo.getContent();
641
642 // These arrays are big enough, and don't need to be expanded.
643 Object[] childrenArray = new Object[children.size()];
644 Object[] contentArray = new Object[99];
645 children.toArray(childrenArray);
646 content.toArray(contentArray);
647
648 assertEquals("bad toArray size", childrenArray.length, 3);
649 assertEquals("bad toArray size", contentArray.length, 99);
650 assertArrays(childrenArray, contentArray);
651
652
653 // These arrays aren't big enough, and do need to be expanded.
654 childrenArray = new Object[1];
655 contentArray = new Object[2];
656 childrenArray = children.toArray(childrenArray);
657 contentArray = content.toArray(contentArray);
658
659 // Make sure they're not live.
660 children.remove(baz);
661 content.remove(1);
662
663 assertEquals("bad toArray size", childrenArray.length, 3);
664 assertEquals("bad toArray size", contentArray.length, 8);
665 assertArrays(childrenArray, contentArray);
666 }
667
668 private void assertArrays(Object[] childrenArray, Object[] contentArray)
669 {
670 assertEquals("bad toArray", bar, childrenArray[0]);
671 assertEquals("bad toArray", baz, childrenArray[1]);
672 assertEquals("bad toArray", quux, childrenArray[2]);
673
674 assertEquals("bad toArray", text1, contentArray[0]);
675 assertEquals("bad toArray", bar, contentArray[1]);
676 assertEquals("bad toArray", text2, contentArray[2]);
677 assertEquals("bad toArray", baz, contentArray[3]);
678 assertEquals("bad toArray", text3, contentArray[4]);
679 assertEquals("bad toArray", comment, contentArray[5]);
680 assertEquals("bad toArray", quux, contentArray[6]);
681 assertEquals("bad toArray", text4, contentArray[7]);
682 }
683
684 @Test
685 public void test_TCM__boolean_contains_Object() {
686 List<Content> content = foo.getContent();
687 List<Element> children = foo.getChildren();
688
689 assertTrue("bad contains", !content.contains(foo));
690 assertTrue("bad contains", content.contains(bar));
691 assertTrue("bad contains", content.contains(baz));
692 assertTrue("bad contains", content.contains(quux));
693 assertTrue("bad contains", content.contains(comment));
694 assertTrue("bad contains", content.contains(text1));
695 assertTrue("bad contains", content.contains(text2));
696 assertTrue("bad contains", content.contains(text3));
697 assertTrue("bad contains", content.contains(text4));
698 assertTrue("bad contains", !content.contains(comment2));
699 assertTrue("bad contains", !content.contains(new Integer(17)));
700
701 assertTrue("bad contains", !children.contains(foo));
702 assertTrue("bad contains", children.contains(bar));
703 assertTrue("bad contains", children.contains(baz));
704 assertTrue("bad contains", children.contains(quux));
705 assertTrue("bad contains", !children.contains(comment));
706 assertTrue("bad contains", !children.contains(text1));
707 assertTrue("bad contains", !children.contains(text2));
708 assertTrue("bad contains", !children.contains(text3));
709 assertTrue("bad contains", !children.contains(text4));
710 assertTrue("bad contains", !children.contains(comment2));
711 assertTrue("bad contains", !children.contains(new Integer(17)));
712 }
713
714 @Test
715 public void test_TCM__void_clear() {
716 List<Content> content = foo.getContent();
717 List<Element> children = foo.getChildren();
718
719 children.clear();
720
721 assertEquals("bad clear", 0, children.size());
722 assertEquals("bad clear", 5, content.size());
723 assertTrue("bad clear", content.get(0).equals(text1));
724 assertTrue("bad clear", content.get(1).equals(text2));
725 assertTrue("bad clear", content.get(2).equals(text3));
726 assertTrue("bad clear", content.get(3) == comment);
727 assertTrue("bad clear", content.get(4).equals(text4));
728
729 assertTrue("parent is not correct", comment.getParent() == foo);
730 assertNull("parent is not correct", bar.getParent());
731 assertNull("parent is not correct", baz.getParent());
732 assertNull("parent is not correct", quux.getParent());
733
734 content.clear();
735
736 assertTrue("bad clear", children.size() == 0);
737 assertTrue("bad clear", content.size() == 0);
738
739 assertNull("parent is not correct", comment.getParent());
740 assertNull("parent is not correct", bar.getParent());
741 assertNull("parent is not correct", baz.getParent());
742 assertNull("parent is not correct", quux.getParent());
743
744 }
745
746 @Test
747 public void test_TCM__Object_remove_int() {
748 List<Content> content = foo.getContent();
749 List<Element> children = foo.getChildren();
750
751 // \n, bar, \n, baz, \n, comment, quux, \n
752 content.remove(4); // third /n
753 children.remove(0); // bar
754 content.remove(3); // comment
755 content.remove(0); // first /n
756 // \n, baz, quux, \n
757
758 assertTrue("bad removal", children.size() == 2);
759 assertTrue("bad removal", children.get(0) == baz);
760 assertTrue("bad removal", children.get(1) == quux);
761 assertTrue("bad removal", content.size() == 4);
762 assertTrue("bad removal", content.get(0).equals(text2));
763 assertTrue("bad removal", content.get(1) == baz);
764 assertTrue("bad removal", content.get(2) == quux);
765 assertTrue("bad removal", content.get(3).equals(text4));
766
767 assertNull("parent is not correct", bar.getParent());
768 assertTrue("parent is not correct", baz.getParent() == foo);
769 assertTrue("parent is not correct", quux.getParent() == foo);
770 assertNull("parent is not correct", comment.getParent());
771
772 try {
773 children.remove(48);
774 fail("Should have thrown an IndexOutOfBoundsException");
775 } catch(IndexOutOfBoundsException ex) {
776 // Do nothing
777 } catch (Exception e) {
778 fail("Unexpected exception " + e.getClass());
779 }
780 try {
781 children.remove(-3);
782 fail("Should have thrown an IndexOutOfBoundsException");
783 } catch(IndexOutOfBoundsException ex) {
784 // Do nothing
785 } catch (Exception e) {
786 fail("Unexpected exception " + e.getClass());
787 }
788 try {
789 content.remove(48);
790 fail("Should have thrown an IndexOutOfBoundsException");
791 } catch(IndexOutOfBoundsException ex) {
792 // Do nothing
793 } catch (Exception e) {
794 fail("Unexpected exception " + e.getClass());
795 }
796 try {
797 content.remove(-3);
798 fail("Should have thrown an IndexOutOfBoundsException");
799 } catch(IndexOutOfBoundsException ex) {
800 // Do nothing
801 } catch (Exception e) {
802 fail("Unexpected exception " + e.getClass());
803 }
804 }
805
806 @Test
807 public void test_TCM__boolean_remove_Object() {
808 List<Content> content = foo.getContent();
809 List<Element> children = foo.getChildren();
810
811 // contents: \n, bar, \n, baz, \n, comment, quux, \n
812 assertTrue("bad removal", content.remove(text1)); // first /n
813 assertTrue("bad removal", children.remove(bar)); // bar
814 assertTrue("bad removal", content.remove(comment)); // comment
815 assertTrue("bad removal", content.remove(text2)); // second /n
816 // contents: baz, \n, quux, \n
817
818 // None of these should have any effect.
819 assertTrue("bad removal", !children.remove(bar));
820 assertTrue("bad removal", !children.remove(text2));
821 assertTrue("bad removal", !children.remove(comment2));
822 assertTrue("bad removal", !children.remove(new Integer(17)));
823 assertTrue("bad removal", !content.remove(bar));
824 assertTrue("bad removal", !content.remove(comment2));
825 assertTrue("bad removal", !content.remove(new Integer(17)));
826
827 assertTrue("bad removal", children.size() == 2);
828 assertTrue("bad removal", children.get(0) == baz);
829 assertTrue("bad removal", children.get(1) == quux);
830 assertTrue("bad removal", content.size() == 4);
831 assertTrue("bad removal", content.get(0) == baz);
832 assertTrue("bad removal", content.get(1).equals(text3));
833 assertTrue("bad removal", content.get(2) == quux);
834 assertTrue("bad removal", content.get(3).equals(text4));
835
836 assertNull("parent is not correct", bar.getParent());
837 assertTrue("parent is not correct", baz.getParent() == foo);
838 assertTrue("parent is not correct", quux.getParent() == foo);
839 assertNull("parent is not correct", comment.getParent());
840 }
841
842 @Test
843 public void test_TCM__boolean_isEmpty() {
844 List<Element> children = foo.getChildren();
845 int size = children.size();
846 for (int i = 0; i < size; i++)
847 {
848 assertFalse("bad isEmpty", children.isEmpty());
849 children.remove(0);
850 }
851
852 assertTrue("bad isEmpty", children.isEmpty());
853 }
854
855 @Test
856 public void test_TCM__boolean_containsAll_Collection() {
857 List<Content> content = foo.getContent();
858 List<Content> contentList = new ArrayList<Content>();
859 contentList.add(quux);
860 contentList.add(baz);
861 contentList.add(text3);
862 contentList.add(text1);
863 contentList.add(text2);
864 contentList.add(comment);
865 assertTrue("bad containsAll", content.containsAll(contentList));
866 contentList.add(bar);
867 contentList.add(text4);
868 assertTrue("bad containsAll", content.containsAll(contentList));
869 contentList.add(comment2);
870 assertFalse("bad containsAll", content.containsAll(contentList));
871
872 List<Element> children = foo.getChildren();
873 List<Object> childrenList = new ArrayList<Object>();
874 childrenList.add(baz);
875 assertTrue("bad containsAll", children.containsAll(childrenList));
876 childrenList.add(bar);
877 childrenList.add(quux);
878 assertTrue("bad containsAll", children.containsAll(childrenList));
879 childrenList.add(comment);
880 assertFalse("bad containsAll", children.containsAll(childrenList));
881 }
882
883 @Test
884 public void test_TCM__boolean_addAll_Collection() {
885 List<Content> content = foo.getContent();
886 List<Content> addList = new ArrayList<Content>();
887 addList.add(comment2);
888 addList.add(comment3);
889 content.addAll(addList);
890 assertEquals("bad addAll", 10, content.size());
891 assertEquals("bad addAll", text1, content.get(0));
892 assertEquals("bad addAll", bar, content.get(1));
893 assertEquals("bad addAll", text2, content.get(2));
894 assertEquals("bad addAll", baz, content.get(3));
895 assertEquals("bad addAll", text3, content.get(4));
896 assertEquals("bad addAll", comment, content.get(5));
897 assertEquals("bad addAll", quux, content.get(6));
898 assertEquals("bad addAll", text4, content.get(7));
899 assertEquals("bad addAll", comment2, content.get(8));
900 assertEquals("bad addAll", comment3, content.get(9));
901 assertEquals("bad addAll", foo, comment2.getParent());
902 assertEquals("bad addAll", foo, comment3.getParent());
903 try {
904 content.addAll(addList);
905 fail("Should have thrown an IllegalArgumentException");
906 } catch(IllegalArgumentException ex) {
907 // Do nothing
908 } catch (Exception e) {
909 fail("Unexpected exception " + e.getClass());
910 }
911
912 List<Element> children = foo.getChildren();
913 List<Element> addList2 = new ArrayList<Element>();
914 Element newElement = new Element("newelement");
915 Element newElement2 = new Element("newelement2");
916 addList2.add(newElement);
917 addList2.add(newElement2);
918 children.addAll(addList2);
919 assertEquals("bad addAll", 5, children.size());
920 assertEquals("bad addAll", bar, children.get(0));
921 assertEquals("bad addAll", baz, children.get(1));
922 assertEquals("bad addAll", quux, children.get(2));
923 assertEquals("bad addAll", newElement, children.get(3));
924 assertEquals("bad addAll", newElement2, children.get(4));
925 assertEquals("bad addAll", foo, newElement.getParent());
926 assertEquals("bad addAll", foo, newElement2.getParent());
927 try {
928 children.addAll(addList2);
929 fail("Should have thrown an IllegalArgumentException");
930 } catch(IllegalArgumentException ex) {
931 // Do nothing
932 } catch (Exception e) {
933 fail("Unexpected exception " + e.getClass());
934 }
935 }
936
937 @Test
938 public void test_TCM__boolean_addAll_int_Collection() {
939 List<Content> content = foo.getContent();
940 List<Content> addList = new ArrayList<Content>();
941 addList.add(comment2);
942 addList.add(comment3);
943 content.addAll(2, addList);
944 assertEquals("bad addAll", 10, content.size());
945 assertEquals("bad addAll", text1, content.get(0));
946 assertEquals("bad addAll", bar, content.get(1));
947 assertEquals("bad addAll", comment2, content.get(2));
948 assertEquals("bad addAll", comment3, content.get(3));
949 assertEquals("bad addAll", text2, content.get(4));
950 assertEquals("bad addAll", baz, content.get(5));
951 assertEquals("bad addAll", text3, content.get(6));
952 assertEquals("bad addAll", comment, content.get(7));
953 assertEquals("bad addAll", quux, content.get(8));
954 assertEquals("bad addAll", text4, content.get(9));
955 assertEquals("bad addAll", foo, comment2.getParent());
956 assertEquals("bad addAll", foo, comment3.getParent());
957 try {
958 content.addAll(2, addList);
959 fail("Should have thrown an IllegalArgumentException");
960 } catch(IllegalArgumentException ex) {
961 // Do nothing
962 } catch (Exception e) {
963 fail("Unexpected exception " + e.getClass());
964 }
965
966 List<Element> children = foo.getChildren();
967 List<Element> addList2 = new ArrayList<Element>();
968 Element newElement = new Element("newelement");
969 Element newElement2 = new Element("newelement2");
970 addList2.add(newElement);
971 addList2.add(newElement2);
972 children.addAll(0, addList2);
973 assertEquals("bad addAll", 5, children.size());
974 assertEquals("bad addAll", newElement, children.get(0));
975 assertEquals("bad addAll", newElement2, children.get(1));
976 assertEquals("bad addAll", bar, children.get(2));
977 assertEquals("bad addAll", baz, children.get(3));
978 assertEquals("bad addAll", quux, children.get(4));
979 assertEquals("bad addAll", foo, newElement.getParent());
980 assertEquals("bad addAll", foo, newElement2.getParent());
981 try {
982 children.addAll(0, addList2);
983 fail("Should have thrown an IllegalArgumentException");
984 } catch(IllegalArgumentException ex) {
985 // Do nothing
986 } catch (Exception e) {
987 fail("Unexpected exception " + e.getClass());
988 }
989 }
990
991 @Test
992 public void test_TCM__boolean_removeAll_Collection() {
993 List<Content> content = foo.getContent();
994 List<Object> removeList = new ArrayList<Object>();
995 removeList.add(text4);
996 removeList.add(comment);
997 removeList.add(bar);
998 removeList.add(new Integer(17)); // should have no effect.
999 content.removeAll(removeList);
1000 assertEquals("bad removeAll", 5, content.size());
1001 assertEquals("bad removeAll", text1, content.get(0));
1002 assertEquals("bad removeAll", text2, content.get(1));
1003 assertEquals("bad removeAll", baz, content.get(2));
1004 assertEquals("bad removeAll", text3, content.get(3));
1005 assertEquals("bad removeAll", quux, content.get(4));
1006 assertEquals("bad removeAll", null, text4.getParent());
1007 assertEquals("bad removeAll", null, comment.getParent());
1008 assertEquals("bad removeAll", null, bar.getParent());
1009
1010 List<Element> children = foo.getChildren();
1011 List<Object> removeList2 = new ArrayList<Object>();
1012 removeList2.add(baz);
1013 removeList2.add(quux);
1014 removeList2.add(new Integer(17)); // should have no effect.
1015 children.removeAll(removeList2);
1016 assertEquals("bad removeAll", 0, children.size());
1017 assertEquals("bad removeAll", null, baz.getParent());
1018 assertEquals("bad removeAll", null, quux.getParent());
1019 }
1020
1021 @Test
1022 public void test_TCM__boolean_retainAll_Collection() {
1023 List<Content> content = foo.getContent();
1024 List<Object> retainList = new ArrayList<Object>();
1025 retainList.add(text3);
1026 retainList.add(quux);
1027 retainList.add(text1);
1028 retainList.add(baz);
1029 retainList.add(text2);
1030 content.retainAll(retainList);
1031 assertEquals("bad retainAll", 5, content.size());
1032 assertEquals("bad retainAll", text1, content.get(0));
1033 assertEquals("bad retainAll", text2, content.get(1));
1034 assertEquals("bad retainAll", baz, content.get(2));
1035 assertEquals("bad retainAll", text3, content.get(3));
1036 assertEquals("bad retainAll", quux, content.get(4));
1037 assertEquals("bad retainAll", null, text4.getParent());
1038 assertEquals("bad retainAll", null, comment.getParent());
1039 assertEquals("bad retainAll", null, bar.getParent());
1040
1041 List<Element> children = foo.getChildren();
1042 List<Element> retainList2 = new ArrayList<Element>();
1043 retainList2.add(baz);
1044 children.retainAll(retainList2);
1045 assertEquals("bad retainAll", 1, children.size());
1046 assertEquals("bad retainAll", null, quux.getParent());
1047 }
1048
1049 @Test
1050 public void test_TCM__List_subList_int_int() {
1051 List<Element> children = foo.getChildren();
1052 List<Content> content = foo.getContent();
1053
1054 List<Content> contentSublist = content.subList(3, 7); // baz, text3, comment, quux
1055 contentSublist.add(comment2);
1056 assertEquals("bad subList", 5, contentSublist.size());
1057 assertEquals("bad subList", baz, contentSublist.get(0));
1058 assertEquals("bad subList", text3, contentSublist.get(1));
1059 assertEquals("bad subList", comment, contentSublist.get(2));
1060 assertEquals("bad subList", quux, contentSublist.get(3));
1061 assertEquals("bad subList", comment2, contentSublist.get(4));
1062
1063 List<Element> childrenSublist = children.subList(0, 2); // bar, baz
1064 childrenSublist.remove(0);
1065 assertEquals("bad subList", 1, childrenSublist.size());
1066 assertEquals("bad subList", baz, childrenSublist.get(0));
1067
1068 assertEquals("wrong element from get", baz, children.get(0));
1069 assertEquals("wrong element from get", quux, children.get(1));
1070
1071 assertEquals("wrong element from get", text1, content.get(0));
1072 assertEquals("wrong element from get", text2, content.get(1));
1073 assertEquals("wrong element from get", baz, content.get(2));
1074 assertEquals("wrong element from get", text3, content.get(3));
1075 assertEquals("wrong element from get", comment, content.get(4));
1076 assertEquals("wrong element from get", quux, content.get(5));
1077 assertEquals("wrong element from get", comment2, content.get(6));
1078 assertEquals("wrong element from get", text4, content.get(7));
1079 }
1080
1081
1082 // We'll assume that this is a decent test of iterator(),
1083 // listIterator(), and listIterator(int).
1084 @Test
1085 public void test_TCM__ListIterator_listIterator_int() {
1086 List<Element> children = foo.getChildren();
1087 ListIterator<Element> iter = children.listIterator(1);
1088
1089 // next
1090 assertTrue("hasPrevious is false", iter.hasPrevious());
1091 assertTrue("hasNext is false", iter.hasNext());
1092 assertEquals("wrong element from get", baz, iter.next());
1093 assertTrue("hasNext is false", iter.hasNext());
1094 assertEquals("wrong element from get", quux, iter.next());
1095 assertFalse("hasNext is true", iter.hasNext());
1096
1097 // prev
1098 assertTrue("hasPrevious is false", iter.hasPrevious());
1099 assertEquals("wrong element from get", quux, iter.previous());
1100 assertTrue("hasPrevious is false", iter.hasPrevious());
1101 assertEquals("wrong element from get", baz, iter.previous());
1102 assertTrue("hasPrevious is false", iter.hasPrevious());
1103 assertEquals("wrong element from get", bar, iter.previous());
1104 assertFalse("hasPrevious is true", iter.hasPrevious());
1105 assertTrue("hasNext is false", iter.hasNext());
1106
1107 List<Content> content = foo.getContent();
1108 ListIterator<Content> iter2 = content.listIterator(1);
1109
1110 // next
1111 assertTrue("hasPrevious is false", iter2.hasPrevious());
1112 assertTrue("hasNext is false", iter2.hasNext());
1113 assertEquals("wrong element from get", bar, iter2.next());
1114 assertTrue("hasNext is false", iter2.hasNext());
1115 assertEquals("wrong element from get", text2, iter2.next());
1116 assertTrue("hasNext is false", iter2.hasNext());
1117 assertEquals("wrong element from get", baz, iter2.next());
1118 assertTrue("hasNext is false", iter2.hasNext());
1119 assertEquals("wrong element from get", text3, iter2.next());
1120 assertTrue("hasNext is false", iter2.hasNext());
1121 assertEquals("wrong element from get", comment, iter2.next());
1122 assertTrue("hasNext is false", iter2.hasNext());
1123 assertEquals("wrong element from get", quux, iter2.next());
1124 assertTrue("hasNext is false", iter2.hasNext());
1125 assertEquals("wrong element from get", text4, iter2.next());
1126 assertFalse("hasNext is true", iter2.hasNext());
1127
1128 // prev
1129 assertTrue("hasPrevious is false", iter2.hasPrevious());
1130 assertEquals("wrong element from get", text4, iter2.previous());
1131 assertTrue("hasPrevious is false", iter2.hasPrevious());
1132 assertEquals("wrong element from get", quux, iter2.previous());
1133 assertTrue("hasPrevious is false", iter2.hasPrevious());
1134 assertEquals("wrong element from get", comment, iter2.previous());
1135 assertTrue("hasPrevious is false", iter2.hasPrevious());
1136 assertEquals("wrong element from get", text3, iter2.previous());
1137 assertTrue("hasPrevious is false", iter2.hasPrevious());
1138 assertEquals("wrong element from get", baz, iter2.previous());
1139 assertTrue("hasPrevious is false", iter2.hasPrevious());
1140 assertEquals("wrong element from get", text2, iter2.previous());
1141 assertTrue("hasPrevious is false", iter2.hasPrevious());
1142 assertEquals("wrong element from get", bar, iter2.previous());
1143 assertTrue("hasPrevious is false", iter2.hasPrevious());
1144 assertEquals("wrong element from get", text1, iter2.previous());
1145 assertFalse("hasPrevious is true", iter2.hasPrevious());
1146 assertTrue("hasNext is false", iter2.hasNext());
1147
1148 try {
1149 children.listIterator(48);
1150 fail("Should have thrown an IndexOutOfBoundsException");
1151 } catch(IndexOutOfBoundsException ex) {
1152 // Do nothing
1153 } catch (Exception e) {
1154 fail("Unexpected exception " + e.getClass());
1155 }
1156 try {
1157 children.listIterator(-3);
1158 fail("Should have thrown an IndexOutOfBoundsException");
1159 } catch(IndexOutOfBoundsException ex) {
1160 // Do nothing
1161 } catch (Exception e) {
1162 fail("Unexpected exception " + e.getClass());
1163 }
1164 try {
1165 content.listIterator(48);
1166 fail("Should have thrown an IndexOutOfBoundsException");
1167 } catch(IndexOutOfBoundsException ex) {
1168 // Do nothing
1169 } catch (Exception e) {
1170 fail("Unexpected exception " + e.getClass());
1171 }
1172 try {
1173 content.listIterator(-3);
1174 fail("Should have thrown an IndexOutOfBoundsException");
1175 } catch(IndexOutOfBoundsException ex) {
1176 // Do nothing
1177 } catch (Exception e) {
1178 fail("Unexpected exception " + e.getClass());
1179 }
1180 }
1181
1182 @Test
1183 public void test_TCM__ListIterator_listIterator_int2() {
1184 List<Element> children = foo.getChildren();
1185 ListIterator<Element> iter = children.listIterator(1);
1186
1187 assertTrue("hasPrevious is false", iter.hasPrevious());
1188 assertTrue("hasPrevious is false", iter.hasPrevious());
1189 assertTrue("hasNext is false", iter.hasNext());
1190 assertTrue("hasNext is false", iter.hasNext());
1191 assertEquals("wrong element from get", baz, iter.next());
1192 assertEquals("wrong element from get", baz, iter.previous());
1193 assertEquals("wrong element from get", baz, iter.next());
1194 assertEquals("wrong element from get", baz, iter.previous());
1195 assertTrue("hasPrevious is false", iter.hasPrevious());
1196 assertTrue("hasPrevious is false", iter.hasPrevious());
1197 assertEquals("wrong element from get", bar, iter.previous());
1198 assertEquals("wrong element from get", bar, iter.next());
1199 assertEquals("wrong element from get", bar, iter.previous());
1200 assertFalse("hasPrevious is true", iter.hasPrevious());
1201 assertFalse("hasPrevious is true", iter.hasPrevious());
1202 assertTrue("hasNext is false", iter.hasNext());
1203 assertTrue("hasNext is false", iter.hasNext());
1204
1205 List<Content> content = foo.getContent();
1206 ListIterator<Content> iter2 = content.listIterator(1);
1207
1208 // next
1209 assertEquals("wrong element from get", bar, iter2.next());
1210 assertEquals("wrong element from get", text2, iter2.next());
1211 assertTrue("hasNext is false", iter2.hasNext());
1212 assertTrue("hasNext is false", iter2.hasNext());
1213 assertEquals("wrong element from get", baz, iter2.next());
1214 assertTrue("hasNext is false", iter2.hasNext());
1215 assertTrue("hasNext is false", iter2.hasNext());
1216 assertEquals("wrong element from get", text3, iter2.next());
1217 assertEquals("wrong element from get", comment, iter2.next());
1218 assertTrue("hasNext is false", iter2.hasNext());
1219 assertTrue("hasNext is false", iter2.hasNext());
1220 assertEquals("wrong element from get", quux, iter2.next());
1221 assertEquals("wrong element from get", quux, iter2.previous());
1222 assertEquals("wrong element from get", comment, iter2.previous());
1223 assertEquals("wrong element from get", text3, iter2.previous());
1224 assertEquals("wrong element from get", baz, iter2.previous());
1225 assertTrue("hasPrevious is false", iter2.hasPrevious());
1226 assertTrue("hasPrevious is false", iter2.hasNext());
1227 assertEquals("wrong element from get", text2, iter2.previous());
1228 assertTrue("hasPrevious is false", iter2.hasPrevious());
1229 assertTrue("hasPrevious is false", iter2.hasNext());
1230 assertEquals("wrong element from get", text2, iter2.next());
1231 assertTrue("hasPrevious is false", iter2.hasPrevious());
1232 assertTrue("hasPrevious is false", iter2.hasNext());
1233 assertEquals("wrong element from get", text2, iter2.previous());
1234 assertTrue("hasPrevious is false", iter2.hasPrevious());
1235 assertTrue("hasPrevious is false", iter2.hasPrevious());
1236 assertEquals("wrong element from get", bar, iter2.previous());
1237 assertEquals("wrong element from get", text1, iter2.previous());
1238 assertTrue("hasNext is false", iter2.hasNext());
1239 assertTrue("hasNext is false", iter2.hasNext());
1240 }
1241
1242 // When we add the first attribute or child, or when we replace the list of
1243 // attributes or children, we may replace the underlying list reference
1244 // in the Element. We need to make sure that any previously-created FilterLists
1245 // somehow get updated.
1246 @Test
1247 public void test_list_replacement() {
1248 Element el = new Element("parent");
1249
1250 List<Attribute> attr = el.getAttributes();
1251 el.setAttribute("test", "test");
1252 assertEquals("wrong list size after adding attribute", 1, attr.size());
1253 ArrayList<Attribute> attr2 = new ArrayList<Attribute>();
1254 attr2.add(new Attribute("test", "test"));
1255 attr2.add(new Attribute("test2", "test2"));
1256 el.setAttributes(attr2);
1257 assertEquals("wrong list size after replacing attribute", 2, attr.size());
1258
1259 List<Content> content = el.getContent();
1260 el.addContent(new Element("test"));
1261 assertEquals("wrong list size after adding content", 1, content.size());
1262 ArrayList<Content> content2 = new ArrayList<Content>();
1263 content2.add(new Element("test"));
1264 content2.add(new Element("test2"));
1265 el.setContent(content2);
1266 content.size();
1267 assertEquals("wrong list size after replacing content", 2, content.size());
1268 }
1269
1270 @Test
1271 public void test_TCM__ListIterator_listIterator_int3() {
1272 try {
1273 Element r = new Element("root");
1274 new Document().setRootElement(r);
1275 r.addContent(new Element("element").setText("1"));
1276 r.addContent(new Element("element").setText("2"));
1277 r.addContent(new Element("element").setText("3"));
1278
1279 Element xxx = new Element("element").setText("xxx");
1280 Element yyy = new Element("element").setText("yyy");
1281
1282 ListIterator<Element> i = r.getChildren("element").listIterator();
1283 while (i.hasNext()) {
1284 Element e = i.next();
1285 i.add(new Element("element").setText(e.getText() + "_x"));
1286 i.add(new Element("element").setText(e.getText() + "_y")); // bug1 - double add should work
1287 }
1288 i.add(xxx); // bug2 - add at end of list....
1289 assertEquals("previous() is not recent add()", xxx, i.previous());
1290 i.set(yyy);
1291 assertEquals("yyy not attached", r, yyy.getParent());
1292 assertFalse("xxx is still attached", xxx.isAncestor(r));
1293
1294 i.remove();
1295
1296 } catch (OutOfMemoryError oom) {
1297 System.gc();
1298 oom.printStackTrace();
1299 fail("ListIterator.add() caused OutOfMemory!");
1300 } catch (Exception e) {
1301 e.printStackTrace();
1302 fail("Unable to complete ListIterator tests");
1303 }
1304 }
1305
1306 @Test
1307 public void testSpecialCaseLotsOfDataAdded() {
1308 // we need to ensure that the FilterList expands correctly when the
1309 // base list is expanded...
1310 Element root = new Element("root");
1311 final int size = 40;
1312 final int mid = size / 2;
1313 Element[] kids = new Element[size];
1314 for (int i = 0; i < mid; i++) {
1315 kids[i] = new Element("kid");
1316 root.addContent(kids[i]);
1317 }
1318 List<Element> kidl = root.getChildren("kid");
1319 assertTrue(kidl.size() == mid);
1320 for (int i = 0; i < mid; i++) {
1321 assertTrue(kids[i] == kidl.get(i));
1322 }
1323
1324 // OK, here is the real test, the FilterList has been set with a base
1325 // size of 'mid', but we now add a bucnh more stuff, we need to make
1326 // sure it stays 'live' appropriately.
1327 for (int i = mid; i < size; i++) {
1328 kids[i] = new Element("kid");
1329 root.addContent(kids[i]);
1330 }
1331
1332 // and finally, the test..... make sure the kidl contains all members.
1333 int c = 0;
1334 for (Element k : kidl) {
1335 assertTrue(kids[c++] == k);
1336 }
1337 assertTrue(c == size);
1338 }
1339
1340 }
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.assertTrue;
3
4 import java.util.Iterator;
5 import java.util.List;
6
7 import org.junit.Test;
8
9 import org.jdom.Element;
10 import org.jdom.Namespace;
11 import org.jdom.test.util.AbstractTestList;
12
13 @SuppressWarnings("javadoc")
14 public class TestFilterListElement extends AbstractTestList<Element> {
15
16 public TestFilterListElement() {
17 super(Element.class, false);
18 }
19
20 @Override
21 public List<Element> buildEmptyList() {
22 Element root = new Element("root");
23 return root.getChildren(null, Namespace.getNamespace("kidnamespace"));
24 }
25
26 @Override
27 public Element[] buildSampleContent() {
28 Namespace kns = Namespace.getNamespace("kidnamespace");
29 return new Element[] {
30 new Element("kida", kns),
31 new Element("kidb", kns),
32 new Element("kidc", kns),
33 new Element("kidd", kns),
34 new Element("kide", kns),
35 new Element("kidf", kns),
36 new Element("kidg", kns),
37 new Element("kidh", kns),
38 new Element("kidi", kns),
39 new Element("kidj", kns),
40 };
41 }
42
43 @Override
44 public Element[] buildAdditionalContent() {
45 Namespace kns = Namespace.getNamespace("kidnamespace");
46 return new Element[]{ new Element("kidk", kns),
47 new Element("kidl", kns)};
48 }
49
50 @Override
51 public Element[] buildIllegalArgumentContent() {
52 // illegal for the filter because it has the wrong namespace.
53 Element kid = new Element("kid");
54 return new Element[] { kid };
55 }
56
57 @Override
58 public Object[] buildIllegalClassContent() {
59 return new Object[] {};
60 }
61
62
63 /**
64 * Issue #81 - multiple concurrent 'open' FilterLIsts do not re-sync on remove....
65 */
66 @Test
67 public void testMultiLists() {
68 Element root = new Element("root");
69 root.addContent(new Element("A"));
70 root.addContent(new Element("B"));
71 root.addContent(new Element("C"));
72 root.addContent(new Element("A"));
73 root.addContent(new Element("B"));
74 root.addContent(new Element("C"));
75 root.addContent(new Element("A"));
76 root.addContent(new Element("B"));
77 root.addContent(new Element("C"));
78 root.addContent(new Element("A"));
79 root.addContent(new Element("B"));
80 root.addContent(new Element("C"));
81
82 List<Element> as = root.getChildren("A");
83 List<Element> bs = root.getChildren("B");
84 List<Element> cs = root.getChildren("C");
85
86 for (Element f : as) {
87 assertTrue("A".equals(f.getName()));
88 }
89 for (Element f : bs) {
90 assertTrue("B".equals(f.getName()));
91 }
92 for (Element f : cs) {
93 assertTrue("C".equals(f.getName()));
94 }
95
96 final int bsz = bs.size();
97 final int csz = cs.size();
98
99 while (!as.isEmpty()) {
100
101 final int sz = as.size() - 1;
102 Element e = as.get(0);
103 as.remove(e);
104
105 assertTrue(sz == as.size());
106 assertTrue(bsz == bs.size());
107 assertTrue(csz == cs.size());
108
109 for (Element f : as) {
110 assertTrue("A".equals(f.getName()));
111 }
112 for (Iterator<Element> bi = bs.iterator(); bi.hasNext();) {
113 assertTrue("B".equals(bi.next().getName()));
114 }
115 for (Element f : cs) {
116 assertTrue("C".equals(f.getName()));
117 }
118 }
119
120
121 }
122 }
0 package org.jdom.test.cases;
1
2 import java.util.List;
3
4 import org.jdom.Element;
5 import org.jdom.Text;
6 import org.jdom.filter.Filters;
7 import org.jdom.test.util.AbstractTestList;
8
9 @SuppressWarnings("javadoc")
10 public class TestFilterListText extends AbstractTestList<Text> {
11
12 public TestFilterListText() {
13 super(Text.class, false);
14 }
15
16 @Override
17 public List<Text> buildEmptyList() {
18 Element root = new Element("root");
19 return root.getContent(Filters.text());
20 }
21
22 @Override
23 public Text[] buildSampleContent() {
24 return new Text[] {
25 new Text("kida"),
26 new Text("kidb"),
27 new Text("kidc"),
28 new Text("kidd"),
29 new Text("kide"),
30 new Text("kidf"),
31 new Text("kidg"),
32 new Text("kidh"),
33 new Text("kidi"),
34 new Text("kidj"),
35 };
36 }
37
38 @Override
39 public Text[] buildAdditionalContent() {
40 return new Text[] { };
41 }
42
43 @Override
44 public Text[] buildIllegalArgumentContent() {
45 return new Text[] { };
46 }
47
48 @Override
49 public Object[] buildIllegalClassContent() {
50 return new Object[] {};
51 }
52
53
54 }
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.*;
3
4 import java.io.ByteArrayOutputStream;
5 import java.io.CharArrayWriter;
6 import java.io.PrintStream;
7 import java.io.PrintWriter;
8
9 import org.jdom.JDOMException;
10 import org.junit.Test;
11
12 @SuppressWarnings("javadoc")
13 public class TestJDOMExceptn {
14
15 @Test
16 public void testJDOMException() {
17 JDOMException e = new JDOMException();
18 assertEquals(e.getMessage(), "Error occurred in JDOM application.");
19 assertEquals(e.getCause(), null);
20 }
21
22 @Test
23 public void testJDOMExceptionString() {
24 JDOMException e = new JDOMException("foo");
25 assertEquals(e.getMessage(), "foo");
26 assertEquals(e.getCause(), null);
27 }
28
29 @Test
30 public void testJDOMExceptionStringThrowable() {
31 Exception c = new RuntimeException("cause");
32 JDOMException e = new JDOMException("foo", c);
33 // assertEquals(e.getMessage(), "foo");
34 assertEquals(e.getCause(), c);
35 }
36
37 @Test
38 public void testInitCauseThrowable() {
39 Exception c = new RuntimeException("cause");
40 JDOMException e = new JDOMException("foo");
41 assertEquals(e.getMessage(), "foo");
42 assertEquals(e.getCause(), null);
43 e.initCause(c);
44 assertEquals(e.getCause(), c);
45 }
46
47 @Test
48 public void testPrintStackTracePrintStream() {
49 Exception c = new RuntimeException("cause");
50 JDOMException e = new JDOMException("foo", c);
51 ByteArrayOutputStream baos = new ByteArrayOutputStream();
52 e.printStackTrace(new PrintStream(baos));
53 String msg = baos.toString();
54 assertTrue(msg != null);
55 assertTrue(msg.indexOf(JDOMException.class.getName()) == 0);
56 assertTrue(msg.indexOf("Caused by") > 0);
57 }
58
59 @Test
60 public void testPrintStackTracePrintWriter() {
61 Exception c = new RuntimeException("cause");
62 JDOMException e = new JDOMException("foo", c);
63 CharArrayWriter caw = new CharArrayWriter();
64 e.printStackTrace(new PrintWriter(caw));
65 String msg = caw.toString();
66 assertTrue(msg != null);
67 assertTrue(msg.indexOf(JDOMException.class.getName()) == 0);
68 assertTrue(msg.indexOf("Caused by") > 0);
69 }
70
71
72 }
0 package org.jdom.test.cases;
1
2 /*--
3
4 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact license@jdom.org.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management (pm@jdom.org).
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Brett McLaughlin <brett@jdom.org> and
51 Jason Hunter <jhunter@jdom.org>. For more information on the
52 JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 /**
57 * Please put a description of your test here.
58 *
59 * @author unascribed
60 * @version 0.1
61 */
62 import javax.xml.XMLConstants;
63
64 import org.jdom.*;
65 import org.junit.Test;
66 import org.junit.runner.JUnitCore;
67 import static org.junit.Assert.*;
68
69 @SuppressWarnings("javadoc")
70 public final class TestNamespace {
71
72 /**
73 * The main method runs all the tests in the text ui
74 */
75 public static void main (String args[])
76 {
77 JUnitCore.runClasses(TestNamespace.class);
78 }
79
80 /**
81 * Test the object comparison method.
82 */
83 @Test
84 public void test_TCM__boolean_equals_Object() {
85 Namespace ns = Namespace.getNamespace("prefx", "http://some.other.place");
86 Object ob = ns;
87 assertTrue("object not equal to attribute", ns.equals(ob));
88
89 ns = Namespace.NO_NAMESPACE;
90 ob = ns;
91 assertTrue("object not equal to attribute", ns.equals(ob));
92
93 //ns = Namespace.EMPTY_NAMESPACE;
94 //ob = (Object)ns;
95 //assertTrue("object not equal to attribute", ns.equals(ob));
96
97
98 }
99
100 /**
101 * Verify that a namespace will produce a hashcode.
102 */
103 @Test
104 public void test_TCM__int_hashCode() {
105 Namespace ns = Namespace.getNamespace("test", "value");
106 //only an exception would be a problem
107 int i = -1;
108 try {
109 i = ns.hashCode();
110 }
111 catch(Exception e) {
112 fail("bad hashCode");
113 }
114
115 //make sure a new one doesn't have the same value
116 Namespace ns2 = Namespace.getNamespace("test", "value2");
117 int x = ns2.hashCode();
118 assertTrue("duplicate hashCode", i!=x );
119
120 //test hashcode for NO_NAMESPACE
121 //only an exception would be a problem
122 try {
123 // Namespace.hashCode() is uri.hashCode().
124 // NO_NAMESPACE has URI ""
125 assertTrue(Namespace.NO_NAMESPACE.hashCode() == "".hashCode());
126 }
127 catch(Exception e) {
128 fail("bad hashCode");
129 }
130
131 //test hashcode for NO_NAMESPACE
132 //y = Namespace.EMPTY_NAMESPACE.hashCode();
133 //only an exception would be a problem
134 //assertTrue("bad hashcode" , true);
135 }
136
137 /**
138 * Test the URI only Namespace.
139 */
140 @Test
141 public void test_TCM__OrgJdomNamespace_getNamespace_String() {
142 Namespace ns = Namespace.getNamespace("http://some.new.place");
143 assertTrue("Incorrect namespace created", ns.toString().equals("[Namespace: prefix \"\" is mapped to URI \"http://some.new.place\"]"));
144 //the is really the default NO_NAMESPACE version
145 Namespace ns2 = Namespace.getNamespace("");
146 assertTrue("Incorrect no namespace namespace created", ns2.toString().equals("[Namespace: prefix \"\" is mapped to URI \"\"]"));
147
148 }
149
150 /**
151 * Test the prefix, uri version of getNamespace.
152 */
153 @Test
154 public void test_TCM__OrgJdomNamespace_getNamespace_String_String() {
155 Namespace ns = Namespace.getNamespace("prefx", "http://some.other.place");
156 assertTrue("Incorrect namespace created", ns.toString().equals("[Namespace: prefix \"prefx\" is mapped to URI \"http://some.other.place\"]"));
157
158 assertTrue(Namespace.NO_NAMESPACE == Namespace.getNamespace(""));
159 assertTrue(Namespace.NO_NAMESPACE == Namespace.getNamespace(null));
160 assertTrue(Namespace.NO_NAMESPACE == Namespace.getNamespace(null, null));
161 assertTrue(Namespace.NO_NAMESPACE == Namespace.getNamespace(null, ""));
162 assertTrue(Namespace.NO_NAMESPACE == Namespace.getNamespace("", ""));
163 assertTrue(Namespace.NO_NAMESPACE == Namespace.getNamespace("", null));
164
165 assertTrue(Namespace.XML_NAMESPACE == Namespace.getNamespace(
166 XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI));
167
168 try {
169 assertTrue(null != Namespace.getNamespace("xml", "myuri"));
170 fail("Should not be able to re-brand Namespace prefix 'xml'");
171 } catch (IllegalNameException ine) {
172 // good
173 } catch (Exception e) {
174 fail("expected IllegalNameException, not " + e.getClass().getName());
175 }
176
177 try {
178 assertTrue(null != Namespace.getNamespace("pfx", XMLConstants.XML_NS_URI));
179 fail("Should not be able to re-brand xml namespace URI to another prefix too.");
180 } catch (IllegalNameException ine) {
181 // good
182 } catch (Exception e) {
183 fail("expected IllegalNameException, not " + e.getClass().getName());
184 }
185
186 try {
187 assertTrue(null != Namespace.getNamespace("pfx", "-this is illegal..."));
188 fail("Should not be able to have a URI starting with '-'.");
189 } catch (IllegalNameException ine) {
190 // good
191 } catch (Exception e) {
192 fail("expected IllegalNameException, not " + e.getClass().getName());
193 }
194
195 try {
196 assertTrue(null != Namespace.getNamespace("p:x", "myuri"));
197 fail("Should not be able to create Namespace with illegal prefix 'p:x'");
198 } catch (IllegalNameException ine) {
199 // good
200 } catch (Exception e) {
201 fail("expected IllegalNameException, not " + e.getClass().getName());
202 }
203
204 try {
205 assertTrue(null != Namespace.getNamespace("pfx", " "));
206 fail("Should not be able to create Namespace with no URI");
207 } catch (IllegalNameException ine) {
208 // good
209 } catch (Exception e) {
210 fail("expected IllegalNameException, not " + e.getClass().getName());
211 }
212
213 try {
214 assertTrue(null != Namespace.getNamespace("pfx", null));
215 fail("Should not be able to create Namespace with no URI");
216 } catch (IllegalNameException ine) {
217 // good
218 } catch (Exception e) {
219 fail("expected IllegalNameException, not " + e.getClass().getName());
220 }
221
222 }
223
224 /**
225 * Test getPrefix()
226 */
227 @Test
228 public void test_TCM__String_getPrefix() {
229 Namespace ns = Namespace.getNamespace("prefx","http://foo");
230 assertTrue("Incorrect namespace prefix", ns.getPrefix().equals("prefx"));
231
232 //ns = Namespace.EMPTY_NAMESPACE;
233 //assertTrue("Incorrect empty namespace prefix", ns.getPrefix().equals(""));
234
235 ns = Namespace.NO_NAMESPACE;
236 assertTrue("Incorrect empty namespace prefix", ns.getPrefix().equals(""));
237
238 }
239
240 /**
241 * Test than a namespace returns the correct URI
242 */
243 @Test
244 public void test_TCM__String_getURI() {
245 Namespace ns = Namespace.getNamespace("prefx","http://foo");
246 assertTrue("Incorrect namespace prefix", ns.getURI().equals("http://foo"));
247
248 }
249
250 /**
251 * Test that toString() operates according to JDOM specs
252 */
253 @Test
254 public void test_TCM__String_toString() {
255 Namespace ns = Namespace.getNamespace("http://some.new.place");
256 assertTrue("Incorrect namespace created", ns.toString().equals("[Namespace: prefix \"\" is mapped to URI \"http://some.new.place\"]"));
257 //the is really the default NO_NAMESPACE version
258 Namespace ns2 = Namespace.getNamespace("");
259 assertTrue("Incorrect no namespace namespace created", ns2.toString().equals("[Namespace: prefix \"\" is mapped to URI \"\"]"));
260 ns2 = Namespace.getNamespace("prefx","http://foo");
261 assertTrue("Incorrect namespace created", ns2.toString().equals("[Namespace: prefix \"prefx\" is mapped to URI \"http://foo\"]"));
262
263 }
264
265 @Test
266 public void testXMLNamespaceGood() {
267 Namespace ns = Namespace.getNamespace("xml", "http://www.w3.org/XML/1998/namespace");
268 assertTrue(ns == Namespace.XML_NAMESPACE);
269 }
270
271 @Test
272 public void testXMLNamespacePrefix() {
273 try {
274 Namespace.getNamespace("xml", "not right");
275 fail("Should not be able to redefine 'xml' prefix.");
276 } catch (IllegalNameException ine) {
277 // good
278 } catch (Exception e) {
279 e.printStackTrace();
280 fail("We expect IllegalNameException not " + e.getClass());
281 }
282 }
283
284 @Test
285 public void testXMLNamespaceOnlyPrefix() {
286 try {
287 Namespace.getNamespace("other", JDOMConstants.NS_URI_XML);
288 fail("Should not be able to have XML Namespace URI mapped to other prefix.");
289 } catch (IllegalNameException ine) {
290 // good
291 } catch (Exception e) {
292 e.printStackTrace();
293 fail("We expect IllegalNameException not " + e.getClass());
294 }
295 }
296
297 @Test
298 public void testXMLNamespaceDefault() {
299 try {
300 Namespace.getNamespace(JDOMConstants.NS_URI_XML);
301 fail("Should not be able to have XML Namespace URI mapped the default namespace.");
302 } catch (IllegalNameException ine) {
303 // good
304 } catch (Exception e) {
305 e.printStackTrace();
306 fail("We expect IllegalNameException not " + e.getClass());
307 }
308 }
309
310
311 @Test
312 public void testXMLNSNamespaceGood() {
313 Namespace ns = Namespace.getNamespace("xmlns", "http://www.w3.org/2000/xmlns/");
314 assertTrue("xmlns".equals(ns.getPrefix()));
315 }
316
317 @Test
318 public void testXMLNSNamespacePrefix() {
319 try {
320 Namespace.getNamespace("xmlns", "not right");
321 fail("Should not be able to redefine 'xmlns' prefix.");
322 } catch (IllegalNameException ine) {
323 // good
324 } catch (Exception e) {
325 e.printStackTrace();
326 fail("We expect IllegalNameException not " + e.getClass());
327 }
328 }
329
330 @Test
331 public void testXMLNSNamespaceOnlyPrefix() {
332 try {
333 Namespace.getNamespace("other", JDOMConstants.NS_URI_XMLNS);
334 fail("Should not be able to have XMLNS Namespace URI mapped to other prefix.");
335 } catch (IllegalNameException ine) {
336 // good
337 } catch (Exception e) {
338 e.printStackTrace();
339 fail("We expect IllegalNameException not " + e.getClass());
340 }
341 }
342
343 @Test
344 public void testXMLNSNamespaceDefault() {
345 try {
346 Namespace.getNamespace(JDOMConstants.NS_URI_XMLNS);
347 fail("Should not be able to have XMLNS Namespace URI mapped the default namespace.");
348 } catch (IllegalNameException ine) {
349 // good
350 } catch (Exception e) {
351 e.printStackTrace();
352 fail("We expect IllegalNameException not " + e.getClass());
353 }
354 }
355
356
357 }
0 package org.jdom.test.cases;
1
2 import org.jdom.Attribute;
3 import org.jdom.Document;
4 import org.jdom.Element;
5 import org.jdom.Namespace;
6 import org.jdom.Text;
7 import org.jdom.test.util.UnitTestUtil;
8 import org.junit.Test;
9
10 @SuppressWarnings("javadoc")
11 public class TestNamespaceAware {
12
13 @Test
14 public void testNamespacesScopeSimple() {
15 Element emt = new Element("root");
16
17 UnitTestUtil.testNamespaceIntro(emt);
18 UnitTestUtil.testNamespaceScope(emt, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
19
20 }
21
22 @Test
23 public void testNamespacesAttributeDetach() {
24 Attribute att = new Attribute("att", "value");
25
26 UnitTestUtil.testNamespaceIntro(att, Namespace.NO_NAMESPACE);
27 UnitTestUtil.testNamespaceScope(att, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
28
29 }
30
31 @Test
32 public void testNamespacesAttributeDetachNS() {
33 Namespace ns = Namespace.getNamespace("pfx", "nspfx");
34 Attribute att = new Attribute("att", "value", ns);
35
36 UnitTestUtil.testNamespaceIntro(att, ns);
37 UnitTestUtil.testNamespaceScope(att, ns, Namespace.XML_NAMESPACE);
38
39 }
40
41 @Test
42 public void testNamespacesAttributeDetachZZZ() {
43 // order should not change with zzz prefix
44 Namespace ns = Namespace.getNamespace("zzz", "nspfx");
45 Attribute att = new Attribute("att", "value", ns);
46
47 UnitTestUtil.testNamespaceIntro(att, ns);
48 UnitTestUtil.testNamespaceScope(att, ns, Namespace.XML_NAMESPACE);
49
50 }
51
52 @Test
53 public void testNamespacesText() {
54 // order should not change with zzz prefix
55 Text txt = new Text("txt");
56
57 UnitTestUtil.testNamespaceIntro(txt);
58 UnitTestUtil.testNamespaceScope(txt, Namespace.XML_NAMESPACE);
59
60 }
61
62 @Test
63 public void testNamespacesScopeSimpleAdded() {
64 Element emt = new Element("root");
65 Namespace pfx = Namespace.getNamespace("pfx", "nsuri");
66 emt.addNamespaceDeclaration(pfx);
67
68 UnitTestUtil.testNamespaceIntro(emt, pfx);
69 UnitTestUtil.testNamespaceScope(emt, Namespace.NO_NAMESPACE, pfx, Namespace.XML_NAMESPACE);
70
71 }
72
73 @Test
74 public void testNamespacesScopeSimpleElement() {
75 Namespace pfx = Namespace.getNamespace("pfx", "nsuri");
76 Element emt = new Element("root", pfx);
77
78 // just to mix it up, double-up the declaration.
79 // cover a condition in getNamespacesInScope();
80 emt.addNamespaceDeclaration(pfx);
81
82 UnitTestUtil.testNamespaceIntro(emt, pfx);
83 UnitTestUtil.testNamespaceScope(emt, pfx, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
84
85 }
86
87 @Test
88 public void testNamespacesScopeDeepElement() {
89 Namespace pfx = Namespace.getNamespace("pfx", "nsuri");
90 Namespace pfy = Namespace.getNamespace("pfy", "nsyyy");
91 Element emt = new Element("root", pfx);
92 Element kid = new Element("kid", pfy);
93 emt.addContent(kid);
94
95 UnitTestUtil.testNamespaceIntro(emt, pfx);
96 UnitTestUtil.testNamespaceScope(emt, pfx, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
97
98 UnitTestUtil.testNamespaceIntro(kid, pfy);
99 UnitTestUtil.testNamespaceScope(kid, pfy, Namespace.NO_NAMESPACE, pfx, Namespace.XML_NAMESPACE);
100
101 }
102
103 @Test
104 public void testNamespacesScopeSimpleAttribute() {
105 Namespace pfx = Namespace.getNamespace("pfx", "nsuri");
106 Element emt = new Element("root");
107 Attribute att = new Attribute("att", "val", pfx);
108 emt.setAttribute(att);
109
110 UnitTestUtil.testNamespaceIntro(emt, pfx);
111 UnitTestUtil.testNamespaceScope(emt, Namespace.NO_NAMESPACE, pfx, Namespace.XML_NAMESPACE);
112
113 UnitTestUtil.testNamespaceIntro(att);
114 UnitTestUtil.testNamespaceScope(att, pfx, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
115
116 }
117
118
119 @Test
120 public void testNamespacesScopeSimpleAttributeNoNs() {
121 Namespace pfx = Namespace.getNamespace("pfx", "nsuri");
122 Element emt = new Element("root", pfx);
123 Attribute att = new Attribute("att", "val");
124 emt.setAttribute(att);
125
126 UnitTestUtil.testNamespaceIntro(emt, pfx);
127 UnitTestUtil.testNamespaceScope(emt, pfx, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
128
129 UnitTestUtil.testNamespaceIntro(att);
130 UnitTestUtil.testNamespaceScope(att, Namespace.NO_NAMESPACE, pfx, Namespace.XML_NAMESPACE);
131 }
132
133 @Test
134 public void testNamespacesScopeDocument() {
135 Element emt = new Element("root");
136 Document doc = new Document(emt);
137
138 UnitTestUtil.testNamespaceIntro(doc, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
139 UnitTestUtil.testNamespaceScope(doc, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
140
141 }
142
143 @Test
144 public void testNamespacesScopeTreeAttributeNoNs() {
145 Namespace pfx = Namespace.getNamespace("pfx", "nsuri");
146 Element emt = new Element("root", pfx);
147 // note that 'kid' is in the NO_NAMESPACE namespace.
148 Element kid = new Element("kid");
149 Text txt = new Text("txt");
150 kid.addContent(txt);
151 emt.addContent(kid);
152 emt.setAttribute("att", "val");
153
154 Namespace kfx = Namespace.getNamespace("kfx", "nskid");
155 kid.addNamespaceDeclaration(kfx);
156
157 UnitTestUtil.testNamespaceIntro(emt, pfx);
158 UnitTestUtil.testNamespaceScope(emt, pfx, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
159
160
161 UnitTestUtil.testNamespaceIntro(kid, kfx);
162 UnitTestUtil.testNamespaceScope(kid, Namespace.NO_NAMESPACE, kfx, pfx, Namespace.XML_NAMESPACE);
163
164 UnitTestUtil.testNamespaceIntro(txt);
165 UnitTestUtil.testNamespaceScope(txt, Namespace.NO_NAMESPACE, kfx, pfx, Namespace.XML_NAMESPACE);
166
167 }
168
169 }
0 package org.jdom.test.cases;
1
2 import static org.jdom.test.util.UnitTestUtil.checkEquals;
3 import static org.jdom.test.util.UnitTestUtil.cloneString;
4 import static org.jdom.test.util.UnitTestUtil.deSerialize;
5 import static org.junit.Assert.*;
6
7 import java.util.Collections;
8 import java.util.LinkedHashMap;
9 import java.util.List;
10 import java.util.Map;
11
12 import org.jdom.Element;
13 import org.jdom.IllegalDataException;
14 import org.jdom.IllegalNameException;
15 import org.jdom.IllegalTargetException;
16 import org.jdom.ProcessingInstruction;
17 import org.junit.Ignore;
18 import org.junit.Test;
19
20 @SuppressWarnings("javadoc")
21 public class TestProcessingInstruction {
22
23 @Test
24 public void testProcessingInstruction() {
25 ProcessingInstruction pi = new ProcessingInstruction() {
26 // nothing
27 private static final long serialVersionUID = 200L;
28 };
29 assertTrue(null == pi.getTarget());
30 assertTrue(null == pi.getValue());
31 }
32
33 @Test
34 public void testProcessingInstructionString() {
35 ProcessingInstruction pi = new ProcessingInstruction("test");
36 checkEquals(pi.getTarget(), "test");
37 checkEquals(pi.getValue(), "");
38 }
39
40 @Test
41 public void testProcessingInstructionStringString() {
42 ProcessingInstruction pi = new ProcessingInstruction("test", "key='value'");
43 checkEquals(pi.getTarget(), "test");
44 checkEquals(pi.getValue(), "key='value'");
45 }
46
47 @Test
48 public void testProcessingInstructionStringMap() {
49 Map<String, String>kvs = buildMap(
50 "key1", "val1",
51 "key2", "val2"
52 );
53 ProcessingInstruction pi = new ProcessingInstruction("test", kvs);
54 checkEquals(pi.getTarget(), "test");
55 assertTrue(pi.getValue() != null);
56 checkMapValues(pi, kvs);
57 }
58
59 @Test (expected=IllegalTargetException.class)
60 public void testIllegalTargetContentA() {
61 new ProcessingInstruction("1tgt", "data");
62 }
63
64 @Test (expected=IllegalTargetException.class)
65 public void testIllegalTargetContentB() {
66 new ProcessingInstruction(" tgt", "data");
67 }
68
69 @Test (expected=IllegalTargetException.class)
70 public void testIllegalTargetContentC() {
71 new ProcessingInstruction("tg?>t", "data");
72 }
73
74 @Test (expected=IllegalTargetException.class)
75 public void testIllegalTargetContentD() {
76 new ProcessingInstruction("tgt ", "data");
77 }
78
79 @Test (expected=IllegalTargetException.class)
80 public void testIllegalTargetContentE() {
81 new ProcessingInstruction("t gt", "data");
82 }
83
84 @Test (expected=IllegalTargetException.class)
85 public void testIllegalTargetContentF() {
86 ProcessingInstruction pi = new ProcessingInstruction("tgt", "data");
87 pi.setTarget("tg t");
88 }
89
90 @Test (expected=IllegalTargetException.class)
91 public void testIllegalTargetContentG() {
92 ProcessingInstruction pi = new ProcessingInstruction("tgt", "data");
93 pi.setTarget("tgt ");
94 }
95
96 @Test (expected=IllegalTargetException.class)
97 public void testIllegalTargetContentH() {
98 ProcessingInstruction pi = new ProcessingInstruction("tgt", "data");
99 pi.setTarget("tg?t");
100 }
101
102 @Test (expected=IllegalDataException.class)
103 public void testIllegalAttnameA() {
104 ProcessingInstruction pi = new ProcessingInstruction("tgt", "data");
105 pi.setPseudoAttribute("tg?>t", "val");
106 }
107
108 @Test (expected=IllegalDataException.class)
109 public void testIllegalAttnameB() {
110 ProcessingInstruction pi = new ProcessingInstruction("tgt", buildMap("ok", "val"));
111 pi.setPseudoAttribute("b?>a", "val");
112 }
113
114 @Test (expected=IllegalNameException.class)
115 @Ignore // FIXME
116 public void testIllegalAttnameC() {
117 new ProcessingInstruction("tgt", buildMap("ok", "val", "b a", "val"));
118 }
119
120 @Test (expected=IllegalDataException.class)
121 @Ignore //FIXME
122 public void testIllegalAttValueA() {
123 new ProcessingInstruction("tgt", buildMap("ok", "val", " bad", "va'''\"\"\"l"));
124 }
125
126 @Test (expected=IllegalDataException.class)
127 public void testIllegalAttValueB() {
128 new ProcessingInstruction("tgt", buildMap("ok", "val", "b a", "v?>al"));
129 }
130
131 @Test (expected=IllegalDataException.class)
132 public void testIllegalAttValueC() {
133 ProcessingInstruction pi = new ProcessingInstruction("tgt", buildMap("ok", "val"));
134 pi.setPseudoAttribute("b a", "v?>al");
135 }
136
137 @Test (expected=IllegalDataException.class)
138 public void testIllegalData() {
139 ProcessingInstruction pi = new ProcessingInstruction("tgt", buildMap("ok", "val"));
140 pi.setData("b?>a=val");
141 }
142
143 private void checkMapValues(ProcessingInstruction pi, Map<String, String> vals) {
144 for (Map.Entry<String,String> me : vals.entrySet()) {
145 checkEquals(pi.getPseudoAttributeValue(me.getKey()), me.getValue());
146 }
147 for (Object s : pi.getPseudoAttributeNames() ) {
148 if (!vals.containsKey(s)) {
149 fail("ProcessingInstruction has key " + s + " which is not expected.");
150 }
151 }
152 }
153
154 private Map<String,String> buildMap(String...kvpairs) {
155 assertTrue(kvpairs != null);
156 assertTrue(kvpairs.length % 2 == 0);
157 LinkedHashMap<String, String> lhm = new LinkedHashMap<String, String>();
158 for (int i = 0; i < kvpairs.length; i += 2) {
159 lhm.put(kvpairs[i], kvpairs[i+1]);
160 }
161 return lhm;
162 }
163
164 @Test
165 public void testGetValue() {
166 ProcessingInstruction pi = new ProcessingInstruction("test", "value");
167 checkEquals(cloneString("value"), pi.getValue());
168 }
169
170 @Test
171 public void testCloneA() {
172 ProcessingInstruction pi = new ProcessingInstruction("test", "value");
173 ProcessingInstruction copy = pi.clone();
174 assertTrue(!pi.equals(copy));
175 checkEquals(pi.getTarget(), copy.getTarget());
176 checkEquals(pi.getValue(), copy.getValue());
177 }
178
179 @Test
180 public void testCloneB() {
181 ProcessingInstruction pi = new ProcessingInstruction("test", "");
182 ProcessingInstruction copy = pi.clone();
183 assertTrue(!pi.equals(copy));
184 checkEquals(pi.getTarget(), copy.getTarget());
185 checkEquals(pi.getValue(), copy.getValue());
186 }
187
188 @Test
189 public void testCloneC() {
190 ProcessingInstruction pi = new ProcessingInstruction("test", "");
191 pi.setPseudoAttribute("hi", "val");
192 pi.removePseudoAttribute("hi");
193 ProcessingInstruction copy = pi.clone();
194 assertTrue(!pi.equals(copy));
195 checkEquals(pi.getTarget(), copy.getTarget());
196 checkEquals(pi.getValue(), copy.getValue());
197 }
198
199 @Test
200 public void testCloneD() {
201 Map<String,String> empty = Collections.emptyMap();
202 ProcessingInstruction pi = new ProcessingInstruction("test", empty);
203 ProcessingInstruction copy = pi.clone();
204 assertTrue(!pi.equals(copy));
205 checkEquals(pi.getTarget(), copy.getTarget());
206 checkEquals(pi.getValue(), copy.getValue());
207 }
208
209 @Test
210 public void testSerialize() {
211 ProcessingInstruction pi = new ProcessingInstruction("test", "value");
212 ProcessingInstruction copy = deSerialize(pi);
213 checkEquals(pi.getTarget(), copy.getTarget());
214 checkEquals(pi.getValue(), copy.getValue());
215 }
216
217 @Test
218 public void testSetTarget() {
219 ProcessingInstruction pi = new ProcessingInstruction("test", "value");
220 checkEquals(pi.getTarget(), "test");
221 checkEquals(pi.getValue(), "value");
222 assertTrue(pi == pi.setTarget("test2"));
223 checkEquals(pi.getTarget(), "test2");
224 assertTrue(pi == pi.setTarget("test"));
225 checkEquals(pi.getTarget(), "test");
226 }
227
228 @Test
229 public void testGetTarget() {
230 ProcessingInstruction pi = new ProcessingInstruction("test", "value");
231 checkEquals(pi.getTarget(), "test");
232 checkEquals(pi.getValue(), "value");
233 pi.setTarget("test2");
234 checkEquals(pi.getTarget(), "test2");
235 pi.setTarget("test");
236 checkEquals(pi.getTarget(), "test");
237 }
238
239 @Test
240 public void testGetData() {
241 ProcessingInstruction pi = new ProcessingInstruction("test", "value");
242 checkEquals(pi.getTarget(), "test");
243 checkEquals(pi.getValue(), "value");
244 checkEquals(pi.getData(), "value");
245 }
246
247 @Test
248 public void testToString() {
249 ProcessingInstruction pi = new ProcessingInstruction("test", "value");
250 assertTrue(pi.toString() != null);
251 }
252
253 @Test
254 public void testExercise() {
255 Map<String,String> data = new LinkedHashMap<String, String>();
256 for (int i = 0; i < 10; i++) {
257 data.put(String.format("key%02d", i), String.format(" val %2d ", i));
258 Map<String,String> td = new LinkedHashMap<String,String>();
259 td.putAll(data);
260 exercise(td);
261 }
262
263 }
264
265
266 private void exercise(Map<String,String> data) {
267 exerciseQuotes("'", "'", data);
268 exerciseQuotes("\"", "\"", data);
269 exerciseQuotes(" \"", "\" ", data);
270 exerciseQuotes(" '", "' ", data);
271 exerciseQuotes(" '", "' ", data);
272 data.put("quote", "Foo'd up!");
273 exerciseQuotes("\"", "\"", data);
274 data.put("quote", "This is a \"quoted\" value.");
275 exerciseQuotes(" '", "' ", data);
276 data.remove("quote");
277 ProcessingInstruction pi = new ProcessingInstruction("tgt", data);
278 for (Map.Entry<String, String> me : data.entrySet()) {
279 assertEquals(me.getValue(), pi.getPseudoAttributeValue(me.getKey()));
280 assertTrue(pi.removePseudoAttribute(me.getKey()));
281 assertFalse(pi.removePseudoAttribute(me.getKey()));
282 }
283 for (Map.Entry<String, String> me : data.entrySet()) {
284 assertTrue(null == pi.getPseudoAttributeValue(me.getKey()));
285 assertFalse(pi.removePseudoAttribute(me.getKey()));
286 assertTrue(pi == pi.setPseudoAttribute(me.getKey(), me.getValue()));
287 assertEquals(me.getValue(), pi.getPseudoAttributeValue(me.getKey()));
288 }
289 checkEquals(mapValue(data), pi.getData());
290
291 }
292
293 private void exerciseQuotes(String open, String close,
294 Map<String, String> data) {
295 StringBuilder sb = new StringBuilder();
296 int cnt = 0;
297 for(Map.Entry<String, String> me : data.entrySet()) {
298 if (cnt++ > 0) {
299 sb.append(" ");
300 }
301 sb.append(me.getKey()).append("=").append(open).append(me.getValue()).append(close);
302 }
303 ProcessingInstruction pi = new ProcessingInstruction("test", sb.toString());
304 checkEquals(pi.getData(), sb.toString());
305 List<?> keys = pi.getPseudoAttributeNames();
306 assertTrue(keys != null);
307 assertTrue(keys.size() == data.size());
308 assertTrue(keys.containsAll(data.keySet()));
309 assertTrue(data.keySet().containsAll(keys));
310 for (Map.Entry<String,String> me : data.entrySet()) {
311 String val = pi.getPseudoAttributeValue(me.getKey());
312 assertTrue(val != null);
313 String x = me.getValue();
314 if (!x.equals(val)) {
315 fail("We expected value '" + x + "' but got '" + val + "'.");
316 }
317 }
318 assertEquals(pi.getData(), pi.getValue());
319 // ProcessingInstruction does not change the quoting unless you mess with
320 // attribute values.
321 assertEquals(pi.getData(), pi.getValue());
322 pi.setPseudoAttribute("foo", "bar");
323 pi.removePseudoAttribute("foo");
324 checkEquals(pi.getData(), mapValue(data));
325 }
326
327 private String mapValue(Map<String,String> data) {
328 StringBuilder sb = new StringBuilder();
329 for (Map.Entry<String,String> me : data.entrySet()) {
330 if (sb.length() > 0) {
331 sb.append(" ");
332 }
333 sb.append(me.getKey()).append("=\"").append(me.getValue()).append("\"");
334 }
335 return sb.toString();
336 }
337
338 @Test
339 public void testCloneDetatchParentProcessingInstruction() {
340 Element parent = new Element("root");
341 ProcessingInstruction content = new ProcessingInstruction("val", "");
342 parent.addContent(content);
343 ProcessingInstruction clone = content.detach().clone();
344 assertEquals(content.getValue(), clone.getValue());
345 assertNull(content.getParent());
346 assertNull(clone.getParent());
347 }
348
349 }
0 package org.jdom.test.cases;
1
2 /*--
3
4 Copyright (C) 2007 Jason Hunter.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact license@jdom.org.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management (pm@jdom.org).
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Brett McLaughlin <brett@jdom.org> and
51 Jason Hunter <jhunter@jdom.org>. For more information on the
52 JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 /**
57 * Please put a description of your test here.
58 *
59 * @author unascribed
60 * @version 0.1
61 */
62 import static org.jdom.test.util.UnitTestUtil.compare;
63 import static org.jdom.test.util.UnitTestUtil.deSerialize;
64 import static org.junit.Assert.assertFalse;
65 import static org.junit.Assert.assertTrue;
66
67 import java.util.Iterator;
68
69 import org.junit.Test;
70 import org.junit.runner.JUnitCore;
71
72 import org.jdom.Attribute;
73 import org.jdom.CDATA;
74 import org.jdom.Comment;
75 import org.jdom.Content;
76 import org.jdom.DocType;
77 import org.jdom.Document;
78 import org.jdom.Element;
79 import org.jdom.EntityRef;
80 import org.jdom.Namespace;
81 import org.jdom.ProcessingInstruction;
82 import org.jdom.Text;
83 import org.jdom.filter2.ElementFilter;
84
85 @SuppressWarnings("javadoc")
86 public final class TestSerialization {
87
88 /**
89 * The main method runs all the tests in the text ui
90 */
91 public static void main(String args[]) {
92 JUnitCore.runClasses(TestSerialization.class);
93 }
94
95
96 private void outAndBack(ElementFilter filter) {
97 ElementFilter filter2 = deSerialize(filter);
98 assertTrue(filter.equals(filter2));
99 }
100
101 @Test
102 public void test_ElementFilterName() {
103 outAndBack(new ElementFilter("name"));
104 }
105
106 @Test
107 public void test_ElementFilterNameNamespace() {
108 outAndBack(new ElementFilter("name", Namespace.XML_NAMESPACE));
109 }
110
111 @Test
112 public void test_ElementFilterNamespace() {
113 outAndBack(new ElementFilter(Namespace.XML_NAMESPACE));
114 }
115
116 @Test
117 public void test_ElementFilterEmpty() {
118 outAndBack(new ElementFilter());
119 }
120
121
122 @Test
123 public void testDocumentSerialization() {
124 // test serialization of all JDOM core types.
125 // Document, Element, DocType, Comment, CDATA, Text,
126 // ProcessingInstruction, EntityRef, Namespace, and Attribute.
127 // Additionally, test ContentList and AttributeList
128 Document doc = new Document();
129 doc.setDocType(new DocType("root", "pubid", "sysid"));
130 doc.getDocType().setInternalSubset(" internalss with space ");
131 doc.addContent(new Comment("doccomment1"));
132 doc.addContent(new ProcessingInstruction("target1"));
133 doc.addContent(new ProcessingInstruction("target2").setData("key=value"));
134 doc.addContent(new Comment("doccomment2"));
135 Element root = new Element("root");
136 doc.setRootElement(root);
137 root.setAttribute(new Attribute("att", "value"));
138 root.addContent(new Text(" "));
139 root.addNamespaceDeclaration(Namespace.getNamespace("pfx", "uriupfx"));
140 root.addContent(new Element("child", Namespace.getNamespace("nopfxuri")));
141 root.addContent(new EntityRef("name"));
142 root.addContent(new CDATA("cdata"));
143
144
145 Document ser = deSerialize(doc);
146 Iterator<Content> sit = ser.getDescendants();
147 Iterator<Content> dit = doc.getDescendants();
148 while (sit.hasNext() && dit.hasNext()) {
149 compare(sit.next(), dit.next());
150 }
151 assertFalse(sit.hasNext());
152 assertFalse(dit.hasNext());
153
154 }
155
156 @Test
157 public void testAttribute() {
158 Element root = new Element("root");
159 Attribute att = new Attribute(
160 "name", "value", Namespace.getNamespace("ans", "attnamespace"));
161 root.setAttribute(att);
162
163 Attribute attc = deSerialize(att);
164
165 assertTrue(attc.getParent() == null);
166
167 compare(att, attc);
168 }
169
170
171
172 }
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.*;
3 import org.junit.Test;
4
5 import org.jdom.JDOMFactory;
6 import org.jdom.SlimJDOMFactory;
7 import org.jdom.Text;
8
9 @SuppressWarnings("javadoc")
10 public class TestSlimJDOMFactory extends AbstractTestJDOMFactory {
11
12 /**
13 * @param located
14 */
15 public TestSlimJDOMFactory() {
16 super(false);
17 }
18
19 @Override
20 protected JDOMFactory buildFactory() {
21 return new SlimJDOMFactory();
22 }
23
24 @Test
25 public void testCaching() {
26 SlimJDOMFactory fac = new SlimJDOMFactory();
27 Text ta = fac.text("hi");
28 String hi = ta.getText();
29 // we expect the StringBin to compact a string value... should no longer
30 // be the intern value.
31 assertTrue("hi" != hi);
32 assertTrue("hi" == hi.intern());
33
34 Text tb = fac.text("hi");
35 assertTrue("hi" != tb.getText());
36 assertTrue(hi == tb.getText());
37
38 fac.clearCache();
39
40 Text tc = fac.text("hi");
41 assertTrue("hi" != tc.getText());
42 assertTrue(hi != tc.getText());
43
44 assertTrue(hi.equals(tc.getText()));
45 }
46 }
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.*;
3 import org.junit.Test;
4
5 import org.jdom.JDOMFactory;
6 import org.jdom.SlimJDOMFactory;
7 import org.jdom.Text;
8
9 @SuppressWarnings("javadoc")
10 public class TestSlimJDOMFactoryNoText extends AbstractTestJDOMFactory {
11
12 /**
13 * @param located
14 */
15 public TestSlimJDOMFactoryNoText() {
16 super(false);
17 }
18
19 @Override
20 protected JDOMFactory buildFactory() {
21 return new SlimJDOMFactory(false);
22 }
23
24 @Test
25 public void testCaching() {
26 SlimJDOMFactory fac = new SlimJDOMFactory(false);
27 Text ta = fac.text("hi");
28 String hi = ta.getText();
29 // we expect the StringBin to compact a string value... should no longer
30 // be the intern value.
31 assertTrue("hi" == hi);
32 assertTrue("hi" == hi.intern());
33
34 Text tb = fac.text("hi");
35 assertTrue("hi" == tb.getText());
36 assertTrue(hi == tb.getText());
37
38 fac.clearCache();
39
40 Text tc = fac.text("hi");
41 assertTrue("hi" == tc.getText());
42 assertTrue(hi == tc.getText());
43
44 assertTrue(hi.equals(tc.getText()));
45 }
46 }
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.assertFalse;
3 import static org.junit.Assert.assertNull;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.assertEquals;
6 import static org.junit.Assert.fail;
7
8 import org.jdom.Content;
9 import org.jdom.Element;
10 import org.jdom.IllegalDataException;
11 import org.jdom.Text;
12 import org.junit.Test;
13
14 @SuppressWarnings("javadoc")
15 public class TestText {
16
17 @Test
18 public void testText() {
19 Text txt = new Text() {
20 // nothing
21 private static final long serialVersionUID = 200L;
22 };
23 assertTrue(txt.getValue() == null);
24 assertTrue(txt.getText() == null);
25 }
26
27 @Test
28 public void testTextString() {
29 Text txt = new Text(" frodo baggins ");
30 assertTrue(" frodo baggins ".equals(txt.getValue()));
31 assertTrue(" frodo baggins ".equals(txt.getText()));
32 assertTrue("frodo baggins".equals(txt.getTextNormalize()));
33 assertTrue("frodo baggins".equals(txt.getTextTrim()));
34 }
35
36 @Test
37 public void testNormalizeString() {
38 assertEquals("", Text.normalizeString(null));
39 assertEquals("", Text.normalizeString(""));
40 assertEquals("boo", Text.normalizeString("boo"));
41 assertEquals("boo", Text.normalizeString(" boo"));
42 assertEquals("boo", Text.normalizeString("boo "));
43 assertEquals("boo", Text.normalizeString(" boo "));
44 assertEquals("boo hoo", Text.normalizeString("boo hoo"));
45 assertEquals("boo hoo", Text.normalizeString("boo\nhoo"));
46 assertEquals("boo hoo", Text.normalizeString("boo \n hoo"));
47 assertEquals("boo hoo", Text.normalizeString("boo \n hoo"));
48 assertEquals("boo hoo", Text.normalizeString("\rboo\thoo\n"));
49 }
50
51 @Test
52 public void testClone() {
53 Text txt = new Text("frodo baggins");
54 Text clone = txt.clone();
55 assertTrue(clone != null);
56 assertTrue(txt != clone);
57 assertFalse(txt.equals(clone));
58 assertFalse(clone.equals(txt));
59 assertTrue("frodo baggins".equals(clone.getText()));
60 }
61
62 @Test
63 public void testSetText() {
64 Text txt = new Text("frodo baggins");
65 assertTrue("frodo baggins".equals(txt.getText()));
66 assertTrue(txt.setText("bilbo baggins") == txt);
67 assertTrue("bilbo baggins".equals(txt.getText()));
68 }
69
70 @Test
71 public void testAppendString() {
72 Text txt = new Text("frodo baggins");
73 assertTrue("frodo baggins".equals(txt.getText()));
74 txt.append(" from the shire");
75 assertTrue("frodo baggins from the shire".equals(txt.getText()));
76 String app = null;
77 txt.append(app);
78 assertTrue("frodo baggins from the shire".equals(txt.getText()));
79 txt.append("");
80 assertTrue("frodo baggins from the shire".equals(txt.getText()));
81 try {
82 txt.append("New char data " + (char)0x05 + " with bad characters.");
83 } catch (IllegalDataException iae) {
84 // good
85 } catch (Exception e) {
86 fail ("Expected IllegalAddException, but got " + e.getClass().getName());
87 }
88 }
89
90 @Test
91 public void testAppendText() {
92 Text txt = new Text("frodo baggins");
93 assertTrue("frodo baggins".equals(txt.getText()));
94 txt.append(new Text(" from the shire"));
95 assertTrue("frodo baggins from the shire".equals(txt.getText()));
96 Text app = null;
97 txt.append(app);
98 assertTrue("frodo baggins from the shire".equals(txt.getText()));
99 }
100
101 @Test
102 public void testToString() {
103 Text txt = new Text("frodo baggins");
104 assertTrue(txt.toString() != null);
105 }
106
107 @Test
108 public void testCloneDetatchParentText() {
109 Element parent = new Element("root");
110 Text content = new Text("val");
111 parent.addContent(content);
112 Text clone = content.detach().clone();
113 assertEquals(content.getValue(), clone.getValue());
114 assertNull(content.getParent());
115 assertNull(clone.getParent());
116 }
117
118 @Test
119 public void testContentCType() {
120 assertTrue(Content.CType.Text == new Text("").getCType());
121 }
122 }
0 package org.jdom.test.cases;
1
2 import org.jdom.JDOMFactory;
3 import org.jdom.UncheckedJDOMFactory;
4
5 @SuppressWarnings("javadoc")
6 public class TestUncheckedJDOMFactory extends AbstractTestJDOMFactory {
7
8 /**
9 * @param located
10 */
11 public TestUncheckedJDOMFactory() {
12 super(false);
13 }
14
15 @Override
16 protected JDOMFactory buildFactory() {
17 return new UncheckedJDOMFactory();
18 }
19
20 }
0 package org.jdom.test.cases;
1
2 /*--
3
4 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions, and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions, and the disclaimer that follows
16 these conditions in the documentation and/or other materials
17 provided with the distribution.
18
19 3. The name "JDOM" must not be used to endorse or promote products
20 derived from this software without prior written permission. For
21 written permission, please contact license@jdom.org.
22
23 4. Products derived from this software may not be called "JDOM", nor
24 may "JDOM" appear in their name, without prior written permission
25 from the JDOM Project Management (pm@jdom.org).
26
27 In addition, we request (but do not require) that you include in the
28 end-user documentation provided with the redistribution and/or in the
29 software itself an acknowledgement equivalent to the following:
30 "This product includes software developed by the
31 JDOM Project (http://www.jdom.org/)."
32 Alternatively, the acknowledgment may be graphical using the logos
33 available at http://www.jdom.org/images/logos.
34
35 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
39 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 SUCH DAMAGE.
47
48 This software consists of voluntary contributions made by many
49 individuals on behalf of the JDOM Project and was originally
50 created by Brett McLaughlin <brett@jdom.org> and
51 Jason Hunter <jhunter@jdom.org>. For more information on the
52 JDOM Project, please see <http://www.jdom.org/>.
53
54 */
55
56 /**
57 * Please put a description of your test here.
58 *
59 * @author unascribed
60 * @version 0.1
61 */
62 import static org.junit.Assert.assertFalse;
63 import static org.junit.Assert.assertNotNull;
64 import static org.junit.Assert.assertNull;
65 import static org.junit.Assert.assertTrue;
66 import static org.junit.Assert.fail;
67
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.List;
71
72 import org.jdom.Attribute;
73 import org.jdom.Element;
74 import org.jdom.Namespace;
75 import org.jdom.Verifier;
76 import org.junit.Test;
77 import org.junit.runner.JUnitCore;
78
79 @SuppressWarnings("javadoc")
80 public final class TestVerifier {
81
82 private final char BADCHAR = (char)0x0b;
83
84 /**
85 * The main method runs all the tests in the text ui
86 */
87 public static void main (String args[])
88 {
89 JUnitCore.runClasses(TestVerifier.class);
90 }
91
92 /**
93 * Test checkElementName such that a name is validated as an
94 * xml name with the following caveats.
95 * The name must not start with "-" or ":".
96 */
97 @Test
98 public void testCheckElementName() {
99 //check out of range values
100 assertNotNull("validated invalid null", Verifier.checkElementName(null));
101 assertNotNull("validated invalid name with null char", Verifier.checkElementName("test" + (char)0x0));
102 assertNotNull("validated invalid name with null char", Verifier.checkElementName("test" + (char)0x0 + "ing"));
103 assertNotNull("validated invalid name with null char", Verifier.checkElementName((char)0x0 + "test"));
104 assertNotNull("validated invalid name with 0x01", Verifier.checkElementName((char)0x01 + "test"));
105 assertNotNull("validated invalid name with 0xD800", Verifier.checkElementName("test" + (char)0xD800));
106 assertNotNull("validated invalid name with 0xD800", Verifier.checkElementName("test" + (char)0xD800 + "ing"));
107 assertNotNull("validated invalid name with 0xD800", Verifier.checkElementName((char)0xD800 + "test"));
108 assertNotNull("validated invalid name with :", Verifier.checkElementName("test" + ':' + "local"));
109 assertNotNull("validated invalid name with :", Verifier.checkElementName("abcd:"));
110 assertNotNull("validated invalid name with :", Verifier.checkElementName("abc:d"));
111 assertNotNull("validated invalid name with :", Verifier.checkElementName("ab:cd"));
112 assertNotNull("validated invalid name with :", Verifier.checkElementName("a:bcd"));
113 assertNotNull("validated invalid name with :", Verifier.checkElementName(":abcd"));
114
115 //invalid start characters
116 assertNotNull("validated invalid name with startin -", Verifier.checkElementName('-' + "test"));
117 assertNotNull("validated invalid name with startin :", Verifier.checkElementName(':' + "test"));
118
119 //valid tests
120 assertNull("invalidated valid name with starting _", Verifier.checkElementName('_' + "test"));
121 assertNull("invalidated valid name with _", Verifier.checkElementName("test" + '_'));
122 assertNull("invalidated valid name with .", Verifier.checkElementName("test" + '.' + "name"));
123 assertNull("invalidated valid name with 0x00B7", Verifier.checkElementName("test" + (char)0x00B7));
124 assertNull("invalidated valid name with 0x4E01", Verifier.checkElementName("test" + (char)0x4E01));
125 assertNull("invalidated valid name with 0x0301", Verifier.checkElementName("test" + (char)0x0301));
126
127 }
128
129 /**
130 * Test for a valid Attribute name. A valid Attribute name is
131 * an xml name (xml start character + xml name characters) with
132 * some special considerations. "xml:lang" and "xml:space" are
133 * allowed. No ':' are allowed since prefixes are defined with
134 * Namespace objects. The name must not be "xmlns"
135 */
136 @Test
137 public void testCheckAttributeName() {
138 //check out of range values
139 assertNotNull("validated invalid null", Verifier.checkAttributeName(null));
140 assertNotNull("validated invalid name with null", Verifier.checkAttributeName("test" + (char)0x0));
141 assertNotNull("validated invalid name with null", Verifier.checkAttributeName("test" + (char)0x0 + "ing"));
142 assertNotNull("validated invalid name with null", Verifier.checkAttributeName((char)0x0 + "test"));
143 assertNotNull("validated invalid name with 0x01", Verifier.checkAttributeName((char)0x01 + "test"));
144 assertNotNull("validated invalid name with 0xD800", Verifier.checkAttributeName("test" + (char)0xD800));
145 assertNotNull("validated invalid name with 0xD800", Verifier.checkAttributeName("test" + (char)0xD800 + "ing"));
146 assertNotNull("validated invalid name with 0xD800", Verifier.checkAttributeName((char)0xD800 + "test"));
147 assertNotNull("validated invalid name with :", Verifier.checkAttributeName("test" + ':' + "local"));
148 assertNotNull("validated invalid name with xml:lang", Verifier.checkAttributeName("xml:lang"));
149 assertNotNull("validated invalid name with xml:space", Verifier.checkAttributeName("xml:space"));
150
151 //invalid start characters
152 assertNotNull("validated invalid name with startin -", Verifier.checkAttributeName('-' + "test"));
153 assertNotNull("validated invalid name with xmlns", Verifier.checkAttributeName("xmlns"));
154 assertNotNull("validated invalid name with startin :", Verifier.checkAttributeName(':' + "test"));
155
156 //valid tests
157 assertNull("invalidated valid name with starting _", Verifier.checkAttributeName('_' + "test"));
158 assertNull("invalidated valid name with _", Verifier.checkAttributeName("test" + '_'));
159 assertNull("invalidated valid name with .", Verifier.checkAttributeName("test" + '.' + "name"));
160 assertNull("invalidated valid name with 0x00B7", Verifier.checkAttributeName("test" + (char)0x00B7));
161 assertNull("invalidated valid name with 0x4E01", Verifier.checkAttributeName("test" + (char)0x4E01));
162 assertNull("invalidated valid name with 0x0301", Verifier.checkAttributeName("test" + (char)0x0301));
163
164 assertNull(Verifier.checkAttributeName("hi"));
165 assertNull(Verifier.checkAttributeName("hi2you"));
166 assertNull(Verifier.checkAttributeName("hi_you"));
167
168 assertNotNull(Verifier.checkAttributeName(null));
169 assertNotNull(Verifier.checkAttributeName(""));
170 assertNotNull(Verifier.checkAttributeName(" "));
171 assertNotNull(Verifier.checkAttributeName(" hi "));
172 assertNotNull(Verifier.checkAttributeName("hi "));
173 assertNotNull(Verifier.checkAttributeName(" hi"));
174 assertNotNull(Verifier.checkAttributeName("2bad"));
175
176 }
177
178 /**
179 * Test that a String contains only xml characters. The method under
180 * only checks for null values and then character by character scans
181 * the string so this test is not exhaustive
182 */
183 @Test
184 public void testCheckCharacterData() {
185 //check out of range values
186 assertNotNull("validated invalid null", Verifier.checkCharacterData(null));
187 assertNotNull("validated invalid string with null", Verifier.checkCharacterData("test" + (char)0x0));
188 assertNotNull("validated invalid string with null", Verifier.checkCharacterData("test" + (char)0x0 + "ing"));
189 assertNotNull("validated invalid string with null", Verifier.checkCharacterData((char)0x0 + "test"));
190 assertNotNull("validated invalid string with 0x01", Verifier.checkCharacterData((char)0x01 + "test"));
191 assertNotNull("validated invalid string with 0xD800", Verifier.checkCharacterData("test" + (char)0xD800));
192 assertNotNull("validated invalid string with 0xD800", Verifier.checkCharacterData("test" + (char)0xD800 + "ing"));
193 assertNotNull("validated invalid string with 0xD800", Verifier.checkCharacterData((char)0xD800 + "test"));
194
195 //various valid strings
196 assertNull("invalidated valid string with \n", Verifier.checkCharacterData("test" + '\n' + "ing"));
197 assertNull("invalidated valid string with 0x29", Verifier.checkCharacterData("test" +(char)0x29));
198 //a few higher values
199 assertNull("invalidated valid string with 0x0B08", Verifier.checkCharacterData("test" + (char)0x0B08));
200 assertNull("invalidated valid string with \t", Verifier.checkCharacterData("test" + '\t'));
201 //xml letter
202 assertNull("invalidated valid string with 0x42", Verifier.checkCharacterData("test" + (char)0x42));
203 assertNull("invalidated valid string with 0x4E01", Verifier.checkCharacterData("test" + (char)0x4E01));
204
205 }
206
207 /**
208 * Test that checkCDATASection verifies CDATA excluding
209 * the closing delimiter.
210 */
211 @Test
212 public void testCheckCDATASection() {
213 //check out of range values
214 assertNotNull("validated invalid null", Verifier.checkCDATASection(null));
215 assertNotNull("validated invalid string with null", Verifier.checkCDATASection("test" + (char)0x0));
216 assertNotNull("validated invalid string with null", Verifier.checkCDATASection("test" + (char)0x0 + "ing"));
217 assertNotNull("validated invalid string with null", Verifier.checkCDATASection((char)0x0 + "test"));
218 assertNotNull("validated invalid string with 0x01", Verifier.checkCDATASection((char)0x01 + "test"));
219 assertNotNull("validated invalid string with 0xD800", Verifier.checkCDATASection("test" + (char)0xD800));
220 assertNotNull("validated invalid string with 0xD800", Verifier.checkCDATASection("test" + (char)0xD800 + "ing"));
221 assertNotNull("validated invalid string with 0xD800", Verifier.checkCDATASection((char)0xD800 + "test"));
222 assertNotNull("validated invalid string with ]]>", Verifier.checkCDATASection("test]]>"));
223
224 //various valid strings
225 assertNull("invalidated valid string with \n", Verifier.checkCDATASection("test" + '\n' + "ing"));
226 assertNull("invalidated valid string with 0x29", Verifier.checkCDATASection("test" +(char)0x29));
227 assertNull("invalidated valid string with ]", Verifier.checkCDATASection("test]"));
228 assertNull("invalidated valid string with [", Verifier.checkCDATASection("test["));
229 //a few higher values
230 assertNull("invalidated valid string with 0x0B08", Verifier.checkCDATASection("test" + (char)0x0B08));
231 assertNull("invalidated valid string with \t", Verifier.checkCDATASection("test" + '\t'));
232 //xml letter
233 assertNull("invalidated valid string with 0x42", Verifier.checkCDATASection("test" + (char)0x42));
234 assertNull("invalidated valid string with 0x4E01", Verifier.checkCDATASection("test" + (char)0x4E01));
235
236 }
237
238 /**
239 * Test that checkNamespacePrefix validates against xml names
240 * with the following exceptions. Prefix names must not start
241 * with "-", "xmlns", digits, "$", or "." and must not contain
242 * ":"
243 */
244 @Test
245 public void testCheckNamespacePrefix() {
246 //check out of range values
247 assertNotNull("validated invalid name with null", Verifier.checkNamespacePrefix("test" + (char)0x0));
248 assertNotNull("validated invalid name with null", Verifier.checkNamespacePrefix("test" + (char)0x0 + "ing"));
249 assertNotNull("validated invalid name with null", Verifier.checkNamespacePrefix((char)0x0 + "test"));
250 assertNotNull("validated invalid name with 0x01", Verifier.checkNamespacePrefix((char)0x01 + "test"));
251 assertNotNull("validated invalid name with 0xD800", Verifier.checkNamespacePrefix("test" + (char)0xD800));
252 assertNotNull("validated invalid name with 0xD800", Verifier.checkNamespacePrefix("test" + (char)0xD800 + "ing"));
253 assertNotNull("validated invalid name with 0xD800", Verifier.checkNamespacePrefix((char)0xD800 + "test"));
254 assertNotNull("validated invalid name with :", Verifier.checkNamespacePrefix("test" + ':' + "local"));
255
256 //invalid start characters
257 assertNotNull("validated invalid name with startin -", Verifier.checkNamespacePrefix('-' + "test"));
258 assertNotNull("validated invalid name with startin :", Verifier.checkNamespacePrefix(':' + "test"));
259 assertNotNull("validated invalid name with starting digit", Verifier.checkNamespacePrefix("9"));
260 assertNotNull("validated invalid name with starting $", Verifier.checkNamespacePrefix("$"));
261 assertNotNull("validated invalid name with starting .", Verifier.checkNamespacePrefix("."));
262
263 // cannot start with xml (case insensitive).
264 // See issue 126: https://github.com/hunterhacker/jdom/issues/126
265 // assertNotNull("validated invalid name with xmlns", Verifier.checkNamespacePrefix("xmlns"));
266 // assertNotNull("validated invalid name beginning with xml", Verifier.checkNamespacePrefix("xmlabc"));
267 // assertNotNull("validated invalid name beginning with xml", Verifier.checkNamespacePrefix("xmLabc"));
268 // assertNotNull("validated invalid name beginning with xml", Verifier.checkNamespacePrefix("xMlabc"));
269 // assertNotNull("validated invalid name beginning with xml", Verifier.checkNamespacePrefix("Xmlabc"));
270
271
272 //valid tests
273 assertNull("invalidated valid null", Verifier.checkNamespacePrefix(null));
274 assertNull("invalidated valid empty String", Verifier.checkNamespacePrefix(""));
275 assertNull("invalidated valid name with starting _", Verifier.checkNamespacePrefix('_' + "test"));
276 assertNull("invalidated valid name with _", Verifier.checkNamespacePrefix("test" + '_'));
277 assertNull("invalidated valid name with .", Verifier.checkNamespacePrefix("test" + '.' + "name"));
278 assertNull("invalidated valid name with digit", Verifier.checkNamespacePrefix("test9"));
279 assertNull("invalidated valid name with 0x00B7", Verifier.checkNamespacePrefix("test" + (char)0x00B7));
280 assertNull("invalidated valid name with 0x4E01", Verifier.checkNamespacePrefix("test" + (char)0x4E01));
281 assertNull("invalidated valid name with 0x0301", Verifier.checkNamespacePrefix("test" + (char)0x0301));
282 assertNull("invalidated valid name with xml embedded", Verifier.checkNamespacePrefix("txml"));
283 assertNull("invalidated valid name with xml embedded", Verifier.checkNamespacePrefix("xmml"));
284
285 // These tests all used to be NotNull tests, but the Verifier as been changed to pass them
286 // See issue 126: https://github.com/hunterhacker/jdom/issues/126
287 assertNull("invalidated invalid name with xmlns", Verifier.checkNamespacePrefix("xmlns"));
288 assertNull("invalidated invalid name beginning with xml", Verifier.checkNamespacePrefix("xmlabc"));
289 assertNull("invalidated invalid name beginning with xml", Verifier.checkNamespacePrefix("xmLabc"));
290 assertNull("invalidated invalid name beginning with xml", Verifier.checkNamespacePrefix("xMlabc"));
291 assertNull("invalidated invalid name beginning with xml", Verifier.checkNamespacePrefix("Xmlabc"));
292
293 assertNull("invalidated invalid name beginning with xml", Verifier.checkNamespacePrefix("XML"));
294 assertNull("invalidated invalid name beginning with xml", Verifier.checkNamespacePrefix("XMLNS"));
295 assertNull("invalidated invalid name beginning with xml", Verifier.checkNamespacePrefix("XmL"));
296 }
297
298 /**
299 * Tests that checkNamespaceURI validates xml uri's.
300 * A valid URI is alphanumeric characters and the reserved characters:
301 * ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
302 *
303 * The URI cannot begin with a digit, "-" or "$". It must have at least
304 * one ":" separating the scheme from the scheme specific part
305 *
306 * XXX:TODO make this match the eventual specs for the Verifier class which is incomplete
307 */
308 @Test
309 public void testCheckNamespaceURI() {
310 //invalid start characters
311 assertNotNull("validated invalid URI with startin -", Verifier.checkNamespaceURI('-' + "test"));
312 assertNotNull("validated invalid URI with starting digit", Verifier.checkNamespaceURI("9"));
313 assertNotNull("validated invalid URI with starting $", Verifier.checkNamespaceURI("$"));
314
315 //valid tests
316 assertNull("invalidated valid null", Verifier.checkNamespaceURI(null));
317 assertNull("invalidated valid null", Verifier.checkNamespaceURI(""));
318 assertNull("invalidated valid URI with :", Verifier.checkNamespaceURI("test" + ':' + "local"));
319 assertNull("invalidated valid URI with _", Verifier.checkNamespaceURI("test" + '_'));
320 assertNull("invalidated valid URI with .", Verifier.checkNamespaceURI("test" + '.' + "URI"));
321 assertNull("invalidated valid URI with digit", Verifier.checkNamespaceURI("test9"));
322 assertNull("invalidated valid URI with 0x00B7", Verifier.checkNamespaceURI("test" + (char)0x00B7));
323 assertNull("invalidated valid URI with 0x4E01", Verifier.checkNamespaceURI("test" + (char)0x4E01));
324 assertNull("invalidated valid URI with 0x0301", Verifier.checkNamespaceURI("test" + (char)0x0301));
325
326 //check out of range values
327
328 /** skip these tests until the time the checks are implemented
329 assertNull("validated invalid URI with xmlns", Verifier.checkNamespaceURI("xmlns"));
330 assertNull("validated invalid URI with startin :", Verifier.checkNamespaceURI(':' + "test"));
331 assertNull("validated invalid URI with starting .", Verifier.checkNamespaceURI("."));
332
333 assertNull("validated invalid URI with null", Verifier.checkNamespaceURI("test" + (char)0x0));
334 assertNull("validated invalid URI with null", Verifier.checkNamespaceURI("test" + (char)0x0 + "ing"));
335 assertNull("validated invalid URI with null", Verifier.checkNamespaceURI((char)0x0 + "test"));
336 assertNull("validated invalid URI with 0x01", Verifier.checkNamespaceURI((char)0x01 + "test"));
337 assertNull("validated invalid URI with 0xD800", Verifier.checkNamespaceURI("test" + (char)0xD800));
338 assertNull("validated invalid URI with 0xD800", Verifier.checkNamespaceURI("test" + (char)0xD800 + "ing"));
339 assertNull("validated invalid URI with 0xD800", Verifier.checkNamespaceURI((char)0xD800 + "test"));
340 */
341 }
342
343 /**
344 * Test that checkProcessintInstructionTarget validates the name
345 * of a processing instruction. This name must be a normal xml
346 * and cannot have ":" or "xml" in the name.
347 */
348 @Test
349 public void testCheckProcessingInstructionTarget() {
350 //check out of range values
351 assertNotNull("validated invalid null", Verifier.checkProcessingInstructionTarget(null));
352 assertNotNull("validated invalid name with null", Verifier.checkProcessingInstructionTarget("test" + (char)0x0));
353 assertNotNull("validated invalid name with null", Verifier.checkProcessingInstructionTarget("test" + (char)0x0 + "ing"));
354 assertNotNull("validated invalid name with null", Verifier.checkProcessingInstructionTarget((char)0x0 + "test"));
355 assertNotNull("validated invalid name with 0x01", Verifier.checkProcessingInstructionTarget((char)0x01 + "test"));
356 assertNotNull("validated invalid name with 0xD800", Verifier.checkProcessingInstructionTarget("test" + (char)0xD800));
357 assertNotNull("validated invalid name with 0xD800", Verifier.checkProcessingInstructionTarget("test" + (char)0xD800 + "ing"));
358 assertNotNull("validated invalid name with 0xD800", Verifier.checkProcessingInstructionTarget((char)0xD800 + "test"));
359 assertNotNull("validated invalid name with :", Verifier.checkProcessingInstructionTarget("test" + ':' + "local"));
360 assertNotNull("validated invalid name with xml:space", Verifier.checkProcessingInstructionTarget("xml:space"));
361 assertNotNull("validated invalid name with xml:lang", Verifier.checkProcessingInstructionTarget("xml:lang"));
362 assertNotNull("validated invalid name with xml", Verifier.checkProcessingInstructionTarget("xml"));
363 assertNotNull("validated invalid name with xMl", Verifier.checkProcessingInstructionTarget("xMl"));
364
365 //invalid start characters
366 assertNotNull("validated invalid name with startin -", Verifier.checkProcessingInstructionTarget('-' + "test"));
367 assertNotNull("validated invalid name with startin :", Verifier.checkProcessingInstructionTarget(':' + "test"));
368 //valid tests
369 assertNull("invalidated valid name with starting _", Verifier.checkProcessingInstructionTarget('_' + "test"));
370 assertNull("invalidated valid name with _", Verifier.checkProcessingInstructionTarget("test" + '_'));
371 assertNull("invalidated valid name with .", Verifier.checkProcessingInstructionTarget("test" + '.' + "name"));
372 assertNull("invalidated valid name with 0x00B7", Verifier.checkProcessingInstructionTarget("test" + (char)0x00B7));
373 assertNull("invalidated valid name with 0x4E01", Verifier.checkProcessingInstructionTarget("test" + (char)0x4E01));
374 assertNull("invalidated valid name with 0x0301", Verifier.checkProcessingInstructionTarget("test" + (char)0x0301));
375
376 }
377
378 @Test
379 public void testCheckProcessingInstructionData() {
380 assertNull(Verifier.checkProcessingInstructionData(""));
381 assertNull(Verifier.checkProcessingInstructionData(" "));
382 assertNull(Verifier.checkProcessingInstructionData("hi"));
383 assertNull(Verifier.checkProcessingInstructionData(" h i "));
384
385 assertNotNull(Verifier.checkProcessingInstructionData(null));
386 assertNotNull(Verifier.checkProcessingInstructionData("hi" + (char)0x0b + " there"));
387 assertNotNull(Verifier.checkProcessingInstructionData("can't have '?>' in text."));
388 }
389
390 /**
391 * Test checkCommentData such that a comment is validated as an
392 * xml comment consisting of xml characters with the following caveats.
393 * The comment must not contain a double hyphen.
394 */
395 @Test
396 public void testCheckCommentData() {
397 //check out of range values
398 assertNotNull("validated invalid null", Verifier.checkCommentData(null));
399 assertNotNull("validated invalid string with null", Verifier.checkCommentData("test" + (char)0x0));
400 assertNotNull("validated invalid string with null", Verifier.checkCommentData("test" + (char)0x0 + "ing"));
401 assertNotNull("validated invalid string with null", Verifier.checkCommentData((char)0x0 + "test"));
402 assertNotNull("validated invalid string with 0x01", Verifier.checkCommentData((char)0x01 + "test"));
403 assertNotNull("validated invalid string with 0xD800", Verifier.checkCommentData("test" + (char)0xD800));
404 assertNotNull("validated invalid string with 0xD800", Verifier.checkCommentData("test" + (char)0xD800 + "ing"));
405 assertNotNull("validated invalid string with 0xD800", Verifier.checkCommentData((char)0xD800 + "test"));
406 assertNotNull("validated invalid string with --", Verifier.checkCommentData("--test"));
407 assertNotNull("validated invalid string ending with -", Verifier.checkCommentData("test-"));
408
409 //various valid strings
410 assertNull("invalidated valid string with \n", Verifier.checkCommentData("test" + '\n' + "ing"));
411 assertNull("invalidated valid string with 0x29", Verifier.checkCommentData("test" +(char)0x29));
412 //a few higher values
413 assertNull("invalidated valid string with 0x0B08", Verifier.checkCommentData("test" + (char)0x0B08));
414 assertNull("invalidated valid string with \t", Verifier.checkCommentData("test" + '\t'));
415 //xml letter
416 assertNull("invalidated valid string with 0x42", Verifier.checkCommentData("test" + (char)0x42));
417 assertNull("invalidated valid string with 0x4E01", Verifier.checkCommentData("test" + (char)0x4E01));
418
419 }
420
421 @Test
422 public void testCheckNamespaceCollision() {
423 try {
424 Namespace ns1 = Namespace.getNamespace("aaa", "http://acme.com/aaa");
425 Element e = new Element("aaa", ns1);
426 e.setAttribute("att1", "att1");
427 Namespace defns = Namespace.getNamespace("http://acme.com/default");
428 e.addNamespaceDeclaration(defns);
429 // pass
430 } catch (Exception e) {
431 // also see http://markmail.org/message/hvzz73em7ztt5i5k
432 fail("Bug http://www.junlu.com/msg/166290.html");
433 }
434
435 Namespace nsnp = Namespace.getNamespace("rootns");
436 Namespace nswp = Namespace.getNamespace("p", nsnp.getURI());
437 Namespace mscp = Namespace.getNamespace("p", "childns");
438 Namespace ans = Namespace.getNamespace("a", "attns");
439
440 // no collision between Namespace and itself
441 assertNull(Verifier.checkNamespaceCollision(nsnp, nsnp));
442
443 // no collision between Namespace and other namespace with different prefix
444 assertNull(Verifier.checkNamespaceCollision(nsnp, nswp));
445
446 // but collision between same prefix, but different URI
447 assertNotNull(Verifier.checkNamespaceCollision(nswp, mscp));
448
449 Element root = new Element("root", nsnp);
450 root.addNamespaceDeclaration(nswp);
451 Attribute att = new Attribute("att", "val", nswp);
452
453 // should be able to add
454 assertNull(Verifier.checkNamespaceCollision(att, root));
455 root.setAttribute(att);
456
457 root.setAttribute(new Attribute("ans", "v", ans));
458
459 // cnns is child no namespace
460 Element cnns = new Element ("cnns");
461 root.addContent(cnns);
462 // cwns is child with namespace
463 Element cwns = new Element ("cwns", nsnp);
464 root.addContent(cwns);
465 // cpns is child prefixed namespace
466 Element cpns = new Element ("cpns", nswp);
467 root.addContent(cpns);
468 // cpms is child prefixed different namespace
469 Element cpms = new Element ("cpms", mscp);
470 root.addContent(cpms);
471
472 //printlement(root);
473 // XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
474 // try {
475 // CharArrayWriter w = new CharArrayWriter();
476 // out.output(root, w);
477 // } catch (IOException e) {
478 // e.printStackTrace();
479 // }
480
481
482 // Check Namespace against elements.
483 assertNull (Verifier.checkNamespaceCollision(att, root));
484 assertNull (Verifier.checkNamespaceCollision(att, cnns));
485 assertNull (Verifier.checkNamespaceCollision(att, cwns));
486 assertNull (Verifier.checkNamespaceCollision(att, cpns));
487
488 // now, check it against the child that redefines the 'p' prefix.
489 assertNotNull(Verifier.checkNamespaceCollision(nswp, cpms));
490 // root has an attribute with the namspace a->ans, cannot then have a->dummy
491 assertNotNull(Verifier.checkNamespaceCollision(Namespace.getNamespace("a", "dummy"), root));
492 // root has an additional namespace p->rootns, can't then have a different 'p'
493 assertNotNull(Verifier.checkNamespaceCollision(Namespace.getNamespace("p", "dummy"), root));
494
495 // Check Namespace against Attributes
496 // we do the same tests as above, only we wrap it in an Attribute
497 // first, one that passes.
498 assertNull(Verifier.checkNamespaceCollision(att, cwns));
499 // now, check it against the child that redefines the 'p' prefix.
500 assertNotNull(Verifier.checkNamespaceCollision(att, cpms));
501 // root has an attribute with the namspace a->ans, cannot then have a->dummy
502 assertNotNull(Verifier.checkNamespaceCollision(
503 new Attribute("ax", "v", Namespace.getNamespace("a", "dummy")), root));
504 // root has an additional namespace p->rootns, can't then have a different 'p'
505 assertNotNull(Verifier.checkNamespaceCollision(
506 new Attribute("ax", "v", Namespace.getNamespace("p", "dummy")), root));
507
508
509 // now we need to check the namespaces against Attributes not Elements
510 // first, one that works
511 assertNull(Verifier.checkNamespaceCollision(nswp, new Attribute("foo", "bar")));
512 // now, check it against the child that redefines the 'p' prefix.
513 assertNotNull(Verifier.checkNamespaceCollision(nswp, new Attribute("foo", "bar", mscp)));
514
515 // Now test some List structures.
516 // first, one that passes.
517 assertNull(Verifier.checkNamespaceCollision(nswp, root.getAdditionalNamespaces()));
518 // then, a passing one... with junk...
519 List<Object> c = null;
520 assertNull(Verifier.checkNamespaceCollision(nswp, c));
521 c = new ArrayList<Object>();
522 c.addAll(Arrays.asList(root.getAdditionalNamespaces().toArray()));
523 c.add(Integer.valueOf(1));
524 c.add(0, "dummy");
525 assertNull(Verifier.checkNamespaceCollision(nswp, c));
526
527 // now, check something that will conflict... check against a conflicting attribute.
528 // which is already in there.
529 assertNotNull(Verifier.checkNamespaceCollision(mscp, c));
530
531 // now check against an Element.
532 // replace prefixed namespace with prefixed Element
533 c.set(c.indexOf(nswp), cpns);
534 assertNotNull(Verifier.checkNamespaceCollision(mscp, c));
535
536 // now replace prefixed Element with prefixed Attribute
537 c.set(c.indexOf(cpns), new Attribute("a", "b", nswp));
538 assertNotNull(Verifier.checkNamespaceCollision(mscp, c));
539
540
541 // some basic namespace/attribute tests similar to the ones done for the bug test up top.
542 // attributes with no prefix can never collide... because attributes are always
543 // in the NO_NAMESPACE unless prefixed.
544 assertNull(Verifier.checkNamespaceCollision(new Attribute("a", "b"), root));
545 // att is already on root, can't fail.
546 assertNull(Verifier.checkNamespaceCollision(att, root));
547 // but, we can fail an attribute on the child with changed p prefix
548 assertNotNull(Verifier.checkNamespaceCollision(new Attribute("a", "b", mscp), root));
549
550 }
551
552 @Test
553 public void testCheckPublicID() {
554 assertNull("invalidated valid publicid: null", Verifier.checkPublicID(null));
555 assertNull("invalidated valid publicid: ''", Verifier.checkPublicID(""));
556 assertNull("invalidated valid publicid: ' '", Verifier.checkPublicID(" "));
557 assertNull("invalidated valid publicid: contains \"'\"",
558 Verifier.checkPublicID("shroedinger's cat was here"));
559
560 assertNotNull(Verifier.checkPublicID("cannot have " + BADCHAR + " characters here"));
561
562 }
563
564 @Test
565 public void testCheckXMLName() {
566 assertNull(Verifier.checkXMLName("hi"));
567 assertNull(Verifier.checkXMLName("hi2you"));
568 assertNull(Verifier.checkXMLName("hi_you"));
569 assertNull(Verifier.checkXMLName("hi:you"));
570
571 assertNotNull(Verifier.checkXMLName(null));
572 assertNotNull(Verifier.checkXMLName(""));
573 assertNotNull(Verifier.checkXMLName(" "));
574 assertNotNull(Verifier.checkXMLName(" hi "));
575 assertNotNull(Verifier.checkXMLName("hi "));
576 assertNotNull(Verifier.checkXMLName(" hi"));
577 assertNotNull(Verifier.checkXMLName("2bad"));
578 }
579
580 @Test
581 public void testCheckSystemLiteral() {
582 assertNull(Verifier.checkSystemLiteral(null));
583 assertNull(Verifier.checkSystemLiteral(""));
584 assertNull(Verifier.checkSystemLiteral(" "));
585 assertNull(Verifier.checkSystemLiteral("frodo's theme "));
586 assertNull(Verifier.checkSystemLiteral("frodo has a \"theme\" "));
587
588 assertNotNull(Verifier.checkSystemLiteral("frodo's \"theme\" "));
589
590 }
591
592
593 @Test
594 public void testCheckURI() {
595 assertNull(Verifier.checkURI(null));
596 assertNull(Verifier.checkURI(""));
597 assertNull(Verifier.checkURI("http://www.jdom.org/index.html"));
598 assertNull(Verifier.checkURI("http://www.jdom.org:321/index.html"));
599 assertNull(Verifier.checkURI("http://www.jdom.org%32%01/index.html?%ab"));
600 assertNull(Verifier.checkURI("http://www.jdom.org/index.html%31"));
601
602 assertNotNull(Verifier.checkURI("http://www.jdom.org/ index.html"));
603 assertNotNull(Verifier.checkURI(" http://www.jdom.org/index.html "));
604 assertNotNull(Verifier.checkURI("http://www.jdom.org%3.21/index.html"));
605 assertNotNull(Verifier.checkURI("http://www.jdom.org%.21/index.html"));
606 assertNotNull(Verifier.checkURI("http://www.jdom.org%3g21/index.html"));
607 assertNotNull(Verifier.checkURI("http://www.jdom.org%3/index.html"));
608 assertNotNull(Verifier.checkURI("http://www.jdom.org" + BADCHAR + "/index.html"));
609 assertNotNull(Verifier.checkURI("http://www.jdom.org" + (char)0x05 + "/index.html"));
610 assertNotNull(Verifier.checkURI("http://www.jdom.org/index.html%3"));
611 }
612
613 @Test
614 public void testIsXMLCharacter() {
615 // this test is not part of the automatic tests because it takes an int
616 // as an argument, instead of a char.
617 // cherry-pick some tests.
618 assertTrue(Verifier.isXMLCharacter('\n'));
619 assertTrue(Verifier.isXMLCharacter('\r'));
620 assertTrue(Verifier.isXMLCharacter('\t'));
621 assertTrue(Verifier.isXMLCharacter(' '));
622 assertTrue(Verifier.isXMLCharacter(0xd7ff));
623 assertTrue(Verifier.isXMLCharacter(0xe000));
624 assertTrue(Verifier.isXMLCharacter(0x10000));
625
626 //cherry-pick values we know will fill out the coverage report.
627 assertFalse(Verifier.isXMLCharacter(0));
628 assertFalse(Verifier.isXMLCharacter(0x19));
629 assertFalse(Verifier.isXMLCharacter(0xd800));
630 assertFalse(Verifier.isXMLCharacter(0xffff));
631 assertFalse(Verifier.isXMLCharacter(0x110000));
632
633 }
634
635 @Test
636 public void testIsAllXMLWhitespace() {
637 assertTrue(Verifier.isAllXMLWhitespace(""));
638 assertTrue(Verifier.isAllXMLWhitespace(" "));
639 assertTrue(Verifier.isAllXMLWhitespace(" \r\n\t "));
640 try {
641 Verifier.isAllXMLWhitespace(null);
642 fail("Expected a NullPointerException, but it did not happen");
643 } catch (NullPointerException npe) {
644 // good.
645 }
646 assertFalse(Verifier.isAllXMLWhitespace(" a "));
647 assertFalse(Verifier.isAllXMLWhitespace(" &nbsp; "));
648 // \u00A0 is Non-Break space.
649 assertFalse(Verifier.isAllXMLWhitespace("\u00A0"));
650 }
651
652 }
0 package org.jdom.test.cases;
1
2 import static org.junit.Assert.*;
3
4 import org.jdom.Verifier;
5 import org.junit.Test;
6
7 @SuppressWarnings("javadoc")
8 public class TestVerifierCharacters {
9
10 // Automated test built by VerifierTestBuilder
11 @Test
12 public void testIsHighSurrogate () {
13 final int[] flips = new int[] {
14
15 0xd800, 0xdc00
16 };
17 int c = 0;
18 int fcnt = 0;
19 boolean valid = false;
20 final long ms = System.currentTimeMillis();
21 while (c <= Character.MAX_VALUE) {
22 if (fcnt < flips.length && flips[fcnt] == c) {
23 valid = !valid;
24 fcnt++;
25 }
26 if (valid) {
27 if (!Verifier.isHighSurrogate((char)c)) {
28 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isHighSurrogate but it failed.");
29 }
30 } else {
31 if (Verifier.isHighSurrogate((char)c)) {
32 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isHighSurrogate but it passed.");
33 }
34 }
35 c++;
36 }
37 System.out.printf("Completed test testIsHighSurrogate in %dms\n", System.currentTimeMillis() - ms);
38 }
39
40
41 // Automated test built by VerifierTestBuilder
42 @Test
43 public void testIsLowSurrogate () {
44 final int[] flips = new int[] {
45
46 0xdc00, 0xe000
47 };
48 int c = 0;
49 int fcnt = 0;
50 boolean valid = false;
51 final long ms = System.currentTimeMillis();
52 while (c <= Character.MAX_VALUE) {
53 if (fcnt < flips.length && flips[fcnt] == c) {
54 valid = !valid;
55 fcnt++;
56 }
57 if (valid) {
58 if (!Verifier.isLowSurrogate((char)c)) {
59 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isLowSurrogate but it failed.");
60 }
61 } else {
62 if (Verifier.isLowSurrogate((char)c)) {
63 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isLowSurrogate but it passed.");
64 }
65 }
66 c++;
67 }
68 System.out.printf("Completed test testIsLowSurrogate in %dms\n", System.currentTimeMillis() - ms);
69 }
70
71
72 // Automated test built by VerifierTestBuilder
73 @Test
74 public void testIsXMLDigit () {
75 final int[] flips = new int[] {
76
77 0x0030, 0x003a, 0x0660, 0x066a, 0x06f0, 0x06fa, 0x0966, 0x0970, 0x09e6, 0x09f0, 0x0a66, 0x0a70, 0x0ae6, 0x0af0, 0x0b66, 0x0b70,
78 0x0be7, 0x0bf0, 0x0c66, 0x0c70, 0x0ce6, 0x0cf0, 0x0d66, 0x0d70, 0x0e50, 0x0e5a, 0x0ed0, 0x0eda, 0x0f20, 0x0f2a
79 };
80 int c = 0;
81 int fcnt = 0;
82 boolean valid = false;
83 final long ms = System.currentTimeMillis();
84 while (c <= Character.MAX_VALUE) {
85 if (fcnt < flips.length && flips[fcnt] == c) {
86 valid = !valid;
87 fcnt++;
88 }
89 if (valid) {
90 if (!Verifier.isXMLDigit((char)c)) {
91 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isXMLDigit but it failed.");
92 }
93 } else {
94 if (Verifier.isXMLDigit((char)c)) {
95 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isXMLDigit but it passed.");
96 }
97 }
98 c++;
99 }
100 System.out.printf("Completed test testIsXMLDigit in %dms\n", System.currentTimeMillis() - ms);
101 }
102
103
104 // Automated test built by VerifierTestBuilder
105 @Test
106 public void testIsXMLNameCharacter () {
107 final int[] flips = new int[] {
108
109 0x002d, 0x002f, 0x0030, 0x003b, 0x0041, 0x005b, 0x005f, 0x0060, 0x0061, 0x007b, 0x00b7, 0x00b8, 0x00c0, 0x00d7, 0x00d8, 0x00f7,
110 0x00f8, 0x0132, 0x0134, 0x013f, 0x0141, 0x0149, 0x014a, 0x017f, 0x0180, 0x01c4, 0x01cd, 0x01f1, 0x01f4, 0x01f6, 0x01fa, 0x0218,
111 0x0250, 0x02a9, 0x02bb, 0x02c2, 0x02d0, 0x02d2, 0x0300, 0x0346, 0x0360, 0x0362, 0x0386, 0x038b, 0x038c, 0x038d, 0x038e, 0x03a2,
112 0x03a3, 0x03cf, 0x03d0, 0x03d7, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df, 0x03e0, 0x03e1, 0x03e2, 0x03f4, 0x0401, 0x040d,
113 0x040e, 0x0450, 0x0451, 0x045d, 0x045e, 0x0482, 0x0483, 0x0487, 0x0490, 0x04c5, 0x04c7, 0x04c9, 0x04cb, 0x04cd, 0x04d0, 0x04ec,
114 0x04ee, 0x04f6, 0x04f8, 0x04fa, 0x0531, 0x0557, 0x0559, 0x055a, 0x0561, 0x0587, 0x0591, 0x05a2, 0x05a3, 0x05ba, 0x05bb, 0x05be,
115 0x05bf, 0x05c0, 0x05c1, 0x05c3, 0x05c4, 0x05c5, 0x05d0, 0x05eb, 0x05f0, 0x05f3, 0x0621, 0x063b, 0x0640, 0x0653, 0x0660, 0x066a,
116 0x0670, 0x06b8, 0x06ba, 0x06bf, 0x06c0, 0x06cf, 0x06d0, 0x06d4, 0x06d5, 0x06e9, 0x06ea, 0x06ee, 0x06f0, 0x06fa, 0x0901, 0x0904,
117 0x0905, 0x093a, 0x093c, 0x094e, 0x0951, 0x0955, 0x0958, 0x0964, 0x0966, 0x0970, 0x0981, 0x0984, 0x0985, 0x098d, 0x098f, 0x0991,
118 0x0993, 0x09a9, 0x09aa, 0x09b1, 0x09b2, 0x09b3, 0x09b6, 0x09ba, 0x09bc, 0x09bd, 0x09be, 0x09c5, 0x09c7, 0x09c9, 0x09cb, 0x09ce,
119 0x09d7, 0x09d8, 0x09dc, 0x09de, 0x09df, 0x09e4, 0x09e6, 0x09f2, 0x0a02, 0x0a03, 0x0a05, 0x0a0b, 0x0a0f, 0x0a11, 0x0a13, 0x0a29,
120 0x0a2a, 0x0a31, 0x0a32, 0x0a34, 0x0a35, 0x0a37, 0x0a38, 0x0a3a, 0x0a3c, 0x0a3d, 0x0a3e, 0x0a43, 0x0a47, 0x0a49, 0x0a4b, 0x0a4e,
121 0x0a59, 0x0a5d, 0x0a5e, 0x0a5f, 0x0a66, 0x0a75, 0x0a81, 0x0a84, 0x0a85, 0x0a8c, 0x0a8d, 0x0a8e, 0x0a8f, 0x0a92, 0x0a93, 0x0aa9,
122 0x0aaa, 0x0ab1, 0x0ab2, 0x0ab4, 0x0ab5, 0x0aba, 0x0abc, 0x0ac6, 0x0ac7, 0x0aca, 0x0acb, 0x0ace, 0x0ae0, 0x0ae1, 0x0ae6, 0x0af0,
123 0x0b01, 0x0b04, 0x0b05, 0x0b0d, 0x0b0f, 0x0b11, 0x0b13, 0x0b29, 0x0b2a, 0x0b31, 0x0b32, 0x0b34, 0x0b36, 0x0b3a, 0x0b3c, 0x0b44,
124 0x0b47, 0x0b49, 0x0b4b, 0x0b4e, 0x0b56, 0x0b58, 0x0b5c, 0x0b5e, 0x0b5f, 0x0b62, 0x0b66, 0x0b70, 0x0b82, 0x0b84, 0x0b85, 0x0b8b,
125 0x0b8e, 0x0b91, 0x0b92, 0x0b96, 0x0b99, 0x0b9b, 0x0b9c, 0x0b9d, 0x0b9e, 0x0ba0, 0x0ba3, 0x0ba5, 0x0ba8, 0x0bab, 0x0bae, 0x0bb6,
126 0x0bb7, 0x0bba, 0x0bbe, 0x0bc3, 0x0bc6, 0x0bc9, 0x0bca, 0x0bce, 0x0bd7, 0x0bd8, 0x0be7, 0x0bf0, 0x0c01, 0x0c04, 0x0c05, 0x0c0d,
127 0x0c0e, 0x0c11, 0x0c12, 0x0c29, 0x0c2a, 0x0c34, 0x0c35, 0x0c3a, 0x0c3e, 0x0c45, 0x0c46, 0x0c49, 0x0c4a, 0x0c4e, 0x0c55, 0x0c57,
128 0x0c60, 0x0c62, 0x0c66, 0x0c70, 0x0c82, 0x0c84, 0x0c85, 0x0c8d, 0x0c8e, 0x0c91, 0x0c92, 0x0ca9, 0x0caa, 0x0cb4, 0x0cb5, 0x0cba,
129 0x0cbe, 0x0cc5, 0x0cc6, 0x0cc9, 0x0cca, 0x0cce, 0x0cd5, 0x0cd7, 0x0cde, 0x0cdf, 0x0ce0, 0x0ce2, 0x0ce6, 0x0cf0, 0x0d02, 0x0d04,
130 0x0d05, 0x0d0d, 0x0d0e, 0x0d11, 0x0d12, 0x0d29, 0x0d2a, 0x0d3a, 0x0d3e, 0x0d44, 0x0d46, 0x0d49, 0x0d4a, 0x0d4e, 0x0d57, 0x0d58,
131 0x0d60, 0x0d62, 0x0d66, 0x0d70, 0x0e01, 0x0e2f, 0x0e30, 0x0e3b, 0x0e40, 0x0e4f, 0x0e50, 0x0e5a, 0x0e81, 0x0e83, 0x0e84, 0x0e85,
132 0x0e87, 0x0e89, 0x0e8a, 0x0e8b, 0x0e8d, 0x0e8e, 0x0e94, 0x0e98, 0x0e99, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea5, 0x0ea6, 0x0ea7, 0x0ea8,
133 0x0eaa, 0x0eac, 0x0ead, 0x0eaf, 0x0eb0, 0x0eba, 0x0ebb, 0x0ebe, 0x0ec0, 0x0ec5, 0x0ec6, 0x0ec7, 0x0ec8, 0x0ece, 0x0ed0, 0x0eda,
134 0x0f18, 0x0f1a, 0x0f20, 0x0f2a, 0x0f35, 0x0f36, 0x0f37, 0x0f38, 0x0f39, 0x0f3a, 0x0f3e, 0x0f48, 0x0f49, 0x0f6a, 0x0f71, 0x0f85,
135 0x0f86, 0x0f8c, 0x0f90, 0x0f96, 0x0f97, 0x0f98, 0x0f99, 0x0fae, 0x0fb1, 0x0fb8, 0x0fb9, 0x0fba, 0x10a0, 0x10c6, 0x10d0, 0x10f7,
136 0x1100, 0x1101, 0x1102, 0x1104, 0x1105, 0x1108, 0x1109, 0x110a, 0x110b, 0x110d, 0x110e, 0x1113, 0x113c, 0x113d, 0x113e, 0x113f,
137 0x1140, 0x1141, 0x114c, 0x114d, 0x114e, 0x114f, 0x1150, 0x1151, 0x1154, 0x1156, 0x1159, 0x115a, 0x115f, 0x1162, 0x1163, 0x1164,
138 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, 0x116a, 0x116d, 0x116f, 0x1172, 0x1174, 0x1175, 0x1176, 0x119e, 0x119f, 0x11a8, 0x11a9,
139 0x11ab, 0x11ac, 0x11ae, 0x11b0, 0x11b7, 0x11b9, 0x11ba, 0x11bb, 0x11bc, 0x11c3, 0x11eb, 0x11ec, 0x11f0, 0x11f1, 0x11f9, 0x11fa,
140 0x1e00, 0x1e9c, 0x1ea0, 0x1efa, 0x1f00, 0x1f16, 0x1f18, 0x1f1e, 0x1f20, 0x1f46, 0x1f48, 0x1f4e, 0x1f50, 0x1f58, 0x1f59, 0x1f5a,
141 0x1f5b, 0x1f5c, 0x1f5d, 0x1f5e, 0x1f5f, 0x1f7e, 0x1f80, 0x1fb5, 0x1fb6, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc2, 0x1fc5, 0x1fc6, 0x1fcd,
142 0x1fd0, 0x1fd4, 0x1fd6, 0x1fdc, 0x1fe0, 0x1fed, 0x1ff2, 0x1ff5, 0x1ff6, 0x1ffd, 0x20d0, 0x20dd, 0x20e1, 0x20e2, 0x2126, 0x2127,
143 0x212a, 0x212c, 0x212e, 0x212f, 0x2180, 0x2183, 0x3005, 0x3006, 0x3007, 0x3008, 0x3021, 0x3030, 0x3031, 0x3036, 0x3041, 0x3095,
144 0x3099, 0x309b, 0x309d, 0x309f, 0x30a1, 0x30fb, 0x30fc, 0x30ff, 0x3105, 0x312d, 0x4e00, 0x9fa6, 0xac00, 0xd7a4
145 };
146 int c = 0;
147 int fcnt = 0;
148 boolean valid = false;
149 final long ms = System.currentTimeMillis();
150 while (c <= Character.MAX_VALUE) {
151 if (fcnt < flips.length && flips[fcnt] == c) {
152 valid = !valid;
153 fcnt++;
154 }
155 if (valid) {
156 if (!Verifier.isXMLNameCharacter((char)c)) {
157 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isXMLNameCharacter but it failed.");
158 }
159 } else {
160 if (Verifier.isXMLNameCharacter((char)c)) {
161 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isXMLNameCharacter but it passed.");
162 }
163 }
164 c++;
165 }
166 System.out.printf("Completed test testIsXMLNameCharacter in %dms\n", System.currentTimeMillis() - ms);
167 }
168
169
170 // Automated test built by VerifierTestBuilder
171 @Test
172 public void testIsXMLPublicIDCharacter () {
173 final int[] flips = new int[] {
174
175 0x0009, 0x000b, 0x000d, 0x000e, 0x0020, 0x0022, 0x0023, 0x0026, 0x0027, 0x003c, 0x003d, 0x003e, 0x003f, 0x005b, 0x005f, 0x0060,
176 0x0061, 0x007b
177 };
178 int c = 0;
179 int fcnt = 0;
180 boolean valid = false;
181 final long ms = System.currentTimeMillis();
182 while (c <= Character.MAX_VALUE) {
183 if (fcnt < flips.length && flips[fcnt] == c) {
184 valid = !valid;
185 fcnt++;
186 }
187 if (valid) {
188 if (!Verifier.isXMLPublicIDCharacter((char)c)) {
189 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isXMLPublicIDCharacter but it failed.");
190 }
191 } else {
192 if (Verifier.isXMLPublicIDCharacter((char)c)) {
193 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isXMLPublicIDCharacter but it passed.");
194 }
195 }
196 c++;
197 }
198 System.out.printf("Completed test testIsXMLPublicIDCharacter in %dms\n", System.currentTimeMillis() - ms);
199 }
200
201
202 // Automated test built by VerifierTestBuilder
203 @Test
204 public void testIsXMLNameStartCharacter () {
205 final int[] flips = new int[] {
206
207 0x003a, 0x003b, 0x0041, 0x005b, 0x005f, 0x0060, 0x0061, 0x007b, 0x00c0, 0x00d7, 0x00d8, 0x00f7, 0x00f8, 0x0132, 0x0134, 0x013f,
208 0x0141, 0x0149, 0x014a, 0x017f, 0x0180, 0x01c4, 0x01cd, 0x01f1, 0x01f4, 0x01f6, 0x01fa, 0x0218, 0x0250, 0x02a9, 0x02bb, 0x02c2,
209 0x0386, 0x0387, 0x0388, 0x038b, 0x038c, 0x038d, 0x038e, 0x03a2, 0x03a3, 0x03cf, 0x03d0, 0x03d7, 0x03da, 0x03db, 0x03dc, 0x03dd,
210 0x03de, 0x03df, 0x03e0, 0x03e1, 0x03e2, 0x03f4, 0x0401, 0x040d, 0x040e, 0x0450, 0x0451, 0x045d, 0x045e, 0x0482, 0x0490, 0x04c5,
211 0x04c7, 0x04c9, 0x04cb, 0x04cd, 0x04d0, 0x04ec, 0x04ee, 0x04f6, 0x04f8, 0x04fa, 0x0531, 0x0557, 0x0559, 0x055a, 0x0561, 0x0587,
212 0x05d0, 0x05eb, 0x05f0, 0x05f3, 0x0621, 0x063b, 0x0641, 0x064b, 0x0671, 0x06b8, 0x06ba, 0x06bf, 0x06c0, 0x06cf, 0x06d0, 0x06d4,
213 0x06d5, 0x06d6, 0x06e5, 0x06e7, 0x0905, 0x093a, 0x093d, 0x093e, 0x0958, 0x0962, 0x0985, 0x098d, 0x098f, 0x0991, 0x0993, 0x09a9,
214 0x09aa, 0x09b1, 0x09b2, 0x09b3, 0x09b6, 0x09ba, 0x09dc, 0x09de, 0x09df, 0x09e2, 0x09f0, 0x09f2, 0x0a05, 0x0a0b, 0x0a0f, 0x0a11,
215 0x0a13, 0x0a29, 0x0a2a, 0x0a31, 0x0a32, 0x0a34, 0x0a35, 0x0a37, 0x0a38, 0x0a3a, 0x0a59, 0x0a5d, 0x0a5e, 0x0a5f, 0x0a72, 0x0a75,
216 0x0a85, 0x0a8c, 0x0a8d, 0x0a8e, 0x0a8f, 0x0a92, 0x0a93, 0x0aa9, 0x0aaa, 0x0ab1, 0x0ab2, 0x0ab4, 0x0ab5, 0x0aba, 0x0abd, 0x0abe,
217 0x0ae0, 0x0ae1, 0x0b05, 0x0b0d, 0x0b0f, 0x0b11, 0x0b13, 0x0b29, 0x0b2a, 0x0b31, 0x0b32, 0x0b34, 0x0b36, 0x0b3a, 0x0b3d, 0x0b3e,
218 0x0b5c, 0x0b5e, 0x0b5f, 0x0b62, 0x0b85, 0x0b8b, 0x0b8e, 0x0b91, 0x0b92, 0x0b96, 0x0b99, 0x0b9b, 0x0b9c, 0x0b9d, 0x0b9e, 0x0ba0,
219 0x0ba3, 0x0ba5, 0x0ba8, 0x0bab, 0x0bae, 0x0bb6, 0x0bb7, 0x0bba, 0x0c05, 0x0c0d, 0x0c0e, 0x0c11, 0x0c12, 0x0c29, 0x0c2a, 0x0c34,
220 0x0c35, 0x0c3a, 0x0c60, 0x0c62, 0x0c85, 0x0c8d, 0x0c8e, 0x0c91, 0x0c92, 0x0ca9, 0x0caa, 0x0cb4, 0x0cb5, 0x0cba, 0x0cde, 0x0cdf,
221 0x0ce0, 0x0ce2, 0x0d05, 0x0d0d, 0x0d0e, 0x0d11, 0x0d12, 0x0d29, 0x0d2a, 0x0d3a, 0x0d60, 0x0d62, 0x0e01, 0x0e2f, 0x0e30, 0x0e31,
222 0x0e32, 0x0e34, 0x0e40, 0x0e46, 0x0e81, 0x0e83, 0x0e84, 0x0e85, 0x0e87, 0x0e89, 0x0e8a, 0x0e8b, 0x0e8d, 0x0e8e, 0x0e94, 0x0e98,
223 0x0e99, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea5, 0x0ea6, 0x0ea7, 0x0ea8, 0x0eaa, 0x0eac, 0x0ead, 0x0eaf, 0x0eb0, 0x0eb1, 0x0eb2, 0x0eb4,
224 0x0ebd, 0x0ebe, 0x0ec0, 0x0ec5, 0x0f40, 0x0f48, 0x0f49, 0x0f6a, 0x10a0, 0x10c6, 0x10d0, 0x10f7, 0x1100, 0x1101, 0x1102, 0x1104,
225 0x1105, 0x1108, 0x1109, 0x110a, 0x110b, 0x110d, 0x110e, 0x1113, 0x113c, 0x113d, 0x113e, 0x113f, 0x1140, 0x1141, 0x114c, 0x114d,
226 0x114e, 0x114f, 0x1150, 0x1151, 0x1154, 0x1156, 0x1159, 0x115a, 0x115f, 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168,
227 0x1169, 0x116a, 0x116d, 0x116f, 0x1172, 0x1174, 0x1175, 0x1176, 0x119e, 0x119f, 0x11a8, 0x11a9, 0x11ab, 0x11ac, 0x11ae, 0x11b0,
228 0x11b7, 0x11b9, 0x11ba, 0x11bb, 0x11bc, 0x11c3, 0x11eb, 0x11ec, 0x11f0, 0x11f1, 0x11f9, 0x11fa, 0x1e00, 0x1e9c, 0x1ea0, 0x1efa,
229 0x1f00, 0x1f16, 0x1f18, 0x1f1e, 0x1f20, 0x1f46, 0x1f48, 0x1f4e, 0x1f50, 0x1f58, 0x1f59, 0x1f5a, 0x1f5b, 0x1f5c, 0x1f5d, 0x1f5e,
230 0x1f5f, 0x1f7e, 0x1f80, 0x1fb5, 0x1fb6, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc2, 0x1fc5, 0x1fc6, 0x1fcd, 0x1fd0, 0x1fd4, 0x1fd6, 0x1fdc,
231 0x1fe0, 0x1fed, 0x1ff2, 0x1ff5, 0x1ff6, 0x1ffd, 0x2126, 0x2127, 0x212a, 0x212c, 0x212e, 0x212f, 0x2180, 0x2183, 0x3007, 0x3008,
232 0x3021, 0x302a, 0x3041, 0x3095, 0x30a1, 0x30fb, 0x3105, 0x312d, 0x4e00, 0x9fa6, 0xac00, 0xd7a4
233 };
234 int c = 0;
235 int fcnt = 0;
236 boolean valid = false;
237 final long ms = System.currentTimeMillis();
238 while (c <= Character.MAX_VALUE) {
239 if (fcnt < flips.length && flips[fcnt] == c) {
240 valid = !valid;
241 fcnt++;
242 }
243 if (valid) {
244 if (!Verifier.isXMLNameStartCharacter((char)c)) {
245 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isXMLNameStartCharacter but it failed.");
246 }
247 } else {
248 if (Verifier.isXMLNameStartCharacter((char)c)) {
249 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isXMLNameStartCharacter but it passed.");
250 }
251 }
252 c++;
253 }
254 System.out.printf("Completed test testIsXMLNameStartCharacter in %dms\n", System.currentTimeMillis() - ms);
255 }
256
257
258 // Automated test built by VerifierTestBuilder
259 @Test
260 public void testIsURICharacter () {
261 final int[] flips = new int[] {
262
263 0x0021, 0x0022, 0x0024, 0x003b, 0x003d, 0x003e, 0x003f, 0x005b, 0x005f, 0x0060, 0x0061, 0x007b, 0x007e, 0x007f
264 };
265 int c = 0;
266 int fcnt = 0;
267 boolean valid = false;
268 final long ms = System.currentTimeMillis();
269 while (c <= Character.MAX_VALUE) {
270 if (fcnt < flips.length && flips[fcnt] == c) {
271 valid = !valid;
272 fcnt++;
273 }
274 if (valid) {
275 if (!Verifier.isURICharacter((char)c)) {
276 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isURICharacter but it failed.");
277 }
278 } else {
279 if (Verifier.isURICharacter((char)c)) {
280 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isURICharacter but it passed.");
281 }
282 }
283 c++;
284 }
285 System.out.printf("Completed test testIsURICharacter in %dms\n", System.currentTimeMillis() - ms);
286 }
287
288
289 // Automated test built by VerifierTestBuilder
290 @Test
291 public void testIsHexDigit () {
292 final int[] flips = new int[] {
293
294 0x0030, 0x003a, 0x0041, 0x0047, 0x0061, 0x0067
295 };
296 int c = 0;
297 int fcnt = 0;
298 boolean valid = false;
299 final long ms = System.currentTimeMillis();
300 while (c <= Character.MAX_VALUE) {
301 if (fcnt < flips.length && flips[fcnt] == c) {
302 valid = !valid;
303 fcnt++;
304 }
305 if (valid) {
306 if (!Verifier.isHexDigit((char)c)) {
307 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isHexDigit but it failed.");
308 }
309 } else {
310 if (Verifier.isHexDigit((char)c)) {
311 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isHexDigit but it passed.");
312 }
313 }
314 c++;
315 }
316 System.out.printf("Completed test testIsHexDigit in %dms\n", System.currentTimeMillis() - ms);
317 }
318
319
320 // Automated test built by VerifierTestBuilder
321 @Test
322 public void testIsXMLLetter () {
323 final int[] flips = new int[] {
324
325 0x0041, 0x005b, 0x0061, 0x007b, 0x00c0, 0x00d7, 0x00d8, 0x00f7, 0x00f8, 0x0132, 0x0134, 0x013f, 0x0141, 0x0149, 0x014a, 0x017f,
326 0x0180, 0x01c4, 0x01cd, 0x01f1, 0x01f4, 0x01f6, 0x01fa, 0x0218, 0x0250, 0x02a9, 0x02bb, 0x02c2, 0x0386, 0x0387, 0x0388, 0x038b,
327 0x038c, 0x038d, 0x038e, 0x03a2, 0x03a3, 0x03cf, 0x03d0, 0x03d7, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df, 0x03e0, 0x03e1,
328 0x03e2, 0x03f4, 0x0401, 0x040d, 0x040e, 0x0450, 0x0451, 0x045d, 0x045e, 0x0482, 0x0490, 0x04c5, 0x04c7, 0x04c9, 0x04cb, 0x04cd,
329 0x04d0, 0x04ec, 0x04ee, 0x04f6, 0x04f8, 0x04fa, 0x0531, 0x0557, 0x0559, 0x055a, 0x0561, 0x0587, 0x05d0, 0x05eb, 0x05f0, 0x05f3,
330 0x0621, 0x063b, 0x0641, 0x064b, 0x0671, 0x06b8, 0x06ba, 0x06bf, 0x06c0, 0x06cf, 0x06d0, 0x06d4, 0x06d5, 0x06d6, 0x06e5, 0x06e7,
331 0x0905, 0x093a, 0x093d, 0x093e, 0x0958, 0x0962, 0x0985, 0x098d, 0x098f, 0x0991, 0x0993, 0x09a9, 0x09aa, 0x09b1, 0x09b2, 0x09b3,
332 0x09b6, 0x09ba, 0x09dc, 0x09de, 0x09df, 0x09e2, 0x09f0, 0x09f2, 0x0a05, 0x0a0b, 0x0a0f, 0x0a11, 0x0a13, 0x0a29, 0x0a2a, 0x0a31,
333 0x0a32, 0x0a34, 0x0a35, 0x0a37, 0x0a38, 0x0a3a, 0x0a59, 0x0a5d, 0x0a5e, 0x0a5f, 0x0a72, 0x0a75, 0x0a85, 0x0a8c, 0x0a8d, 0x0a8e,
334 0x0a8f, 0x0a92, 0x0a93, 0x0aa9, 0x0aaa, 0x0ab1, 0x0ab2, 0x0ab4, 0x0ab5, 0x0aba, 0x0abd, 0x0abe, 0x0ae0, 0x0ae1, 0x0b05, 0x0b0d,
335 0x0b0f, 0x0b11, 0x0b13, 0x0b29, 0x0b2a, 0x0b31, 0x0b32, 0x0b34, 0x0b36, 0x0b3a, 0x0b3d, 0x0b3e, 0x0b5c, 0x0b5e, 0x0b5f, 0x0b62,
336 0x0b85, 0x0b8b, 0x0b8e, 0x0b91, 0x0b92, 0x0b96, 0x0b99, 0x0b9b, 0x0b9c, 0x0b9d, 0x0b9e, 0x0ba0, 0x0ba3, 0x0ba5, 0x0ba8, 0x0bab,
337 0x0bae, 0x0bb6, 0x0bb7, 0x0bba, 0x0c05, 0x0c0d, 0x0c0e, 0x0c11, 0x0c12, 0x0c29, 0x0c2a, 0x0c34, 0x0c35, 0x0c3a, 0x0c60, 0x0c62,
338 0x0c85, 0x0c8d, 0x0c8e, 0x0c91, 0x0c92, 0x0ca9, 0x0caa, 0x0cb4, 0x0cb5, 0x0cba, 0x0cde, 0x0cdf, 0x0ce0, 0x0ce2, 0x0d05, 0x0d0d,
339 0x0d0e, 0x0d11, 0x0d12, 0x0d29, 0x0d2a, 0x0d3a, 0x0d60, 0x0d62, 0x0e01, 0x0e2f, 0x0e30, 0x0e31, 0x0e32, 0x0e34, 0x0e40, 0x0e46,
340 0x0e81, 0x0e83, 0x0e84, 0x0e85, 0x0e87, 0x0e89, 0x0e8a, 0x0e8b, 0x0e8d, 0x0e8e, 0x0e94, 0x0e98, 0x0e99, 0x0ea0, 0x0ea1, 0x0ea4,
341 0x0ea5, 0x0ea6, 0x0ea7, 0x0ea8, 0x0eaa, 0x0eac, 0x0ead, 0x0eaf, 0x0eb0, 0x0eb1, 0x0eb2, 0x0eb4, 0x0ebd, 0x0ebe, 0x0ec0, 0x0ec5,
342 0x0f40, 0x0f48, 0x0f49, 0x0f6a, 0x10a0, 0x10c6, 0x10d0, 0x10f7, 0x1100, 0x1101, 0x1102, 0x1104, 0x1105, 0x1108, 0x1109, 0x110a,
343 0x110b, 0x110d, 0x110e, 0x1113, 0x113c, 0x113d, 0x113e, 0x113f, 0x1140, 0x1141, 0x114c, 0x114d, 0x114e, 0x114f, 0x1150, 0x1151,
344 0x1154, 0x1156, 0x1159, 0x115a, 0x115f, 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, 0x116a, 0x116d, 0x116f,
345 0x1172, 0x1174, 0x1175, 0x1176, 0x119e, 0x119f, 0x11a8, 0x11a9, 0x11ab, 0x11ac, 0x11ae, 0x11b0, 0x11b7, 0x11b9, 0x11ba, 0x11bb,
346 0x11bc, 0x11c3, 0x11eb, 0x11ec, 0x11f0, 0x11f1, 0x11f9, 0x11fa, 0x1e00, 0x1e9c, 0x1ea0, 0x1efa, 0x1f00, 0x1f16, 0x1f18, 0x1f1e,
347 0x1f20, 0x1f46, 0x1f48, 0x1f4e, 0x1f50, 0x1f58, 0x1f59, 0x1f5a, 0x1f5b, 0x1f5c, 0x1f5d, 0x1f5e, 0x1f5f, 0x1f7e, 0x1f80, 0x1fb5,
348 0x1fb6, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc2, 0x1fc5, 0x1fc6, 0x1fcd, 0x1fd0, 0x1fd4, 0x1fd6, 0x1fdc, 0x1fe0, 0x1fed, 0x1ff2, 0x1ff5,
349 0x1ff6, 0x1ffd, 0x2126, 0x2127, 0x212a, 0x212c, 0x212e, 0x212f, 0x2180, 0x2183, 0x3007, 0x3008, 0x3021, 0x302a, 0x3041, 0x3095,
350 0x30a1, 0x30fb, 0x3105, 0x312d, 0x4e00, 0x9fa6, 0xac00, 0xd7a4
351 };
352 int c = 0;
353 int fcnt = 0;
354 boolean valid = false;
355 final long ms = System.currentTimeMillis();
356 while (c <= Character.MAX_VALUE) {
357 if (fcnt < flips.length && flips[fcnt] == c) {
358 valid = !valid;
359 fcnt++;
360 }
361 if (valid) {
362 if (!Verifier.isXMLLetter((char)c)) {
363 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isXMLLetter but it failed.");
364 }
365 } else {
366 if (Verifier.isXMLLetter((char)c)) {
367 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isXMLLetter but it passed.");
368 }
369 }
370 c++;
371 }
372 System.out.printf("Completed test testIsXMLLetter in %dms\n", System.currentTimeMillis() - ms);
373 }
374
375
376 // Automated test built by VerifierTestBuilder
377 @Test
378 public void testIsXMLCombiningChar () {
379 final int[] flips = new int[] {
380
381 0x0300, 0x0346, 0x0360, 0x0362, 0x0483, 0x0487, 0x0591, 0x05a2, 0x05a3, 0x05ba, 0x05bb, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c3,
382 0x05c4, 0x05c5, 0x064b, 0x0653, 0x0670, 0x0671, 0x06d6, 0x06e5, 0x06e7, 0x06e9, 0x06ea, 0x06ee, 0x0901, 0x0904, 0x093c, 0x093d,
383 0x093e, 0x094e, 0x0951, 0x0955, 0x0962, 0x0964, 0x0981, 0x0984, 0x09bc, 0x09bd, 0x09be, 0x09c5, 0x09c7, 0x09c9, 0x09cb, 0x09ce,
384 0x09d7, 0x09d8, 0x09e2, 0x09e4, 0x0a02, 0x0a03, 0x0a3c, 0x0a3d, 0x0a3e, 0x0a43, 0x0a47, 0x0a49, 0x0a4b, 0x0a4e, 0x0a70, 0x0a72,
385 0x0a81, 0x0a84, 0x0abc, 0x0abd, 0x0abe, 0x0ac6, 0x0ac7, 0x0aca, 0x0acb, 0x0ace, 0x0b01, 0x0b04, 0x0b3c, 0x0b3d, 0x0b3e, 0x0b44,
386 0x0b47, 0x0b49, 0x0b4b, 0x0b4e, 0x0b56, 0x0b58, 0x0b82, 0x0b84, 0x0bbe, 0x0bc3, 0x0bc6, 0x0bc9, 0x0bca, 0x0bce, 0x0bd7, 0x0bd8,
387 0x0c01, 0x0c04, 0x0c3e, 0x0c45, 0x0c46, 0x0c49, 0x0c4a, 0x0c4e, 0x0c55, 0x0c57, 0x0c82, 0x0c84, 0x0cbe, 0x0cc5, 0x0cc6, 0x0cc9,
388 0x0cca, 0x0cce, 0x0cd5, 0x0cd7, 0x0d02, 0x0d04, 0x0d3e, 0x0d44, 0x0d46, 0x0d49, 0x0d4a, 0x0d4e, 0x0d57, 0x0d58, 0x0e31, 0x0e32,
389 0x0e34, 0x0e3b, 0x0e47, 0x0e4f, 0x0eb1, 0x0eb2, 0x0eb4, 0x0eba, 0x0ebb, 0x0ebd, 0x0ec8, 0x0ece, 0x0f18, 0x0f1a, 0x0f35, 0x0f36,
390 0x0f37, 0x0f38, 0x0f39, 0x0f3a, 0x0f3e, 0x0f40, 0x0f71, 0x0f85, 0x0f86, 0x0f8c, 0x0f90, 0x0f96, 0x0f97, 0x0f98, 0x0f99, 0x0fae,
391 0x0fb1, 0x0fb8, 0x0fb9, 0x0fba, 0x20d0, 0x20dd, 0x20e1, 0x20e2, 0x302a, 0x3030, 0x3099, 0x309b
392 };
393 int c = 0;
394 int fcnt = 0;
395 boolean valid = false;
396 final long ms = System.currentTimeMillis();
397 while (c <= Character.MAX_VALUE) {
398 if (fcnt < flips.length && flips[fcnt] == c) {
399 valid = !valid;
400 fcnt++;
401 }
402 if (valid) {
403 if (!Verifier.isXMLCombiningChar((char)c)) {
404 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isXMLCombiningChar but it failed.");
405 }
406 } else {
407 if (Verifier.isXMLCombiningChar((char)c)) {
408 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isXMLCombiningChar but it passed.");
409 }
410 }
411 c++;
412 }
413 System.out.printf("Completed test testIsXMLCombiningChar in %dms\n", System.currentTimeMillis() - ms);
414 }
415
416
417 // Automated test built by VerifierTestBuilder
418 @Test
419 public void testIsXMLExtender () {
420 final int[] flips = new int[] {
421
422 0x00b7, 0x00b8, 0x02d0, 0x02d2, 0x0387, 0x0388, 0x0640, 0x0641, 0x0e46, 0x0e47, 0x0ec6, 0x0ec7, 0x3005, 0x3006, 0x3031, 0x3036,
423 0x309d, 0x309f, 0x30fc, 0x30ff
424 };
425 int c = 0;
426 int fcnt = 0;
427 boolean valid = false;
428 final long ms = System.currentTimeMillis();
429 while (c <= Character.MAX_VALUE) {
430 if (fcnt < flips.length && flips[fcnt] == c) {
431 valid = !valid;
432 fcnt++;
433 }
434 if (valid) {
435 if (!Verifier.isXMLExtender((char)c)) {
436 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isXMLExtender but it failed.");
437 }
438 } else {
439 if (Verifier.isXMLExtender((char)c)) {
440 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isXMLExtender but it passed.");
441 }
442 }
443 c++;
444 }
445 System.out.printf("Completed test testIsXMLExtender in %dms\n", System.currentTimeMillis() - ms);
446 }
447
448
449 // Automated test built by VerifierTestBuilder
450 @Test
451 public void testIsXMLLetterOrDigit () {
452 final int[] flips = new int[] {
453
454 0x0030, 0x003a, 0x0041, 0x005b, 0x0061, 0x007b, 0x00c0, 0x00d7, 0x00d8, 0x00f7, 0x00f8, 0x0132, 0x0134, 0x013f, 0x0141, 0x0149,
455 0x014a, 0x017f, 0x0180, 0x01c4, 0x01cd, 0x01f1, 0x01f4, 0x01f6, 0x01fa, 0x0218, 0x0250, 0x02a9, 0x02bb, 0x02c2, 0x0386, 0x0387,
456 0x0388, 0x038b, 0x038c, 0x038d, 0x038e, 0x03a2, 0x03a3, 0x03cf, 0x03d0, 0x03d7, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df,
457 0x03e0, 0x03e1, 0x03e2, 0x03f4, 0x0401, 0x040d, 0x040e, 0x0450, 0x0451, 0x045d, 0x045e, 0x0482, 0x0490, 0x04c5, 0x04c7, 0x04c9,
458 0x04cb, 0x04cd, 0x04d0, 0x04ec, 0x04ee, 0x04f6, 0x04f8, 0x04fa, 0x0531, 0x0557, 0x0559, 0x055a, 0x0561, 0x0587, 0x05d0, 0x05eb,
459 0x05f0, 0x05f3, 0x0621, 0x063b, 0x0641, 0x064b, 0x0660, 0x066a, 0x0671, 0x06b8, 0x06ba, 0x06bf, 0x06c0, 0x06cf, 0x06d0, 0x06d4,
460 0x06d5, 0x06d6, 0x06e5, 0x06e7, 0x06f0, 0x06fa, 0x0905, 0x093a, 0x093d, 0x093e, 0x0958, 0x0962, 0x0966, 0x0970, 0x0985, 0x098d,
461 0x098f, 0x0991, 0x0993, 0x09a9, 0x09aa, 0x09b1, 0x09b2, 0x09b3, 0x09b6, 0x09ba, 0x09dc, 0x09de, 0x09df, 0x09e2, 0x09e6, 0x09f2,
462 0x0a05, 0x0a0b, 0x0a0f, 0x0a11, 0x0a13, 0x0a29, 0x0a2a, 0x0a31, 0x0a32, 0x0a34, 0x0a35, 0x0a37, 0x0a38, 0x0a3a, 0x0a59, 0x0a5d,
463 0x0a5e, 0x0a5f, 0x0a66, 0x0a70, 0x0a72, 0x0a75, 0x0a85, 0x0a8c, 0x0a8d, 0x0a8e, 0x0a8f, 0x0a92, 0x0a93, 0x0aa9, 0x0aaa, 0x0ab1,
464 0x0ab2, 0x0ab4, 0x0ab5, 0x0aba, 0x0abd, 0x0abe, 0x0ae0, 0x0ae1, 0x0ae6, 0x0af0, 0x0b05, 0x0b0d, 0x0b0f, 0x0b11, 0x0b13, 0x0b29,
465 0x0b2a, 0x0b31, 0x0b32, 0x0b34, 0x0b36, 0x0b3a, 0x0b3d, 0x0b3e, 0x0b5c, 0x0b5e, 0x0b5f, 0x0b62, 0x0b66, 0x0b70, 0x0b85, 0x0b8b,
466 0x0b8e, 0x0b91, 0x0b92, 0x0b96, 0x0b99, 0x0b9b, 0x0b9c, 0x0b9d, 0x0b9e, 0x0ba0, 0x0ba3, 0x0ba5, 0x0ba8, 0x0bab, 0x0bae, 0x0bb6,
467 0x0bb7, 0x0bba, 0x0be7, 0x0bf0, 0x0c05, 0x0c0d, 0x0c0e, 0x0c11, 0x0c12, 0x0c29, 0x0c2a, 0x0c34, 0x0c35, 0x0c3a, 0x0c60, 0x0c62,
468 0x0c66, 0x0c70, 0x0c85, 0x0c8d, 0x0c8e, 0x0c91, 0x0c92, 0x0ca9, 0x0caa, 0x0cb4, 0x0cb5, 0x0cba, 0x0cde, 0x0cdf, 0x0ce0, 0x0ce2,
469 0x0ce6, 0x0cf0, 0x0d05, 0x0d0d, 0x0d0e, 0x0d11, 0x0d12, 0x0d29, 0x0d2a, 0x0d3a, 0x0d60, 0x0d62, 0x0d66, 0x0d70, 0x0e01, 0x0e2f,
470 0x0e30, 0x0e31, 0x0e32, 0x0e34, 0x0e40, 0x0e46, 0x0e50, 0x0e5a, 0x0e81, 0x0e83, 0x0e84, 0x0e85, 0x0e87, 0x0e89, 0x0e8a, 0x0e8b,
471 0x0e8d, 0x0e8e, 0x0e94, 0x0e98, 0x0e99, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea5, 0x0ea6, 0x0ea7, 0x0ea8, 0x0eaa, 0x0eac, 0x0ead, 0x0eaf,
472 0x0eb0, 0x0eb1, 0x0eb2, 0x0eb4, 0x0ebd, 0x0ebe, 0x0ec0, 0x0ec5, 0x0ed0, 0x0eda, 0x0f20, 0x0f2a, 0x0f40, 0x0f48, 0x0f49, 0x0f6a,
473 0x10a0, 0x10c6, 0x10d0, 0x10f7, 0x1100, 0x1101, 0x1102, 0x1104, 0x1105, 0x1108, 0x1109, 0x110a, 0x110b, 0x110d, 0x110e, 0x1113,
474 0x113c, 0x113d, 0x113e, 0x113f, 0x1140, 0x1141, 0x114c, 0x114d, 0x114e, 0x114f, 0x1150, 0x1151, 0x1154, 0x1156, 0x1159, 0x115a,
475 0x115f, 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, 0x116a, 0x116d, 0x116f, 0x1172, 0x1174, 0x1175, 0x1176,
476 0x119e, 0x119f, 0x11a8, 0x11a9, 0x11ab, 0x11ac, 0x11ae, 0x11b0, 0x11b7, 0x11b9, 0x11ba, 0x11bb, 0x11bc, 0x11c3, 0x11eb, 0x11ec,
477 0x11f0, 0x11f1, 0x11f9, 0x11fa, 0x1e00, 0x1e9c, 0x1ea0, 0x1efa, 0x1f00, 0x1f16, 0x1f18, 0x1f1e, 0x1f20, 0x1f46, 0x1f48, 0x1f4e,
478 0x1f50, 0x1f58, 0x1f59, 0x1f5a, 0x1f5b, 0x1f5c, 0x1f5d, 0x1f5e, 0x1f5f, 0x1f7e, 0x1f80, 0x1fb5, 0x1fb6, 0x1fbd, 0x1fbe, 0x1fbf,
479 0x1fc2, 0x1fc5, 0x1fc6, 0x1fcd, 0x1fd0, 0x1fd4, 0x1fd6, 0x1fdc, 0x1fe0, 0x1fed, 0x1ff2, 0x1ff5, 0x1ff6, 0x1ffd, 0x2126, 0x2127,
480 0x212a, 0x212c, 0x212e, 0x212f, 0x2180, 0x2183, 0x3007, 0x3008, 0x3021, 0x302a, 0x3041, 0x3095, 0x30a1, 0x30fb, 0x3105, 0x312d,
481 0x4e00, 0x9fa6, 0xac00, 0xd7a4
482 };
483 int c = 0;
484 int fcnt = 0;
485 boolean valid = false;
486 final long ms = System.currentTimeMillis();
487 while (c <= Character.MAX_VALUE) {
488 if (fcnt < flips.length && flips[fcnt] == c) {
489 valid = !valid;
490 fcnt++;
491 }
492 if (valid) {
493 if (!Verifier.isXMLLetterOrDigit((char)c)) {
494 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isXMLLetterOrDigit but it failed.");
495 }
496 } else {
497 if (Verifier.isXMLLetterOrDigit((char)c)) {
498 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isXMLLetterOrDigit but it passed.");
499 }
500 }
501 c++;
502 }
503 System.out.printf("Completed test testIsXMLLetterOrDigit in %dms\n", System.currentTimeMillis() - ms);
504 }
505
506
507 // Automated test built by VerifierTestBuilder
508 @Test
509 public void testIsXMLWhitespace () {
510 final int[] flips = new int[] {
511
512 0x0009, 0x000b, 0x000d, 0x000e, 0x0020, 0x0021
513 };
514 int c = 0;
515 int fcnt = 0;
516 boolean valid = false;
517 final long ms = System.currentTimeMillis();
518 while (c <= Character.MAX_VALUE) {
519 if (fcnt < flips.length && flips[fcnt] == c) {
520 valid = !valid;
521 fcnt++;
522 }
523 if (valid) {
524 if (!Verifier.isXMLWhitespace((char)c)) {
525 fail("Expected char 0x" + Integer.toHexString(c) + " to pass isXMLWhitespace but it failed.");
526 }
527 } else {
528 if (Verifier.isXMLWhitespace((char)c)) {
529 fail("Expected char 0x" + Integer.toHexString(c) + " to fail isXMLWhitespace but it passed.");
530 }
531 }
532 c++;
533 }
534 System.out.printf("Completed test testIsXMLWhitespace in %dms\n", System.currentTimeMillis() - ms);
535 }
536
537 }
0 package org.jdom.test.cases.adapters;
1
2 import org.junit.Test;
3 import org.w3c.dom.Document;
4
5 import org.jdom.JDOMException;
6 import org.jdom.adapters.JAXPDOMAdapter;
7
8 @SuppressWarnings("javadoc")
9 public class TestJAXPDOMAdapter {
10
11 @Test
12 public void testCreateDocument() throws JDOMException {
13 for (int i = 10; i > 0; i--) {
14 timeDoc();
15 }
16 }
17
18 private void timeDoc() throws JDOMException {
19 long time = System.nanoTime();
20 long hash = 0L;
21 final int cnt = 1000;
22 for (int i = 0; i < cnt; i++) {
23 Document doc = new JAXPDOMAdapter().createDocument();
24 hash += doc.hashCode();
25 }
26 time = System.nanoTime() - time;
27 System.out.printf("JAXPDOMAdapter Speed %.3f %d\n", (time / 1000000.0) / cnt, hash & 0x01);
28 }
29
30 }
0 package org.jdom.test.cases.filter;
1
2 import static org.junit.Assert.assertFalse;
3 import static org.junit.Assert.assertTrue;
4 import static org.junit.Assert.assertEquals;
5 import static org.junit.Assert.fail;
6
7 import java.util.ArrayList;
8 import java.util.Iterator;
9 import java.util.LinkedList;
10 import java.util.List;
11 import java.util.RandomAccess;
12
13 import org.jdom.Attribute;
14 import org.jdom.CDATA;
15 import org.jdom.Comment;
16 import org.jdom.Content;
17 import org.jdom.DocType;
18 import org.jdom.Document;
19 import org.jdom.Element;
20 import org.jdom.EntityRef;
21 import org.jdom.Namespace;
22 import org.jdom.Parent;
23 import org.jdom.ProcessingInstruction;
24 import org.jdom.Text;
25 import org.jdom.filter2.*;
26 import org.jdom.test.util.UnitTestUtil;
27
28 @SuppressWarnings("javadoc")
29 public class AbstractTestFilter {
30
31 protected static final void assertFilterNotEquals(Filter<?> a, Filter<?> b) {
32 assertTrue("A Filter is null.", a != null);
33 assertTrue("B Filter is null.", b != null);
34 assertTrue (!a.equals(null));
35 assertTrue (!b.equals(null));
36 if (a.equals(b) || b.equals(a)) {
37 fail("Filters are equals(), but they are not supposed to be: " +
38 a.toString() + " and " + b.toString());
39 }
40 if (a.hashCode() == b.hashCode()) {
41 System.out.println("Two different (not equals() ) Filters have " +
42 "the same hashCode(): " + a.hashCode() + "\n " +
43 a.toString() + " \n " + b.toString());
44 }
45 Filter<Content> base = new ContentFilter();
46 assertFalse(base.refine(a).equals(base.refine(b)));
47 }
48
49 protected static final void assertFilterEquals(Filter<?> a, Filter<?> b) {
50 assertTrue("A Filter is null.", a != null);
51 assertTrue("B Filter is null.", b != null);
52 assertTrue (!a.equals(null));
53 assertTrue (!b.equals(null));
54 if (!a.equals(a)) {
55 fail("Filter " + a.toString() + " is not equals() to itself");
56 }
57 if (!b.equals(b)) {
58 fail("Filter " + b.toString() + " is not equals() to itself");
59 }
60 if (!a.equals(b)) {
61 fail("Filters are not equals(), but they are supposed to be: " +
62 a.toString() + " and " + b.toString());
63 }
64 if (!b.equals(a)) {
65 fail("Filters a.equals(b), but not b.equals(a) : " +
66 a.toString() + " and " + b.toString());
67 }
68 if (a.hashCode() != b.hashCode()) {
69 fail("Both filters are equals(), but their hashCode() values differ: " +
70 a.toString() + " and " + b.toString());
71 }
72 Filter<Content> base = new ContentFilter();
73 assertTrue(base.refine(a).equals(base.refine(b)));
74 }
75
76 protected interface CallBack {
77 boolean isValid(Object c);
78 }
79
80 protected class NegateCallBack implements CallBack {
81 private final CallBack basecallback;
82 public NegateCallBack(CallBack base) {
83 basecallback = base;
84 }
85 @Override
86 public boolean isValid(Object c) {
87 return !basecallback.isValid(c);
88 }
89 }
90
91 protected class AndCallBack implements CallBack {
92 private final CallBack onecallback, twocallback;
93 public AndCallBack(CallBack one, CallBack two) {
94 onecallback = one;
95 twocallback = two;
96 }
97 @Override
98 public boolean isValid(Object c) {
99 // do not want to do short-circuit || logic.
100 // Make seperate statements
101 boolean one = onecallback.isValid(c);
102 boolean two = twocallback.isValid(c);
103 return one && two;
104 }
105 }
106
107 protected class OrCallBack implements CallBack {
108 private final CallBack onecallback, twocallback;
109 public OrCallBack(CallBack one, CallBack two) {
110 onecallback = one;
111 twocallback = two;
112 }
113 @Override
114 public boolean isValid(Object c) {
115 // do not want to do short-circuit || logic.
116 // Make seperate statements
117 boolean one = onecallback.isValid(c);
118 boolean two = twocallback.isValid(c);
119 return one || two;
120 }
121 }
122
123 private class TrueCallBack implements CallBack {
124 @Override
125 public boolean isValid(Object c) {
126 return true;
127 }
128 }
129
130 private class FalseCallBack implements CallBack {
131 @Override
132 public boolean isValid(Object c) {
133 return false;
134 }
135 }
136
137 private final Document doc;
138 private final Element root;
139 private final Namespace testns;
140 private final Content[] rootcontent;
141 private final Content[] doccontent;
142
143 protected AbstractTestFilter() {
144
145 root = new Element("root");
146 testns = Namespace.getNamespace("testns", "http://jdom.org/testns");
147
148 Element zero = new Element("zero");
149 Element one = new Element("one");
150 Element two = new Element("two");
151 Element three = new Element("three", testns);
152 Element four = new Element("four");
153 Element five = new Element("five", testns);
154 Element six = new Element("six");
155 Element seven = new Element("seven");
156
157 EntityRef e0 = new EntityRef("erent", "ERSystemID");
158
159 Text t0 = new Text("t0");
160 Text t1 = new Text("t1");
161 Text t2 = new Text("t2");
162 Text t3 = new Text("t3");
163 Text t4 = new Text("t4");
164 Text t5 = new Text("t5");
165 Text t6 = new Text("t6");
166 Text t7 = new Text("t7");
167 Text t8 = new Text("t8");
168 Text t9 = new Text("t9");
169
170 CDATA c0 = new CDATA("c0");
171 CDATA c1 = new CDATA("c1");
172
173 Comment com0 = new Comment("Comment0");
174 Comment com1 = new Comment("Comment1");
175 Comment com2 = new Comment("Comment2");
176
177 DocType doctype = new DocType("root");
178 ProcessingInstruction pi = new ProcessingInstruction ("dummy", "name=value");
179 Comment doccom = new Comment("DocComment");
180 doc = new Document();
181
182
183 doc.addContent(doctype);
184 doc.addContent(pi);
185 doc.addContent(doccom);
186 doc.addContent(root);
187
188 doccontent = new Content[] {doctype, pi, doccom, root};
189
190 rootcontent = new Content[] {t0, com0, t1, zero, t2, one, t3, com1,
191 t4, two, t5, three, c0, four, t6, e0, five, t7, six, c1, t8,
192 seven, t9, com2};
193
194 for (Content c : rootcontent ) {
195 root.addContent(c);
196 }
197
198 }
199
200 protected Document getDocument() {
201 return doc;
202 }
203
204 protected Element getRoot() {
205 return root;
206 }
207
208 protected Content[] getDocumentContent() {
209 return doccontent;
210 }
211
212 protected Content[] getRootContent() {
213 return rootcontent;
214 }
215
216 protected Namespace getTestNamespace() {
217 return testns;
218 }
219
220 protected Content[] filter(Content[] input, Class<?>...types) {
221 ArrayList<Content> al = new ArrayList<Content>(input.length);
222 content: for (Content c : input) {
223 for (Class<?> cclass : types) {
224 if (cclass.isInstance(c)) {
225 al.add(c);
226 continue content;
227 }
228 }
229 }
230 return al.toArray(new Content[al.size()]);
231 }
232
233
234 protected <F extends Content> void exercise(Filter<F> af, Parent parent, CallBack callback) {
235 assertTrue("filter is null", af != null);
236 assertTrue("list is null", parent != null);
237 assertTrue("callback is null", callback != null);
238 assertTrue(af.toString() != null); // basic test to ensure toString is run.
239 // can never match null if it returns a <F extends Content>
240 assertFalse(af.matches(null));
241 // can never match Object if it returns a <F extends Content>
242 assertFalse(af.matches(new Object()));
243 exerciseCore(af, parent, callback);
244
245 // test the deserialized version of the Filter.
246 final Filter<F> des = UnitTestUtil.deSerialize(af);
247 assertTrue(des != af);
248 assertFilterEquals(af, des);
249 exerciseCore(des, parent, callback);
250
251 try {
252 Filter<?> or = af.or(null);
253 fail ("expected an exception from " + or);
254 } catch (RuntimeException re) {
255 // good
256 } catch (Exception e) {
257 fail ("Expected a RuntimeException.");
258 }
259
260 try {
261 Filter<F> and = af.and(null);
262 fail ("expected an exception from " + and);
263 } catch (RuntimeException re) {
264 // good
265 } catch (Exception e) {
266 fail ("Expected a RuntimeException.");
267 }
268
269 exerciseCore(af.negate().refine(Filters.content()), parent, new NegateCallBack(callback));
270 exerciseCore(af.or(af.negate()).refine(Filters.content()), parent, new TrueCallBack());
271 exerciseCore(af.or(UnitTestUtil.deSerialize(af)).refine(Filters.content()), parent, callback);
272 exerciseCore(af.negate().and(af).refine(Filters.content()), parent, new FalseCallBack());
273 exerciseCore(af.and(af).refine(Filters.content()), parent, callback);
274 exerciseCore(af.and(UnitTestUtil.deSerialize(af)).refine(Filters.content()), parent, callback);
275
276 Filter<?> nf = af.negate();
277 exerciseCore(nf.negate().refine(Filters.content()), parent, callback);
278 exerciseCore(nf.or(nf.negate()).refine(Filters.content()), parent, new TrueCallBack());
279 exerciseCore(nf.and(nf.negate()).refine(Filters.content()), parent, new FalseCallBack());
280
281
282 Filter<?> afor = UnitTestUtil.deSerialize(af).or(nf);
283 Filter<?> bfor = nf.or(af);
284 assertFilterEquals(afor, bfor);
285
286 Filter<F> afand = UnitTestUtil.deSerialize(af).and(nf);
287 Filter<?> bfand = nf.and(af);
288 assertFilterEquals(afand, bfand);
289
290 assertFalse(af.equals(null));
291 assertFalse(nf.equals(null));
292 assertFalse(afor.equals(null));
293 assertFalse(bfor.equals(null));
294 assertFalse(afand.equals(null));
295 assertFalse(bfand.equals(null));
296
297 }
298
299 private final void exerciseCore(Filter<? extends Content> ef, Parent parent, CallBack callback) {
300 // exercise the toString()
301 assertTrue(ef.toString() != null);
302 LinkedList<Content> oc = new LinkedList<Content>();
303 ArrayList<Content> mc = new ArrayList<Content>();
304 List<Content> cont = parent.getContent();
305 for (Content c : cont) {
306 oc.add(c);
307 assertTrue(parent == c.getParent());
308 if (parent instanceof Document) {
309 assertTrue(null == c.getParentElement());
310 } else {
311 assertTrue(parent == c.getParentElement());
312 }
313 boolean mat = ef.matches(c);
314 if (mat) {
315 mc.add(c);
316 }
317 boolean cbv = callback.isValid(c);
318 if (mat != cbv) {
319 fail ("Filter " + ef + " returned " + mat
320 + " but isValid CallBack returned " + cbv
321 + " for value " + c);
322 }
323 }
324 List<?> fc = ef.filter(oc);
325 assertTrue(fc instanceof RandomAccess);
326 assertTrue(fc.size() == mc.size());
327 for (int i = 0; i < fc.size(); i++) {
328 assertTrue(fc.get(i) == mc.get(i));
329 }
330 Filter<? extends Content> cf = UnitTestUtil.deSerialize(ef);
331 assertFilterEquals(cf, ef);
332 ContentFilter xf = new ContentFilter();
333 assertFilterEquals(cf.refine(xf), ef.refine(xf));
334 assertFilterEquals(xf.refine(cf), xf.refine(ef));
335 assertFalse(ef.equals(null));
336 assertFilterNotEquals(ef, ef.negate());
337 assertFilterNotEquals(ef.refine(xf), ef.negate().refine(xf));
338 assertFilterNotEquals(xf.refine(ef), xf.refine(ef.negate()));
339 List<Content> depth = new ArrayList<Content>();
340 depth.addAll(cont);
341 int sz = depth.size();
342 for (int i = 0; i < sz; i++) {
343 if (depth.get(i) instanceof Element) {
344 List<Content> kdata = ((Element)depth.get(i)).getContent();
345 depth.addAll(i+1, kdata);
346 sz += kdata.size();
347 }
348 }
349 Iterator<? extends Content> di = parent.getDescendants();
350
351 // confirm that the DepthIterator iterates over all content.
352 UnitTestUtil.testReadIterator(di, depth.toArray());
353
354 List<Content> filtered = new ArrayList<Content>(depth.size());
355 for (Iterator<Content> it = depth.iterator(); it.hasNext(); ) {
356 Content c = it.next();
357 if (callback.isValid(c)) {
358 filtered.add(c);
359 }
360 }
361
362 //
363 di = parent.getDescendants(AbstractFilter.toFilter(ef));
364 UnitTestUtil.testReadIterator(di, filtered.toArray());
365 assertEquals(filtered, ef.filter(depth));
366 }
367
368
369
370
371 protected <F extends Attribute> void exerciseAtt(Filter<F> af, Parent parent, CallBack callback) {
372 assertTrue("filter is null", af != null);
373 assertTrue("list is null", parent != null);
374 assertTrue("callback is null", callback != null);
375 assertTrue(af.toString() != null); // basic test to ensure toString is run.
376 // can never match null if it returns a <F extends Content>
377 assertFalse(af.matches(null));
378 // can never match Object if it returns a <F extends Content>
379 assertFalse(af.matches(new Object()));
380 exerciseCoreAtt(af, parent, callback);
381 try {
382 Filter<?> or = af.or(null);
383 fail ("expected an exception from " + or);
384 } catch (RuntimeException re) {
385 // good
386 } catch (Exception e) {
387 fail ("Expected a RuntimeException.");
388 }
389
390 try {
391 Filter<F> and = af.and(null);
392 fail ("expected an exception from " + and);
393 } catch (RuntimeException re) {
394 // good
395 } catch (Exception e) {
396 fail ("Expected a RuntimeException.");
397 }
398
399 //exerciseCoreAtt(af.negate().refine(Filters.attribute()), parent, new NegateCallBack(callback));
400 //exerciseCoreAtt(af.or(af.negate()).refine(Filters.attribute()), parent, new TrueCallBack());
401 exerciseCoreAtt(af.or(UnitTestUtil.deSerialize(af)).refine(Filters.attribute()), parent, callback);
402 //exerciseCoreAtt(af.negate().and(af).refine(Filters.attribute()), parent, new FalseCallBack());
403 exerciseCoreAtt(af.and(af).refine(Filters.attribute()), parent, callback);
404 exerciseCoreAtt(af.and(UnitTestUtil.deSerialize(af)).refine(Filters.attribute()), parent, callback);
405
406 Filter<?> nf = af.negate();
407 // exerciseCore(nf.negate().refine(Filters.content()), parent, callback);
408 // exerciseCore(nf.or(nf.negate()).refine(Filters.content()), parent, new TrueCallBack());
409 // exerciseCore(nf.and(nf.negate()).refine(Filters.content()), parent, new FalseCallBack());
410
411
412 Filter<?> afor = UnitTestUtil.deSerialize(af).or(nf);
413 Filter<?> bfor = nf.or(af);
414 assertFilterEquals(afor, bfor);
415
416 Filter<F> afand = UnitTestUtil.deSerialize(af).and(nf);
417 Filter<?> bfand = nf.and(af);
418 assertFilterEquals(afand, bfand);
419
420 assertFalse(af.equals(null));
421 assertFalse(nf.equals(null));
422 assertFalse(afor.equals(null));
423 assertFalse(bfor.equals(null));
424 assertFalse(afand.equals(null));
425 assertFalse(bfand.equals(null));
426
427 }
428
429 private final void exerciseCoreAtt(Filter<? extends Attribute> ef, Parent parent, CallBack callback) {
430 // exercise the toString()
431 assertTrue(ef.toString() != null);
432 List<Content> cont = parent.getContent();
433 for (Content c : cont) {
434 assertTrue(parent == c.getParent());
435 if (parent instanceof Document) {
436 assertTrue(null == c.getParentElement());
437 } else {
438 assertTrue(parent == c.getParentElement());
439 }
440 boolean mat = ef.matches(c);
441 boolean cbv = callback.isValid(c);
442 if (mat != cbv) {
443 fail ("Filter " + ef + " returned " + mat
444 + " but isValid CallBack returned " + cbv
445 + " for value " + c);
446 }
447 }
448 Filter<? extends Attribute> cf = UnitTestUtil.deSerialize(ef);
449 assertFilterEquals(cf, ef);
450 AttributeFilter xf = new AttributeFilter();
451 assertFilterEquals(cf.refine(xf), ef.refine(xf));
452 assertFilterEquals(xf.refine(cf), xf.refine(ef));
453 assertFalse(ef.equals(null));
454 assertFilterNotEquals(ef, ef.negate());
455 assertFilterNotEquals(ef.refine(xf), ef.negate().refine(xf));
456 assertFilterNotEquals(xf.refine(ef), xf.refine(ef.negate()));
457
458 List<Object> cnt = new ArrayList<Object>();
459 List<Attribute> atts = new ArrayList<Attribute>();
460 for (Iterator<Content> itc = parent.getDescendants(); itc.hasNext();) {
461 Content c = itc.next();
462 cnt.add(c);
463 if (c instanceof Element) {
464 cnt.addAll(((Element)c).getAttributes());
465 for (Attribute a : ((Element)c).getAttributes()) {
466 if (ef.matches(a)) {
467 atts.add(a);
468 }
469 }
470 }
471 }
472
473 List<? extends Attribute> filtered = ef.filter(cnt);
474
475 assertEquals(atts, filtered);
476 }
477
478
479 }
0 package org.jdom.test.cases.filter;
1
2 import org.jdom.Attribute;
3 import org.jdom.Namespace;
4 import org.jdom.filter2.AttributeFilter;
5 import org.junit.Test;
6
7 @SuppressWarnings("javadoc")
8 public class TestAtributeFilter extends AbstractTestFilter {
9
10 @Test
11 public void testAttributeFilter() {
12 AttributeFilter ef = new AttributeFilter();
13 CallBack cb = new CallBack() {
14 @Override
15 public boolean isValid(Object c) {
16 return c != null && c instanceof Attribute;
17 }
18 };
19 exerciseAtt(ef, getRoot(), cb);
20 exerciseAtt(ef, getDocument(), cb);
21 }
22
23 @Test
24 public void testElementFilterString() {
25 final String name = "four";
26 AttributeFilter ef = new AttributeFilter(name);
27 CallBack cb = new CallBack() {
28 @Override
29 public boolean isValid(Object c) {
30 return (c != null) && (c instanceof Attribute) &&
31 name.equals(((Attribute)c).getName());
32 }
33 };
34 exerciseAtt(ef, getRoot(), cb);
35 exerciseAtt(ef, getDocument(), cb);
36 }
37
38 @Test
39 public void testElementFilterNamespace() {
40 AttributeFilter efa = new AttributeFilter(Namespace.NO_NAMESPACE);
41 CallBack cba = new CallBack() {
42 @Override
43 public boolean isValid(Object c) {
44 return (c != null) && (c instanceof Attribute) &&
45 Namespace.NO_NAMESPACE.equals(((Attribute)c).getNamespace());
46 }
47 };
48 exerciseAtt(efa, getRoot(), cba);
49 exerciseAtt(efa, getDocument(), cba);
50
51 AttributeFilter efb = new AttributeFilter(getTestNamespace());
52 CallBack cbb = new CallBack() {
53 @Override
54 public boolean isValid(Object c) {
55 return (c != null) && (c instanceof Attribute) &&
56 getTestNamespace().equals(((Attribute)c).getNamespace());
57 }
58 };
59 exerciseAtt(efb, getRoot(), cbb);
60 exerciseAtt(efb, getDocument(), cbb);
61
62
63 }
64
65 @Test
66 public void testElementFilterStringNamespace() {
67 final String namea = "four";
68 AttributeFilter efa = new AttributeFilter(namea, Namespace.NO_NAMESPACE);
69 CallBack cba = new CallBack() {
70 @Override
71 public boolean isValid(Object c) {
72 return (c != null) && (c instanceof Attribute) &&
73 namea.equals(((Attribute)c).getName()) &&
74 Namespace.NO_NAMESPACE.equals(((Attribute)c).getNamespace());
75 }
76 };
77 exerciseAtt(efa, getRoot(), cba);
78 exerciseAtt(efa, getDocument(), cba);
79
80 final String nameb = "three";
81 AttributeFilter efb = new AttributeFilter(nameb, getTestNamespace());
82 CallBack cbb = new CallBack() {
83 @Override
84 public boolean isValid(Object c) {
85 return (c != null) && (c instanceof Attribute) &&
86 nameb.equals(((Attribute)c).getName()) &&
87 getTestNamespace().equals(((Attribute)c).getNamespace());
88 }
89 };
90 exerciseAtt(efb, getRoot(), cbb);
91 exerciseAtt(efb, getDocument(), cbb);
92
93 }
94
95 @Test
96 public void testEqualsObject() {
97 final String URI1 = "http://jdom.org/test1";
98 final String URI2 = "http://jdom.org/test2";
99 Namespace ns1a = Namespace.getNamespace("pfxa", URI1);
100 Namespace ns1b = Namespace.getNamespace("pfxb", URI1);
101 Namespace ns1c = Namespace.getNamespace(URI1);
102
103 Namespace ns2a = Namespace.getNamespace("pfxa", URI2);
104 Namespace ns2c = Namespace.getNamespace(URI2);
105
106 assertFilterEquals(new AttributeFilter("test"),
107 new AttributeFilter("test"));
108
109 // same namespace
110 assertFilterEquals(new AttributeFilter("test", ns1a),
111 new AttributeFilter("test", ns1a));
112
113 // same namespace URI (different prefix)
114 assertFilterEquals(new AttributeFilter("test", ns1a),
115 new AttributeFilter("test", ns1b));
116
117 // same namespace URI (different prefix)
118 assertFilterEquals(new AttributeFilter("test", ns1a),
119 new AttributeFilter("test", ns1c));
120
121 // same namespace URI (different prefix)
122 assertFilterEquals(new AttributeFilter(ns1a),
123 new AttributeFilter(ns1a));
124
125 // same namespace URI (different prefix)
126 assertFilterEquals(new AttributeFilter(ns1a),
127 new AttributeFilter(ns1b));
128
129 // same namespace URI (different prefix)
130 assertFilterEquals(new AttributeFilter(ns1a),
131 new AttributeFilter(ns1c));
132
133 assertFilterNotEquals(new AttributeFilter("test", ns1a),
134 new AttributeFilter(ns1a));
135
136 assertFilterNotEquals(new AttributeFilter("test"),
137 new AttributeFilter("testfoo"));
138
139 assertFilterNotEquals(new AttributeFilter("test"),
140 new AttributeFilter("test", Namespace.NO_NAMESPACE));
141
142 assertFilterNotEquals(new AttributeFilter("test", ns1a),
143 new AttributeFilter("test", Namespace.NO_NAMESPACE));
144
145 assertFilterNotEquals(new AttributeFilter("test", Namespace.NO_NAMESPACE),
146 new AttributeFilter("test", ns1a));
147
148 assertFilterNotEquals(new AttributeFilter(ns1a),
149 new AttributeFilter(ns2a));
150
151 assertFilterNotEquals(new AttributeFilter(ns1c),
152 new AttributeFilter(ns2c));
153
154 assertFilterNotEquals(new AttributeFilter(ns1c),
155 new AttributeFilter(ns1c).negate());
156
157 }
158
159 }
0 package org.jdom.test.cases.filter;
1
2 import static org.junit.Assert.fail;
3 import static org.junit.Assert.assertTrue;
4
5 import org.jdom.CDATA;
6 import org.jdom.Comment;
7 import org.jdom.DocType;
8 import org.jdom.Element;
9 import org.jdom.EntityRef;
10 import org.jdom.ProcessingInstruction;
11 import org.jdom.Text;
12 import org.jdom.filter2.ContentFilter;
13 import org.jdom.filter2.ElementFilter;
14 import org.jdom.test.util.UnitTestUtil;
15 import org.junit.Test;
16
17 @SuppressWarnings("javadoc")
18 public class TestContentFilter extends AbstractTestFilter {
19
20 private final int[] allContent = new int[] {
21 ContentFilter.CDATA, ContentFilter.COMMENT,
22 ContentFilter.DOCTYPE, ContentFilter.DOCUMENT,
23 ContentFilter.ELEMENT, ContentFilter.ENTITYREF,
24 ContentFilter.PI, ContentFilter.TEXT
25 };
26
27 @Test
28 public void testSetters() {
29 int mask = 0;
30 boolean flag = false;
31 ContentFilter cfa = new ContentFilter(false);
32 do {
33 flag = !flag;
34 for (int m : allContent) {
35 switch (m) {
36 case ContentFilter.CDATA :
37 cfa.setCDATAVisible(flag);
38 break;
39 case ContentFilter.COMMENT :
40 cfa.setCommentVisible(flag);
41 break;
42 case ContentFilter.DOCTYPE :
43 cfa.setDocTypeVisible(flag);
44 break;
45 case ContentFilter.DOCUMENT :
46 if (flag) {
47 cfa.setFilterMask(cfa.getFilterMask() | ContentFilter.DOCUMENT);
48 } else {
49 cfa.setFilterMask(cfa.getFilterMask() & (~ ContentFilter.DOCUMENT) );
50 }
51 break;
52 case ContentFilter.ELEMENT :
53 cfa.setElementVisible(flag);
54 break;
55 case ContentFilter.ENTITYREF :
56 cfa.setEntityRefVisible(flag);
57 break;
58 case ContentFilter.PI :
59 cfa.setPIVisible(flag);
60 break;
61 case ContentFilter.TEXT :
62 cfa.setTextVisible(flag);
63 break;
64 }
65 if (flag) {
66 mask |= m;
67 } else {
68 mask &= (~m);
69 }
70 if (cfa.getFilterMask() != mask) {
71 fail(String.format("ContentFilter Mask is out of sync after " +
72 "setting flag %d with value %s", m, flag));
73 }
74 }
75 } while (flag);
76 }
77
78 @Test
79 public void testDefaultDocumentContent() {
80 ContentFilter cf = new ContentFilter();
81 cf.setDocumentContent();
82 CallBack cb = new CallBack() {
83 @Override
84 public boolean isValid(Object c) {
85 if (c instanceof Element) {
86 return true;
87 }
88 if (c instanceof ProcessingInstruction) {
89 return true;
90 }
91 if (c instanceof DocType) {
92 return true;
93 }
94 if (c instanceof Comment) {
95 return true;
96 }
97 return false;
98 }
99 };
100
101 exerciseContent(cb, ContentFilter.PI, ContentFilter.ELEMENT,
102 ContentFilter.COMMENT, ContentFilter.DOCTYPE);
103
104 }
105
106 @Test
107 public void testAllElementContent() {
108 ContentFilter cf = new ContentFilter();
109 cf.setElementContent();
110 CallBack cb = new CallBack() {
111 @Override
112 public boolean isValid(Object c) {
113 if (c instanceof Element) {
114 return true;
115 }
116 if (c instanceof ProcessingInstruction) {
117 return true;
118 }
119 if (c instanceof EntityRef) {
120 return true;
121 }
122 if (c instanceof CDATA) {
123 return true;
124 }
125 if (c instanceof Text) {
126 return true;
127 }
128 if (c instanceof Comment) {
129 return true;
130 }
131 return false;
132 }
133 };
134
135 exerciseContent(cb, ContentFilter.ELEMENT, ContentFilter.ENTITYREF,
136 ContentFilter.COMMENT, ContentFilter.CDATA,
137 ContentFilter.TEXT, ContentFilter.PI);
138
139 }
140
141
142 @Test
143 public void testAllContentFilter() {
144 CallBack cb = new CallBack() {
145 @Override
146 public boolean isValid(Object c) {
147 return c != null;
148 }
149 };
150 exerciseContent(cb, ContentFilter.CDATA, ContentFilter.COMMENT,
151 ContentFilter.DOCTYPE, ContentFilter.DOCUMENT,
152 ContentFilter.ELEMENT, ContentFilter.ENTITYREF,
153 ContentFilter.PI, ContentFilter.TEXT);
154 }
155
156 @Test
157 public void testElementContentFilter() {
158 CallBack cb = new CallBack() {
159 @Override
160 public boolean isValid(Object c) {
161 return c instanceof Element;
162 }
163 };
164 exerciseContent(cb, ContentFilter.ELEMENT);
165 }
166
167 // @Test
168 // public void testDocumentContentFilter() {
169 // ContentFilter cf = new ContentFilter(ContentFilter.DOCUMENT);
170 // assertTrue(cf.matches(getDocument()));
171 // assertFalse(cf.matches(getRoot()));
172 // ContentFilter cfe = new ContentFilter(ContentFilter.ELEMENT);
173 // assertFalse(cfe.matches(getDocument()));
174 // }
175
176 @Test
177 public void testDocTypeContentFilter() {
178 CallBack cb = new CallBack() {
179 @Override
180 public boolean isValid(Object c) {
181 return c instanceof DocType;
182 }
183 };
184 exerciseContent(cb, ContentFilter.DOCTYPE);
185 }
186
187 @Test
188 public void testPIContentFilter() {
189 CallBack cb = new CallBack() {
190 @Override
191 public boolean isValid(Object c) {
192 return c instanceof ProcessingInstruction;
193 }
194 };
195 exerciseContent(cb, ContentFilter.PI);
196 }
197
198 @Test
199 public void testCDATAContentFilter() {
200 CallBack cb = new CallBack() {
201 @Override
202 public boolean isValid(Object c) {
203 return c instanceof CDATA;
204 }
205 };
206 exerciseContent(cb, ContentFilter.CDATA);
207 }
208
209 @Test
210 public void testCommentContentFilter() {
211 CallBack cb = new CallBack() {
212 @Override
213 public boolean isValid(Object c) {
214 return c instanceof Comment;
215 }
216 };
217 exerciseContent(cb, ContentFilter.COMMENT);
218 }
219
220 private void exerciseContent(CallBack cb, int...types) {
221 int mask = 0;
222 ContentFilter cfa = new ContentFilter(0);
223 for (int m : types) {
224 mask |= m;
225 switch (m) {
226 case ContentFilter.CDATA :
227 cfa.setCDATAVisible(true);
228 break;
229 case ContentFilter.COMMENT :
230 cfa.setCommentVisible(true);
231 break;
232 case ContentFilter.DOCTYPE :
233 cfa.setDocTypeVisible(true);
234 break;
235 case ContentFilter.DOCUMENT :
236 cfa.setFilterMask(cfa.getFilterMask() | ContentFilter.DOCUMENT);
237 break;
238 case ContentFilter.ELEMENT :
239 cfa.setElementVisible(true);
240 break;
241 case ContentFilter.ENTITYREF :
242 cfa.setEntityRefVisible(true);
243 break;
244 case ContentFilter.PI :
245 cfa.setPIVisible(true);
246 break;
247 case ContentFilter.TEXT :
248 cfa.setTextVisible(true);
249 break;
250 }
251 }
252 exercise(cfa, getRoot(), cb);
253 exercise(cfa, getDocument(), cb);
254
255 ContentFilter cf = new ContentFilter(mask);
256 exercise(cf, getRoot(), cb);
257 exercise(cf, getDocument(), cb);
258
259 assertFilterEquals(cf, cfa);
260
261 assertTrue(cf.filter(new Object()) == null);
262 assertTrue(cfa.filter(new Object()) == null);
263 }
264
265 @Test
266 public void testEqualsObject() {
267 assertFilterEquals(new ContentFilter(), new ContentFilter(true));
268
269 ContentFilter cfa = new ContentFilter(ContentFilter.CDATA);
270 ContentFilter cfb = UnitTestUtil.deSerialize(cfa);
271 assertFilterEquals(cfa, cfb);
272 cfa.setCommentVisible(true);
273 assertFilterNotEquals(cfa, cfb);
274
275 assertFilterNotEquals(cfa, new ContentFilter(true));
276 assertFilterNotEquals(cfa, new ContentFilter(false));
277 assertFilterNotEquals(cfa, new ElementFilter());
278
279 }
280
281 }
0 package org.jdom.test.cases.filter;
1
2 import org.jdom.Element;
3 import org.jdom.Namespace;
4 import org.jdom.filter2.ElementFilter;
5 import org.junit.Test;
6
7 @SuppressWarnings("javadoc")
8 public class TestElementFilter extends AbstractTestFilter {
9
10 @Test
11 public void testElementFilter() {
12 ElementFilter ef = new ElementFilter();
13 CallBack cb = new CallBack() {
14 @Override
15 public boolean isValid(Object c) {
16 return c != null && c instanceof Element;
17 }
18 };
19 exercise(ef, getRoot(), cb);
20 exercise(ef, getDocument(), cb);
21 }
22
23 @Test
24 public void testElementFilterString() {
25 final String name = "four";
26 ElementFilter ef = new ElementFilter(name);
27 CallBack cb = new CallBack() {
28 @Override
29 public boolean isValid(Object c) {
30 return (c != null) && (c instanceof Element) &&
31 name.equals(((Element)c).getName());
32 }
33 };
34 exercise(ef, getRoot(), cb);
35 exercise(ef, getDocument(), cb);
36 }
37
38 @Test
39 public void testElementFilterNamespace() {
40 ElementFilter efa = new ElementFilter(Namespace.NO_NAMESPACE);
41 CallBack cba = new CallBack() {
42 @Override
43 public boolean isValid(Object c) {
44 return (c != null) && (c instanceof Element) &&
45 Namespace.NO_NAMESPACE.equals(((Element)c).getNamespace());
46 }
47 };
48 exercise(efa, getRoot(), cba);
49 exercise(efa, getDocument(), cba);
50
51 ElementFilter efb = new ElementFilter(getTestNamespace());
52 CallBack cbb = new CallBack() {
53 @Override
54 public boolean isValid(Object c) {
55 return (c != null) && (c instanceof Element) &&
56 getTestNamespace().equals(((Element)c).getNamespace());
57 }
58 };
59 exercise(efb, getRoot(), cbb);
60 exercise(efb, getDocument(), cbb);
61
62
63 }
64
65 @Test
66 public void testElementFilterStringNamespace() {
67 final String namea = "four";
68 ElementFilter efa = new ElementFilter(namea, Namespace.NO_NAMESPACE);
69 CallBack cba = new CallBack() {
70 @Override
71 public boolean isValid(Object c) {
72 return (c != null) && (c instanceof Element) &&
73 namea.equals(((Element)c).getName()) &&
74 Namespace.NO_NAMESPACE.equals(((Element)c).getNamespace());
75 }
76 };
77 exercise(efa, getRoot(), cba);
78 exercise(efa, getDocument(), cba);
79
80 final String nameb = "three";
81 ElementFilter efb = new ElementFilter(nameb, getTestNamespace());
82 CallBack cbb = new CallBack() {
83 @Override
84 public boolean isValid(Object c) {
85 return (c != null) && (c instanceof Element) &&
86 nameb.equals(((Element)c).getName()) &&
87 getTestNamespace().equals(((Element)c).getNamespace());
88 }
89 };
90 exercise(efb, getRoot(), cbb);
91 exercise(efb, getDocument(), cbb);
92
93 }
94
95 @Test
96 public void testEqualsObject() {
97 final String URI1 = "http://jdom.org/test1";
98 final String URI2 = "http://jdom.org/test2";
99 Namespace ns1a = Namespace.getNamespace("pfxa", URI1);
100 Namespace ns1b = Namespace.getNamespace("pfxb", URI1);
101 Namespace ns1c = Namespace.getNamespace(URI1);
102
103 Namespace ns2a = Namespace.getNamespace("pfxa", URI2);
104 Namespace ns2c = Namespace.getNamespace(URI2);
105
106 assertFilterEquals(new ElementFilter("test"),
107 new ElementFilter("test"));
108
109 // same namespace
110 assertFilterEquals(new ElementFilter("test", ns1a),
111 new ElementFilter("test", ns1a));
112
113 // same namespace URI (different prefix)
114 assertFilterEquals(new ElementFilter("test", ns1a),
115 new ElementFilter("test", ns1b));
116
117 // same namespace URI (different prefix)
118 assertFilterEquals(new ElementFilter("test", ns1a),
119 new ElementFilter("test", ns1c));
120
121 // same namespace URI (different prefix)
122 assertFilterEquals(new ElementFilter(ns1a),
123 new ElementFilter(ns1a));
124
125 // same namespace URI (different prefix)
126 assertFilterEquals(new ElementFilter(ns1a),
127 new ElementFilter(ns1b));
128
129 // same namespace URI (different prefix)
130 assertFilterEquals(new ElementFilter(ns1a),
131 new ElementFilter(ns1c));
132
133 assertFilterNotEquals(new ElementFilter("test", ns1a),
134 new ElementFilter(ns1a));
135
136 assertFilterNotEquals(new ElementFilter("test"),
137 new ElementFilter("testfoo"));
138
139 assertFilterNotEquals(new ElementFilter("test"),
140 new ElementFilter("test", Namespace.NO_NAMESPACE));
141
142 assertFilterNotEquals(new ElementFilter("test", ns1a),
143 new ElementFilter("test", Namespace.NO_NAMESPACE));
144
145 assertFilterNotEquals(new ElementFilter("test", Namespace.NO_NAMESPACE),
146 new ElementFilter("test", ns1a));
147
148 assertFilterNotEquals(new ElementFilter(ns1a),
149 new ElementFilter(ns2a));
150
151 assertFilterNotEquals(new ElementFilter(ns1c),
152 new ElementFilter(ns2c));
153
154 assertFilterNotEquals(new ElementFilter(ns1c),
155 new ElementFilter(ns1c).negate());
156
157 }
158
159 }
0 package org.jdom.test.cases.filter;
1
2 import static org.junit.Assert.*;
3
4 import java.util.ArrayList;
5 import java.util.List;
6
7 import org.jdom.Attribute;
8 import org.jdom.CDATA;
9 import org.jdom.Comment;
10 import org.jdom.DocType;
11 import org.jdom.Document;
12 import org.jdom.Element;
13 import org.jdom.EntityRef;
14 import org.jdom.Namespace;
15 import org.jdom.ProcessingInstruction;
16 import org.jdom.Text;
17 import org.jdom.filter2.ContentFilter;
18 import org.jdom.filter2.Filter;
19 import org.jdom.filter2.Filters;
20 import org.jdom.test.util.UnitTestUtil;
21 import org.junit.Test;
22
23 @SuppressWarnings("javadoc")
24 public class TestFilters extends AbstractTestFilter {
25
26
27 private <F> void checkFilter(Filter<F> filter, F match, Object not) {
28 assertNotNull(filter);
29 assertNotNull(filter.toString());
30 assertFilterEquals(filter, UnitTestUtil.deSerialize(filter));
31 assertFilterNotEquals(filter, filter.negate());
32 assertFalse(filter.equals(null));
33 assertTrue(filter.matches(match));
34 assertFalse(filter.matches(not));
35 ArrayList<Object> al = null;
36 assertTrue(filter.filter(al).isEmpty());
37 al = new ArrayList<Object>(3);
38 al.add(not);
39 al.add(match);
40 al.add(null);
41 List<F> mat = filter.filter(al);
42
43 assertTrue(mat.size() == 1);
44 assertTrue(mat.get(0) == match);
45 }
46
47 @Test
48 public void testContent() {
49 checkFilter(Filters.content(), new Element("tag"), new Object());
50 checkFilter(Filters.content(), new Element("tag"), null);
51 }
52
53 @Test
54 public void testDocument() {
55 checkFilter(Filters.document(), new Document(), new Object());
56 }
57
58 @Test
59 public void testAttribute() {
60 checkFilter(Filters.attribute(), new Attribute("tag", "val"), new Object());
61 }
62
63 @Test
64 public void testAttributeString() {
65 checkFilter(Filters.attribute("mat"), new Attribute("mat", "val"), new Attribute("not", "val"));
66 }
67
68 @Test
69 public void testAttributeStringNamespace() {
70 Namespace nsa = Namespace.getNamespace("pfa", "uria");
71 Namespace nsb = Namespace.getNamespace("pfb", "urib");
72 checkFilter(Filters.attribute("mat", nsa),
73 new Attribute("mat", "val", nsa), new Object());
74 checkFilter(Filters.attribute("mat", nsa),
75 new Attribute("mat", "val", nsa), new Attribute("mat", "val", nsb));
76 checkFilter(Filters.attribute("mat", nsa),
77 new Attribute("mat", "val", nsa), new Attribute("not", "val", nsa));
78 checkFilter(Filters.attribute("mat", nsa),
79 new Attribute("mat", "val", nsa), new Attribute("mat", "val"));
80 checkFilter(Filters.attribute("mat", null),
81 new Attribute("mat", "val", nsa), new Attribute("not", "val", nsa));
82 checkFilter(Filters.attribute(null, nsa),
83 new Attribute("mat", "val", nsa), new Attribute("mat", "val", nsb));
84 checkFilter(Filters.attribute(null, null),
85 new Attribute("mat", "val", nsa), new Element("mat", nsb));
86 }
87
88 @Test
89 public void testAttributeNamespace() {
90 Namespace nsa = Namespace.getNamespace("pfa", "uria");
91 Namespace nsb = Namespace.getNamespace("pfb", "urib");
92 checkFilter(Filters.attribute(nsa),
93 new Attribute("mat", "val", nsa), new Object());
94 checkFilter(Filters.attribute(nsa),
95 new Attribute("mat", "val", nsa), new Attribute("mat", "val", nsb));
96 }
97
98 @Test
99 public void testComment() {
100 checkFilter(Filters.comment(), new Comment("comment"), new Object());
101 }
102
103 @Test
104 public void testCdata() {
105 checkFilter(Filters.cdata(), new CDATA("comment"), new Object());
106 }
107
108 @Test
109 public void testDoctype() {
110 checkFilter(Filters.doctype(), new DocType("root"), new Object());
111 }
112
113 @Test
114 public void testEntityref() {
115 checkFilter(Filters.entityref(), new EntityRef("er"), new Object());
116 }
117
118 @Test
119 public void testElement() {
120 checkFilter(Filters.element(), new Element("emt"), new Object());
121 }
122
123 @Test
124 public void testElementString() {
125 Namespace nsa = Namespace.getNamespace("pfa", "uria");
126 checkFilter(Filters.element("mat"),
127 new Element("mat"), new Object());
128 checkFilter(Filters.element("mat"),
129 new Element("mat"), new Element("mat", nsa));
130 checkFilter(Filters.element("mat"),
131 new Element("mat"), new Element("not", nsa));
132 }
133
134 @Test
135 public void testElementStringNamespace() {
136 Namespace nsa = Namespace.getNamespace("pfa", "uria");
137 Namespace nsb = Namespace.getNamespace("pfb", "urib");
138 checkFilter(Filters.element("mat", nsa),
139 new Element("mat", nsa), new Object());
140 checkFilter(Filters.element("mat", nsa),
141 new Element("mat", nsa), new Element("mat", nsb));
142 checkFilter(Filters.element("mat", nsa),
143 new Element("mat", nsa), new Element("not", nsa));
144 checkFilter(Filters.element("mat", nsa),
145 new Element("mat", nsa), new Element("mat"));
146 }
147
148 @Test
149 public void testElementNamespace() {
150 Namespace nsa = Namespace.getNamespace("pfa", "uria");
151 Namespace nsb = Namespace.getNamespace("pfb", "urib");
152 checkFilter(Filters.element(nsa),
153 new Element("mat", nsa), new Object());
154 checkFilter(Filters.element(nsa),
155 new Element("mat", nsa), new Element("mat", nsb));
156 checkFilter(Filters.element(nsa),
157 new Element("mat", nsa), new Element("mat"));
158 }
159
160 @Test
161 public void testProcessinginstruction() {
162 checkFilter(Filters.processinginstruction(),
163 new ProcessingInstruction("jdomtest", ""), new Object());
164 }
165
166 @Test
167 public void testText() {
168 checkFilter(Filters.text(), new Text("txt"), new Object());
169 checkFilter(Filters.text(), new CDATA("txt"), new Object());
170 }
171
172 @Test
173 public void testTextOnly() {
174 checkFilter(Filters.textOnly(), new Text("txt"), new CDATA("txt"));
175 }
176
177 @Test
178 public void testFBoolean() {
179 checkFilter(Filters.fboolean(), Boolean.TRUE, new Object());
180 }
181
182 @Test
183 public void testFString() {
184 checkFilter(Filters.fstring(), new String("txt"), new Object());
185 }
186
187 @Test
188 public void testFDouble() {
189 checkFilter(Filters.fdouble(), Double.valueOf(123.45), new Object());
190 }
191
192 @Test
193 public void testFClass() {
194 checkFilter(Filters.fclass(Integer.class), Integer.valueOf(123), new Object());
195 }
196
197 @Test
198 public void testRefine() {
199 try {
200 new ContentFilter().refine(null);
201 fail("Should not be able to set null refine filter");
202 } catch (NullPointerException npe) {
203 //good
204 } catch (Exception e) {
205 e.printStackTrace();
206 fail("Expected NullPointerException but got " + e.getClass());
207 }
208 }
209
210 }
0 package org.jdom.test.cases.filter;
1
2 import static org.junit.Assert.*;
3
4 import java.util.ArrayList;
5 import java.util.LinkedList;
6 import java.util.List;
7 import java.util.RandomAccess;
8
9 import org.jdom.filter2.Filter;
10 import org.jdom.filter2.Filters;
11 import org.jdom.test.util.UnitTestUtil;
12
13 import org.junit.Test;
14
15 @SuppressWarnings("javadoc")
16 public class TestPassThroughFilter {
17
18 @Test
19 public void testPassThroughFilterRandom() {
20 Filter<Object> ef = Filters.fpassthrough();
21
22 List<String> lst = new ArrayList<String>(3);
23 lst.add("hello");
24 lst.add("there");
25 lst.add("world");
26 List<Object> filtered = ef.filter(lst);
27 assertTrue(filtered instanceof RandomAccess);
28 assertTrue(filtered.size() == 3);
29 assertEquals("hello", filtered.get(0));
30 assertEquals("there", filtered.get(1));
31 assertEquals("world", filtered.get(2));
32
33 try {
34 filtered.add("boo");
35 UnitTestUtil.failNoException(UnsupportedOperationException.class);
36 } catch (Exception e) {
37 UnitTestUtil.checkException(UnsupportedOperationException.class, e);
38 }
39
40 }
41
42
43 @Test
44 public void testPassThroughFilterLinked() {
45 Filter<Object> ef = Filters.fpassthrough();
46
47 List<String> lst = new LinkedList<String>();
48 lst.add("hello");
49 lst.add("there");
50 lst.add("world");
51 List<Object> filtered = ef.filter(lst);
52 assertTrue(filtered instanceof RandomAccess);
53 assertTrue(filtered.size() == 3);
54 assertEquals("hello", filtered.get(0));
55 assertEquals("there", filtered.get(1));
56 assertEquals("world", filtered.get(2));
57
58 try {
59 filtered.add("boo");
60 UnitTestUtil.failNoException(UnsupportedOperationException.class);
61 } catch (Exception e) {
62 UnitTestUtil.checkException(UnsupportedOperationException.class, e);
63 }
64
65 }
66
67
68 @Test
69 public void testPassThroughFilterNull() {
70 Filter<Object> ef = Filters.fpassthrough();
71
72 List<String> lst = null;
73 List<Object> filtered = ef.filter(lst);
74 assertTrue(filtered instanceof RandomAccess);
75 assertTrue(filtered.size() == 0);
76
77 try {
78 filtered.add("boo");
79 UnitTestUtil.failNoException(UnsupportedOperationException.class);
80 } catch (Exception e) {
81 UnitTestUtil.checkException(UnsupportedOperationException.class, e);
82 }
83
84 }
85
86 @Test
87 public void testPassThroughFilterEmpty() {
88 Filter<Object> ef = Filters.fpassthrough();
89
90 List<String> lst = new LinkedList<String>();
91 List<Object> filtered = ef.filter(lst);
92 assertTrue(filtered instanceof RandomAccess);
93 assertTrue(filtered.size() == 0);
94
95 try {
96 filtered.add("boo");
97 UnitTestUtil.failNoException(UnsupportedOperationException.class);
98 } catch (Exception e) {
99 UnitTestUtil.checkException(UnsupportedOperationException.class, e);
100 }
101
102 }
103 }
0 package org.jdom.test.cases.input;
1
2 import java.io.IOException;
3
4 import javax.xml.parsers.DocumentBuilder;
5 import javax.xml.parsers.DocumentBuilderFactory;
6 import javax.xml.parsers.ParserConfigurationException;
7
8 import org.w3c.dom.Document;
9 import org.w3c.dom.Element;
10 import org.w3c.dom.Node;
11 import org.xml.sax.InputSource;
12 import org.xml.sax.SAXException;
13
14 import org.jdom.test.util.FidoFetch;
15
16 /**
17 * This class encapsulates all the org.w3c.dom.DOM details, so that the actual
18 * TestDOMBuilder class has a cleaner import * setup with just
19 * JDOM imports.
20 * @author rolf
21 *
22 */
23 @SuppressWarnings("javadoc")
24 public class HelpTestDOMBuilder {
25
26 public static final Document getDocument(String resname, boolean xsdvalidate) throws ParserConfigurationException, SAXException, IOException {
27 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
28 dbf.setNamespaceAware(true);
29 dbf.setValidating(xsdvalidate);
30 dbf.setExpandEntityReferences(false);
31
32 if (xsdvalidate) {
33 dbf.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
34 }
35 DocumentBuilder db = dbf.newDocumentBuilder();
36 InputSource is = new InputSource(FidoFetch.getFido().getURL(resname).toExternalForm());
37 return db.parse(is);
38 }
39
40 public static final Element getRoot(Document doc) {
41 Node n = doc.getFirstChild();
42 while (n != null) {
43 if (n instanceof Element) {
44 return (Element)n;
45 }
46 n = n.getNextSibling();
47 }
48 return null;
49 }
50 }
0 package org.jdom.test.cases.input;
1
2 import static org.junit.Assert.*;
3
4 import org.jdom.input.sax.BuilderErrorHandler;
5
6 import org.junit.Test;
7 import org.xml.sax.SAXException;
8 import org.xml.sax.SAXParseException;
9
10 @SuppressWarnings("javadoc")
11 public class TestBuilderErrorHandler {
12
13 @Test
14 public void testWarning() {
15 BuilderErrorHandler handler = new BuilderErrorHandler();
16 try {
17 handler.warning(new SAXParseException(null, null, null, 0, 0));
18 } catch (Exception e) {
19 fail("Warning should not throw an exception, but got " + e.getClass() + ": " + e.getMessage());
20 }
21 }
22
23 @Test
24 public void testError() {
25 BuilderErrorHandler handler = new BuilderErrorHandler();
26 try {
27 handler.error(new SAXParseException(null, null, null, 0, 0));
28 fail("Error should throw a SAXException, but did not");
29 } catch (SAXException spe) {
30 //good
31 } catch (Exception e) {
32 fail("Error should throw a SAXException, but got " + e.getClass() + ": " + e.getMessage());
33 }
34 }
35
36 @Test
37 public void testFatalError() {
38 BuilderErrorHandler handler = new BuilderErrorHandler();
39 try {
40 handler.fatalError(new SAXParseException(null, null, null, 0, 0));
41 fail("Error should throw a SAXException, but did not");
42 } catch (SAXException spe) {
43 //good
44 } catch (Exception e) {
45 fail("Error should throw a SAXException, but got " + e.getClass() + ": " + e.getMessage());
46 }
47 }
48
49 }
0 package org.jdom.test.cases.input;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertTrue;
6
7 import java.io.CharArrayWriter;
8 import java.io.IOException;
9
10 import javax.xml.parsers.DocumentBuilderFactory;
11
12 import org.junit.Test;
13 import org.jdom.Attribute;
14 import org.jdom.DefaultJDOMFactory;
15 import org.jdom.DocType;
16 import org.jdom.Document;
17 import org.jdom.Element;
18 import org.jdom.Namespace;
19 import org.jdom.input.DOMBuilder;
20 import org.jdom.input.SAXBuilder;
21 import org.jdom.input.sax.XMLReaders;
22 import org.jdom.output.Format;
23 import org.jdom.output.XMLOutputter2;
24 import org.jdom.test.util.FidoFetch;
25 import org.jdom.test.util.UnitTestUtil;
26
27 @SuppressWarnings("javadoc")
28 public class TestDOMBuilder {
29
30 @Test
31 public void testDOMBuilder() {
32 DOMBuilder db = new DOMBuilder();
33 assertNotNull(db);
34 }
35
36 @Test
37 public void testFactory() {
38 DOMBuilder db = new DOMBuilder();
39 assertTrue(db.getFactory() instanceof DefaultJDOMFactory);
40 DefaultJDOMFactory fac = new DefaultJDOMFactory();
41 assertFalse(db.getFactory() == fac);
42 db.setFactory(fac);
43 assertTrue(db.getFactory() == fac);
44 }
45
46 @Test
47 public void testSimpleDocument() {
48 checkDOM("/DOMBuilder/simple.xml", false);
49 }
50
51 @Test
52 public void testAttributesDocument() {
53 checkDOM("/DOMBuilder/attributes.xml", false);
54 }
55
56 @Test
57 public void testNamespaceDocument() {
58 checkDOM("/DOMBuilder/namespaces.xml", false);
59 }
60
61 @Test
62 public void testDocTypeDocument() {
63 checkDOM("/DOMBuilder/doctype.xml", false);
64 }
65
66 @Test
67 public void testComplexDocument() {
68 checkDOM("/DOMBuilder/complex.xml", false);
69 }
70
71 @Test
72 public void testXSDDocument() {
73 checkDOM("/xsdcomplex/input.xml", true);
74 }
75
76 @Test
77 public void testNoNamespaceDOM() throws Exception {
78 // https://github.com/hunterhacker/jdom/issues/138
79 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
80 org.w3c.dom.Document doc = dbFactory.newDocumentBuilder().newDocument();
81 doc.setXmlVersion("1.0");
82
83 org.w3c.dom.Element root = doc.createElement("Document");
84
85 root.setAttribute("xmlns", "urn:iso:foo");
86 root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
87 root.setAttribute("xsi:schemaLocation", "urn:iso:foo bar.xsd");
88 doc.appendChild(root);
89
90 // The above is a badly-formed DOM document without the correct
91 // namespaceing. The second attribute should use root.setAttributeNS
92 DOMBuilder dbuilder = new DOMBuilder();
93 Document jdoc = dbuilder.build(doc);
94
95 Namespace xsi = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
96 Attribute att = jdoc.getRootElement().getAttribute("schemaLocation", xsi);
97 assertTrue(att != null);
98 assertTrue("xsi".equals(att.getNamespacePrefix()));
99
100 }
101
102 private void checkDOM(String resname, boolean xsdvalidate) {
103 try {
104 org.w3c.dom.Document domdoc = HelpTestDOMBuilder.getDocument(resname, xsdvalidate);
105 DOMBuilder db = new DOMBuilder();
106 Document dombuild = db.build(domdoc);
107 Element domroot = db.build(HelpTestDOMBuilder.getRoot(domdoc));
108
109 SAXBuilder sb = new SAXBuilder(xsdvalidate
110 ? XMLReaders.XSDVALIDATING
111 : XMLReaders.NONVALIDATING );
112 sb.setExpandEntities(false);
113
114 Document saxbuild = sb.build(FidoFetch.getFido().getURL(resname));
115 Element saxroot = saxbuild.hasRootElement() ? saxbuild.getRootElement() : null;
116
117 assertEquals(toString(saxbuild), toString(dombuild));
118 assertEquals(toString(saxroot), toString(domroot));
119
120 } catch (Exception e) {
121 UnitTestUtil.failException(
122 "Could not parse file '" + resname + "': " + e.getMessage(), e);
123 }
124 }
125
126 private void normalizeDTD(DocType dt) {
127 if (dt == null) {
128 return;
129 }
130 // do some tricks so that we can compare the results.
131 // these may well break the actual syntax of DTD's but for testing
132 // purposes it is OK.
133 String internalss = dt.getInternalSubset().trim() ;
134 // the spaceing in and around the internal subset is different between
135 // our SAX parse, and the DOM parse.
136 // make all whitespace a single space.
137 internalss = internalss.replaceAll("\\s+", " ");
138 // It seems the DOM parser internally quotes entities with single quote
139 // but our sax parser uses double-quote.
140 // simply replace all " with ' and be done with it.
141 internalss = internalss.replaceAll("\"", "'");
142 dt.setInternalSubset("\n" + internalss + "\n");
143 }
144
145 private String toString(Document doc) {
146 UnitTestUtil.normalizeAttributes(doc.getRootElement());
147 normalizeDTD(doc.getDocType());
148 XMLOutputter2 out = new XMLOutputter2(Format.getPrettyFormat());
149 CharArrayWriter caw = new CharArrayWriter();
150 try {
151 out.output(doc, caw);
152 } catch (IOException e) {
153 e.printStackTrace();
154 return null;
155 }
156 return caw.toString();
157 }
158
159 private String toString(Element emt) {
160 UnitTestUtil.normalizeAttributes(emt);
161 XMLOutputter2 out = new XMLOutputter2(Format.getPrettyFormat());
162 CharArrayWriter caw = new CharArrayWriter();
163 try {
164 out.output(emt, caw);
165 } catch (IOException e) {
166 e.printStackTrace();
167 return null;
168 }
169 return caw.toString();
170 }
171
172 }
0 package org.jdom.test.cases.input;
1
2 import static org.junit.Assert.*;
3
4 import org.jdom.DocType;
5 import org.jdom.JDOMException;
6 import org.jdom.JDOMFactory;
7 import org.jdom.DefaultJDOMFactory;
8 import org.jdom.input.stax.DTDParser;
9 import org.jdom.test.util.UnitTestUtil;
10 import org.junit.Test;
11
12 @SuppressWarnings("javadoc")
13 public class TestDTDParser {
14
15 private static final JDOMFactory factory = new DefaultJDOMFactory();
16
17 @Test
18 public void testParseSimple() throws JDOMException {
19 DocType dt = DTDParser.parse(
20 "<!DOCTYPE root >",
21 factory);
22
23 assertEquals("root", dt.getElementName());
24 assertEquals(null, dt.getPublicID());
25 assertEquals(null, dt.getSystemID());
26 assertEquals(null, dt.getInternalSubset());
27 }
28
29 @Test
30 public void testParseSimpleCompact() throws JDOMException {
31 DocType dt = DTDParser.parse(
32 "<!DOCTYPE root>",
33 factory);
34
35 assertEquals("root", dt.getElementName());
36 assertEquals(null, dt.getPublicID());
37 assertEquals(null, dt.getSystemID());
38 assertEquals(null, dt.getInternalSubset());
39 }
40
41 @Test
42 public void testParseSimpleCompactInternal() throws JDOMException {
43 DocType dt = DTDParser.parse(
44 "<!DOCTYPE root[internal]>",
45 factory);
46
47 assertEquals("root", dt.getElementName());
48 assertEquals(null, dt.getPublicID());
49 assertEquals(null, dt.getSystemID());
50 assertEquals("internal", dt.getInternalSubset());
51 }
52
53 @Test
54 public void testParseSYSTEMquotNONE() throws JDOMException {
55 DocType dt = DTDParser.parse(
56 "<!DOCTYPE root SYSTEM \"system\" >",
57 factory);
58
59 assertEquals("root", dt.getElementName());
60 assertEquals(null, dt.getPublicID());
61 assertEquals("system", dt.getSystemID());
62 assertEquals(null, dt.getInternalSubset());
63 }
64
65 @Test
66 public void testParseSYSTEMaposNONE() throws JDOMException {
67 DocType dt = DTDParser.parse(
68 "<!DOCTYPE root SYSTEM 'system' >",
69 factory);
70
71 assertEquals("root", dt.getElementName());
72 assertEquals(null, dt.getPublicID());
73 assertEquals("system", dt.getSystemID());
74 assertEquals(null, dt.getInternalSubset());
75 }
76
77 @Test
78 public void testParseSYSTEMquotSimple() throws JDOMException {
79 DocType dt = DTDParser.parse(
80 "<!DOCTYPE root SYSTEM \"system\" [internal] >",
81 factory);
82
83 assertEquals("root", dt.getElementName());
84 assertEquals(null, dt.getPublicID());
85 assertEquals("system", dt.getSystemID());
86 assertEquals("internal", dt.getInternalSubset());
87 }
88
89 @Test
90 public void testParseSYSTEMaposSimple() throws JDOMException {
91 DocType dt = DTDParser.parse(
92 "<!DOCTYPE root SYSTEM 'system' [internal] >",
93 factory);
94
95 assertEquals("root", dt.getElementName());
96 assertEquals(null, dt.getPublicID());
97 assertEquals("system", dt.getSystemID());
98 assertEquals("internal", dt.getInternalSubset());
99 }
100
101 @Test
102 public void testParsePUBLICquotenullNONE() throws JDOMException {
103 DocType dt = DTDParser.parse(
104 "<!DOCTYPE root PUBLIC \"public\" >",
105 factory);
106
107 assertEquals("root", dt.getElementName());
108 assertEquals("public", dt.getPublicID());
109 assertEquals(null, dt.getSystemID());
110 assertEquals(null, dt.getInternalSubset());
111 }
112
113 @Test
114 public void testParsePUBLICaposnullNONE() throws JDOMException {
115 DocType dt = DTDParser.parse(
116 "<!DOCTYPE root PUBLIC 'public' >",
117 factory);
118
119 assertEquals("root", dt.getElementName());
120 assertEquals("public", dt.getPublicID());
121 assertEquals(null, dt.getSystemID());
122 assertEquals(null, dt.getInternalSubset());
123 }
124
125 @Test
126 public void testParsePUBLICquotquotNONE() throws JDOMException {
127 DocType dt = DTDParser.parse(
128 "<!DOCTYPE root PUBLIC \"public\" \"system\" >",
129 factory);
130
131 assertEquals("root", dt.getElementName());
132 assertEquals("public", dt.getPublicID());
133 assertEquals("system", dt.getSystemID());
134 assertEquals(null, dt.getInternalSubset());
135 }
136
137 @Test
138 public void testParsePUBLICquotaposNONE() throws JDOMException {
139 DocType dt = DTDParser.parse(
140 "<!DOCTYPE root PUBLIC \"public\" 'system' >",
141 factory);
142
143 assertEquals("root", dt.getElementName());
144 assertEquals("public", dt.getPublicID());
145 assertEquals("system", dt.getSystemID());
146 assertEquals(null, dt.getInternalSubset());
147 }
148
149 @Test
150 public void testParsePUBLICaposquotNONE() throws JDOMException {
151 DocType dt = DTDParser.parse(
152 "<!DOCTYPE root PUBLIC 'public' \"system\" >",
153 factory);
154
155 assertEquals("root", dt.getElementName());
156 assertEquals("public", dt.getPublicID());
157 assertEquals("system", dt.getSystemID());
158 assertEquals(null, dt.getInternalSubset());
159 }
160
161 @Test
162 public void testParsePUBLICaposaposNONE() throws JDOMException {
163 DocType dt = DTDParser.parse(
164 "<!DOCTYPE root PUBLIC 'public' 'system' >",
165 factory);
166
167 assertEquals("root", dt.getElementName());
168 assertEquals("public", dt.getPublicID());
169 assertEquals("system", dt.getSystemID());
170 assertEquals(null, dt.getInternalSubset());
171 }
172
173 @Test
174 public void testParsePUBLICaposaposSimple() throws JDOMException {
175 DocType dt = DTDParser.parse(
176 "<!DOCTYPE root PUBLIC 'public' 'system' [internal] >",
177 factory);
178
179 assertEquals("root", dt.getElementName());
180 assertEquals("public", dt.getPublicID());
181 assertEquals("system", dt.getSystemID());
182 assertEquals("internal", dt.getInternalSubset());
183 }
184
185 @Test
186 public void testParsePUBLICaposaposSimpleCompact() throws JDOMException {
187 DocType dt = DTDParser.parse(
188 "<!DOCTYPE root PUBLIC 'public' 'system'[internal]>",
189 factory);
190
191 assertEquals("root", dt.getElementName());
192 assertEquals("public", dt.getPublicID());
193 assertEquals("system", dt.getSystemID());
194 assertEquals("internal", dt.getInternalSubset());
195 }
196
197 @Test
198 public void testParsePUBLICaposaposSimpleSpacy() throws JDOMException {
199 DocType dt = DTDParser.parse(
200 " <!DOCTYPE root PUBLIC ' public ' ' system ' [ <!ENTITY " +
201 " ent\n EntityDef > ] > ",
202 factory);
203
204 assertEquals("root", dt.getElementName());
205 assertEquals(" public ", dt.getPublicID());
206 assertEquals(" system ", dt.getSystemID());
207 assertEquals(" <!ENTITY ent EntityDef>\n", dt.getInternalSubset());
208 }
209
210 @Test
211 public void testParseInternalA() throws JDOMException {
212 DocType dt = DTDParser.parse(
213 "<!DOCTYPE root [<!ELEMENT root (#PCDATA)><!ENTITY xpd 'Expand Me!' >]>",
214 factory);
215
216 assertEquals("root", dt.getElementName());
217 assertEquals(null, dt.getPublicID());
218 assertEquals(null, dt.getSystemID());
219 assertEquals(" <!ELEMENT root (#PCDATA)>\n <!ENTITY xpd 'Expand Me!'>\n", dt.getInternalSubset());
220 }
221
222 @Test
223 public void testParseInternalEmbeddedNewlines() throws JDOMException {
224 DocType dt = DTDParser.parse(
225 "<!DOCTYPE root \t \r \n [ \r \n <!ELEMENT root\n (#PCDATA)> \n <!ENTITY xpd \n 'Expand Me!' >\n ] \n >",
226 factory);
227
228 assertEquals("root", dt.getElementName());
229 assertEquals(null, dt.getPublicID());
230 assertEquals(null, dt.getSystemID());
231 assertEquals(" <!ELEMENT root (#PCDATA)>\n <!ENTITY xpd 'Expand Me!'>\n", dt.getInternalSubset());
232 }
233
234 @Test
235 public void testParseIncomplete() {
236 try {
237 DTDParser.parse("<!DOCTYPE root",factory);
238 UnitTestUtil.failNoException(JDOMException.class);
239 } catch (Exception e) {
240 UnitTestUtil.checkException(JDOMException.class, e);
241 }
242
243 }
244
245 @Test
246 public void testParseSpace() throws JDOMException {
247 DocType dt = DTDParser.parse("<!DOCTYPE root>",factory);
248 assertEquals("root", dt.getElementName());
249 assertEquals(null, dt.getPublicID());
250 assertEquals(null, dt.getSystemID());
251 assertEquals(null, dt.getInternalSubset());
252 }
253
254 @Test
255 public void testParseTab() throws JDOMException {
256 DocType dt = DTDParser.parse("<!DOCTYPE\troot>",factory);
257 assertEquals("root", dt.getElementName());
258 assertEquals(null, dt.getPublicID());
259 assertEquals(null, dt.getSystemID());
260 assertEquals(null, dt.getInternalSubset());
261 }
262
263 @Test
264 public void testParseNewline() throws JDOMException {
265 DocType dt = DTDParser.parse("<!DOCTYPE\nroot>",factory);
266 assertEquals("root", dt.getElementName());
267 assertEquals(null, dt.getPublicID());
268 assertEquals(null, dt.getSystemID());
269 assertEquals(null, dt.getInternalSubset());
270 }
271
272 @Test
273 public void testParseCarriageReturn() throws JDOMException {
274 DocType dt = DTDParser.parse("<!DOCTYPE\rroot>",factory);
275 assertEquals("root", dt.getElementName());
276 assertEquals(null, dt.getPublicID());
277 assertEquals(null, dt.getSystemID());
278 assertEquals(null, dt.getInternalSubset());
279 }
280
281 @Test
282 public void testParseInternalSpace() throws JDOMException {
283 DocType dt = DTDParser.parse("<!DOCTYPE root [ <!ENTITY ent 'entity' > ] >",factory);
284 assertEquals("root", dt.getElementName());
285 assertEquals(null, dt.getPublicID());
286 assertEquals(null, dt.getSystemID());
287 assertEquals(" <!ENTITY ent 'entity'>\n", dt.getInternalSubset());
288 }
289
290 @Test
291 public void testParseInternalTab() throws JDOMException {
292 DocType dt = DTDParser.parse("<!DOCTYPE root [\t<!ENTITY\tent\t'entity'\t>\t]\t>",factory);
293 assertEquals("root", dt.getElementName());
294 assertEquals(null, dt.getPublicID());
295 assertEquals(null, dt.getSystemID());
296 assertEquals(" <!ENTITY ent 'entity'>\n", dt.getInternalSubset());
297 }
298
299 @Test
300 public void testParseInternalNewline() throws JDOMException {
301 DocType dt = DTDParser.parse("<!DOCTYPE root [\n<!ENTITY\nent\n'entity'\n>\n]\n>",factory);
302 assertEquals("root", dt.getElementName());
303 assertEquals(null, dt.getPublicID());
304 assertEquals(null, dt.getSystemID());
305 assertEquals(" <!ENTITY ent 'entity'>\n", dt.getInternalSubset());
306 }
307
308 @Test
309 public void testParseInternalCarriageReturn() throws JDOMException {
310 DocType dt = DTDParser.parse("<!DOCTYPE root [\r<!ENTITY\rent\r'entity'\r>\r]\r>",factory);
311 assertEquals("root", dt.getElementName());
312 assertEquals(null, dt.getPublicID());
313 assertEquals(null, dt.getSystemID());
314 assertEquals(" <!ENTITY ent 'entity'>\n", dt.getInternalSubset());
315 }
316
317 @Test
318 public void testParseInternalWithAPosSpace() throws JDOMException {
319 DocType dt = DTDParser.parse("<!DOCTYPE root [<!ENTITY ent 'entity with spaces\nand newlines,\ttabs, and crs\r' >]>",factory);
320 assertEquals("root", dt.getElementName());
321 assertEquals(null, dt.getPublicID());
322 assertEquals(null, dt.getSystemID());
323 assertEquals(" <!ENTITY ent 'entity with spaces\nand newlines,\ttabs, and crs\r'>\n", dt.getInternalSubset());
324 }
325
326 @Test
327 public void testParseInternalWithQuoteSpace() throws JDOMException {
328 DocType dt = DTDParser.parse("<!DOCTYPE root [<!ENTITY ent \"entity with spaces\nand newlines,\ttabs, and crs\r\" >]>",factory);
329 assertEquals("root", dt.getElementName());
330 assertEquals(null, dt.getPublicID());
331 assertEquals(null, dt.getSystemID());
332 assertEquals(" <!ENTITY ent \"entity with spaces\nand newlines,\ttabs, and crs\r\">\n", dt.getInternalSubset());
333 }
334
335 }
0 package org.jdom.test.cases.input;
1
2 import static org.junit.Assert.*;
3
4 import org.jdom.Document;
5 import org.jdom.input.JDOMParseException;
6 import org.junit.Test;
7 import org.xml.sax.SAXParseException;
8
9 // Do not use name ending in Exception.
10 @SuppressWarnings("javadoc")
11 public class TestJDOMParseExceptn {
12
13 private final SAXParseException spe = new SAXParseException("message", "publicID", "systemID", 5, 10);
14
15 @Test
16 public void testJDOMParseExceptionStringThrowable() {
17 JDOMParseException e = new JDOMParseException("test", spe);
18 assertTrue(e.getPartialDocument() == null);
19 }
20
21 @Test
22 public void testJDOMParseExceptionStringThrowableDocument() {
23 Document doc = new Document();
24 JDOMParseException e = new JDOMParseException("test", spe, doc);
25 assertTrue(e.getPartialDocument() == doc);
26 }
27
28 @Test
29 public void testGetPartialDocument() {
30 Document doc = new Document();
31 JDOMParseException e = new JDOMParseException("test", spe, doc);
32 assertTrue(e.getPartialDocument() == doc);
33 }
34
35 @Test
36 public void testGetPublicId() {
37 assertEquals("publicID", new JDOMParseException("test", spe).getPublicId());
38 assertTrue(null== new JDOMParseException("test", new Exception()).getPublicId());
39 }
40
41 @Test
42 public void testGetSystemId() {
43 assertEquals("systemID", new JDOMParseException("test", spe).getSystemId());
44 assertTrue(null== new JDOMParseException("test", new Exception()).getSystemId());
45 }
46
47 @Test
48 public void testGetLineNumber() {
49 assertEquals(5, new JDOMParseException("test", spe).getLineNumber());
50 assertTrue(-1 == new JDOMParseException("test", new Exception()).getLineNumber());
51 }
52
53 @Test
54 public void testGetColumnNumber() {
55 assertEquals(10, new JDOMParseException("test", spe).getColumnNumber());
56 assertTrue(-1 == new JDOMParseException("test", new Exception()).getColumnNumber());
57 }
58
59 }
0 /*--
1
2 Copyright (C) 2000 Brett McLaughlin & Jason Hunter.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact license@jdom.org.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management (pm@jdom.org).
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Brett McLaughlin <brett@jdom.org> and
49 Jason Hunter <jhunter@jdom.org>. For more information on the
50 JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54
55 package org.jdom.test.cases.input;
56
57 /**
58 * Tests of SAXBuilder functionality. Since most of these methods are tested in other parts
59 * of the test suite, many tests are not filled.
60 *
61 * @author Philip Nelson
62 * @version 0.5
63 */
64 import static org.jdom.test.util.UnitTestUtil.checkException;
65 import static org.jdom.test.util.UnitTestUtil.failNoException;
66 import static org.junit.Assert.assertEquals;
67 import static org.junit.Assert.assertFalse;
68 import static org.junit.Assert.assertNotNull;
69 import static org.junit.Assert.assertNull;
70 import static org.junit.Assert.assertTrue;
71 import static org.junit.Assert.fail;
72
73 import java.io.*;
74 import java.net.MalformedURLException;
75 import java.net.URL;
76 import java.nio.CharBuffer;
77 import java.util.Arrays;
78 import java.util.List;
79
80 import org.junit.Ignore;
81 import org.junit.Test;
82 import org.xml.sax.Attributes;
83 import org.xml.sax.DTDHandler;
84 import org.xml.sax.EntityResolver;
85 import org.xml.sax.ErrorHandler;
86 import org.xml.sax.InputSource;
87 import org.xml.sax.SAXException;
88 import org.xml.sax.XMLFilter;
89 import org.xml.sax.XMLReader;
90 import org.xml.sax.ext.LexicalHandler;
91 import org.xml.sax.helpers.XMLFilterImpl;
92
93 import org.jdom.Content;
94 import org.jdom.DefaultJDOMFactory;
95 import org.jdom.Document;
96 import org.jdom.EntityRef;
97 import org.jdom.JDOMException;
98 import org.jdom.JDOMFactory;
99 import org.jdom.UncheckedJDOMFactory;
100 import org.jdom.input.SAXBuilder;
101 import org.jdom.input.sax.BuilderErrorHandler;
102 import org.jdom.input.sax.SAXEngine;
103 import org.jdom.input.sax.SAXHandler;
104 import org.jdom.input.sax.SAXHandlerFactory;
105 import org.jdom.input.sax.XMLReaderJDOMFactory;
106 import org.jdom.input.sax.XMLReaderSAX2Factory;
107 import org.jdom.input.sax.XMLReaders;
108 import org.jdom.output.Format;
109 import org.jdom.output.XMLOutputter2;
110 import org.jdom.test.util.FidoFetch;
111 import org.jdom.test.util.UnitTestUtil;
112
113
114 @SuppressWarnings("javadoc")
115 public final class TestSAXBuilder {
116
117 private static final String testxml = "<?xml version=\"1.0\"?><root/>";
118 private static final String testpattern = "\\s*<\\?xml\\s+version=\"1.0\"\\s+encoding=\"UTF-8\"\\s*\\?>\\s*<root\\s*/>\\s*";
119
120 private class MySAXBuilder extends SAXBuilder {
121 public MySAXBuilder() {
122 super();
123 }
124
125 @SuppressWarnings("deprecation")
126 public MySAXBuilder(String driver) {
127 super(driver);
128 }
129
130 public MySAXBuilder(XMLReaderJDOMFactory fac) {
131 super(fac);
132 }
133
134 /**
135 * This sets and configures the parser (SAXBuilder just sets).
136 */
137 @Override
138 public XMLReader createParser() throws JDOMException {
139 XMLReader reader = super.createParser();
140 configureParser(reader, new SAXHandler());
141 return reader;
142 }
143 }
144
145 @SuppressWarnings("deprecation")
146 @Test
147 public void testSAXBuilder() {
148 SAXBuilder sb = new SAXBuilder();
149 assertNull(sb.getDriverClass());
150 assertTrue(sb.getEntityResolver() == null);
151 assertTrue(sb.getDTDHandler() == null);
152 assertTrue(sb.getXMLFilter() == null);
153 assertFalse(sb.isValidating());
154 assertTrue(sb.getExpandEntities());
155 }
156
157 @SuppressWarnings("deprecation")
158 @Test
159 public void testSAXBuilderBooleanFalse() {
160 SAXBuilder sb = new SAXBuilder(false);
161 assertNull(sb.getDriverClass());
162 assertTrue(sb.getEntityResolver() == null);
163 assertTrue(sb.getDTDHandler() == null);
164 assertTrue(sb.getXMLFilter() == null);
165 assertFalse(sb.isValidating());
166 assertTrue(sb.getExpandEntities());
167 }
168
169 @SuppressWarnings("deprecation")
170 @Test
171 public void testSAXBuilderBooleanTrue() {
172 SAXBuilder sb = new SAXBuilder(true);
173 assertNull(sb.getDriverClass());
174 assertTrue(sb.getEntityResolver() == null);
175 assertTrue(sb.getDTDHandler() == null);
176 assertTrue(sb.getXMLFilter() == null);
177 assertTrue(sb.isValidating());
178 assertTrue(sb.getExpandEntities());
179 }
180
181 @SuppressWarnings("deprecation")
182 @Test
183 public void testSAXBuilderString() {
184 MySAXBuilder sb = new MySAXBuilder("org.apache.xerces.parsers.SAXParser");
185 assertEquals("org.apache.xerces.parsers.SAXParser", sb.getDriverClass());
186 assertTrue(sb.getEntityResolver() == null);
187 assertTrue(sb.getDTDHandler() == null);
188 assertTrue(sb.getXMLFilter() == null);
189 assertFalse(sb.isValidating());
190 assertTrue(sb.getExpandEntities());
191 try {
192 XMLReader reader = sb.createParser();
193 assertNotNull(reader);
194 assertEquals("org.apache.xerces.parsers.SAXParser", reader.getClass().getName());
195
196 } catch (Exception e) {
197 e.printStackTrace();
198 fail("Could not create parser: " + e.getMessage());
199 }
200
201 sb = new MySAXBuilder("com.sun.org.apache.xerces.internal.parsers.SAXParser");
202 assertEquals("com.sun.org.apache.xerces.internal.parsers.SAXParser", sb.getDriverClass());
203 assertTrue(sb.getEntityResolver() == null);
204 assertTrue(sb.getDTDHandler() == null);
205 assertTrue(sb.getXMLFilter() == null);
206 assertFalse(sb.isValidating());
207 assertTrue(sb.getExpandEntities());
208 try {
209 XMLReader reader = sb.createParser();
210 assertNotNull(reader);
211 assertTrue(reader.getClass().getName().equals("com.sun.org.apache.xerces.internal.parsers.SAXParser"));
212
213 } catch (Exception e) {
214 e.printStackTrace();
215 fail("Could not create parser: " + e.getMessage());
216 }
217 }
218
219 @SuppressWarnings("deprecation")
220 @Test
221 public void testSAXBuilderStringNew() {
222 XMLReaderSAX2Factory fac = new XMLReaderSAX2Factory(false, "org.apache.xerces.parsers.SAXParser");
223 MySAXBuilder sb = new MySAXBuilder(fac);
224 assertEquals("org.apache.xerces.parsers.SAXParser", sb.getDriverClass());
225 assertTrue(sb.getEntityResolver() == null);
226 assertTrue(sb.getDTDHandler() == null);
227 assertTrue(sb.getXMLFilter() == null);
228 assertFalse(sb.isValidating());
229 assertTrue(sb.getExpandEntities());
230 try {
231 XMLReader reader = sb.createParser();
232 assertNotNull(reader);
233 assertEquals("org.apache.xerces.parsers.SAXParser", reader.getClass().getName());
234
235 } catch (Exception e) {
236 e.printStackTrace();
237 fail("Could not create parser: " + e.getMessage());
238 }
239
240 fac = new XMLReaderSAX2Factory(false, "com.sun.org.apache.xerces.internal.parsers.SAXParser");
241 sb = new MySAXBuilder("com.sun.org.apache.xerces.internal.parsers.SAXParser");
242 assertEquals("com.sun.org.apache.xerces.internal.parsers.SAXParser", sb.getDriverClass());
243 assertTrue(sb.getEntityResolver() == null);
244 assertTrue(sb.getDTDHandler() == null);
245 assertTrue(sb.getXMLFilter() == null);
246 assertFalse(sb.isValidating());
247 assertTrue(sb.getExpandEntities());
248 try {
249 XMLReader reader = sb.createParser();
250 assertNotNull(reader);
251 assertTrue(reader.getClass().getName().equals("com.sun.org.apache.xerces.internal.parsers.SAXParser"));
252
253 } catch (Exception e) {
254 e.printStackTrace();
255 fail("Could not create parser: " + e.getMessage());
256 }
257 }
258
259 @SuppressWarnings("deprecation")
260 @Test
261 public void testSAXBuilderStringTrue() {
262 SAXBuilder sb = new SAXBuilder("org.apache.xerces.parsers.SAXParser", true);
263 assertEquals("org.apache.xerces.parsers.SAXParser", sb.getDriverClass());
264 assertTrue(sb.getEntityResolver() == null);
265 assertTrue(sb.getDTDHandler() == null);
266 assertTrue(sb.getXMLFilter() == null);
267 assertTrue(sb.getValidation());
268 assertTrue(sb.getExpandEntities());
269 }
270
271 @SuppressWarnings("deprecation")
272 @Test
273 public void testSAXBuilderStringFalse() {
274 SAXBuilder sb = new SAXBuilder("org.apache.xerces.parsers.SAXParser", false);
275 assertEquals("org.apache.xerces.parsers.SAXParser", sb.getDriverClass());
276 assertTrue(sb.getEntityResolver() == null);
277 assertTrue(sb.getDTDHandler() == null);
278 assertTrue(sb.getXMLFilter() == null);
279 assertFalse(sb.isValidating());
280 assertTrue(sb.getExpandEntities());
281 }
282
283 @SuppressWarnings("deprecation")
284 @Test
285 public void testGetJDOMFactory() {
286 SAXBuilder sb = new SAXBuilder(true);
287 assertNull(sb.getDriverClass());
288 assertTrue(sb.getEntityResolver() == null);
289 assertTrue(sb.getDTDHandler() == null);
290 assertTrue(sb.getXMLFilter() == null);
291 assertTrue(sb.isValidating());
292 assertTrue(sb.getExpandEntities());
293 assertTrue(sb.getJDOMFactory() instanceof DefaultJDOMFactory);
294 assertTrue(sb.getJDOMFactory() == sb.getFactory());
295 }
296
297 @SuppressWarnings("deprecation")
298 @Test
299 public void testSetJDOMFactory() throws JDOMException {
300 SAXBuilder sb = new SAXBuilder(true);
301 assertNull(sb.getDriverClass());
302 assertTrue(sb.getEntityResolver() == null);
303 assertTrue(sb.getDTDHandler() == null);
304 assertTrue(sb.getXMLFilter() == null);
305 assertTrue(sb.getValidation());
306 assertTrue(sb.getExpandEntities());
307 JDOMFactory fac = sb.getJDOMFactory();
308 assertTrue(fac instanceof DefaultJDOMFactory);
309 UncheckedJDOMFactory udf = new UncheckedJDOMFactory();
310 sb.setJDOMFactory(udf);
311 assertTrue(sb.getJDOMFactory() == udf);
312 assertTrue(sb.buildEngine().getJDOMFactory() == udf);
313 sb.setFactory(fac);
314 assertTrue(sb.getJDOMFactory() == fac);
315 assertTrue(sb.buildEngine().getJDOMFactory() == fac);
316 }
317
318 @Test
319 public void testGetSAXHandlerFactory() {
320 SAXBuilder sb = new SAXBuilder();
321 assertTrue(sb.getSAXHandlerFactory() != null);
322 }
323
324 @SuppressWarnings("deprecation")
325 @Test
326 public void testSetSAXHandlerFactory() {
327 SAXBuilder sb = new SAXBuilder(true);
328 SAXHandlerFactory fac = sb.getSAXHandlerFactory();
329 sb.setSAXHandlerFactory(null);
330 assertTrue(fac == sb.getSAXHandlerFactory());
331 SAXHandlerFactory fbee = new SAXHandlerFactory() {
332 @Override
333 public SAXHandler createSAXHandler(JDOMFactory factory) {
334 return new SAXHandler();
335 }
336 };
337 sb.setSAXHandlerFactory(fbee);
338 assertTrue(fbee == sb.getSAXHandlerFactory());
339 sb.setSAXHandlerFactory(null);
340 assertTrue(fac == sb.getSAXHandlerFactory());
341 }
342
343 @SuppressWarnings("deprecation")
344 @Test
345 public void testSetValidation() {
346 SAXBuilder sb = new SAXBuilder(true);
347 assertNull(sb.getDriverClass());
348 assertTrue(sb.getEntityResolver() == null);
349 assertTrue(sb.getDTDHandler() == null);
350 assertTrue(sb.getXMLFilter() == null);
351 assertTrue(sb.getValidation());
352 assertTrue(sb.isValidating());
353 assertTrue(sb.getExpandEntities());
354
355 sb.setValidation(false);
356 assertFalse(sb.getValidation());
357 assertFalse(sb.isValidating());
358
359 sb.setValidation(true);
360 assertTrue(sb.getValidation());
361 assertTrue(sb.isValidating());
362
363 }
364
365 @SuppressWarnings("deprecation")
366 @Test
367 public void testGetErrorHandler() throws JDOMException {
368 SAXBuilder sb = new SAXBuilder(true);
369 assertTrue(sb.getEntityResolver() == null);
370 assertTrue(sb.getErrorHandler() == null);
371 assertTrue(sb.getDTDHandler() == null);
372 assertTrue(sb.getXMLFilter() == null);
373 assertTrue(sb.isValidating());
374 assertTrue(sb.getExpandEntities());
375
376 assertTrue(sb.buildEngine().getErrorHandler() instanceof BuilderErrorHandler);
377
378 ErrorHandler handler = new BuilderErrorHandler();
379
380 sb.setErrorHandler(handler);
381 assertTrue(handler == sb.getErrorHandler());
382 assertTrue(handler == sb.buildEngine().getErrorHandler());
383 }
384
385 @SuppressWarnings("deprecation")
386 @Test
387 public void testGetEntityResolver() {
388 SAXBuilder sb = new SAXBuilder(true);
389 assertTrue(sb.getEntityResolver() == null);
390 assertTrue(sb.getErrorHandler() == null);
391 assertTrue(sb.getDTDHandler() == null);
392 assertTrue(sb.getXMLFilter() == null);
393 assertTrue(sb.isValidating());
394 assertTrue(sb.getExpandEntities());
395
396 EntityResolver er = new EntityResolver() {
397 @Override
398 public InputSource resolveEntity(String arg0, String arg1) {
399 return null;
400 }
401 };
402
403 sb.setEntityResolver(er);
404 assertTrue(er == sb.getEntityResolver());
405 }
406
407 @SuppressWarnings("deprecation")
408 @Test
409 public void testGetDTDHandler() {
410 SAXBuilder sb = new SAXBuilder(true);
411 assertTrue(sb.getEntityResolver() == null);
412 assertTrue(sb.getErrorHandler() == null);
413 assertTrue(sb.getDTDHandler() == null);
414 assertTrue(sb.getXMLFilter() == null);
415 assertTrue(sb.isValidating());
416 assertTrue(sb.getExpandEntities());
417
418 DTDHandler dtd = new DTDHandler() {
419 @Override
420 public void notationDecl(String arg0, String arg1, String arg2)
421 throws SAXException {
422 // do nothing
423 }
424 @Override
425 public void unparsedEntityDecl(String arg0, String arg1,
426 String arg2, String arg3) throws SAXException {
427 // do nothing
428 }
429 };
430
431 sb.setDTDHandler(dtd);
432 assertTrue(dtd == sb.getDTDHandler());
433 }
434
435 @Test
436 public void testGetSetXMLReaderFactory() {
437 SAXBuilder sb = new SAXBuilder();
438 XMLReaderJDOMFactory xrjf = sb.getXMLReaderFactory();
439 assertTrue(xrjf == XMLReaders.NONVALIDATING);
440 sb.setXMLReaderFactory(XMLReaders.XSDVALIDATING);
441 assertTrue(sb.getXMLReaderFactory() == XMLReaders.XSDVALIDATING);
442 sb.setXMLReaderFactory(null);
443 assertTrue(xrjf == XMLReaders.NONVALIDATING);
444 }
445
446 @Test
447 public void testXMLFilter() {
448 MySAXBuilder sb = new MySAXBuilder();
449 assertTrue(sb.getEntityResolver() == null);
450 assertTrue(sb.getErrorHandler() == null);
451 assertTrue(sb.getDTDHandler() == null);
452 assertTrue(sb.getXMLFilter() == null);
453 assertTrue(sb.getExpandEntities());
454
455 XMLFilter filter = new XMLFilterImpl() {
456 @Override
457 public void startElement(String arg0, String arg1, String arg2,
458 Attributes arg3) throws SAXException {
459 super.startElement(arg0, "f" + arg1, arg2, arg3);
460 }
461 @Override
462 public void endElement(String arg0, String arg1, String arg2) throws SAXException {
463 super.endElement(arg0, "f" + arg1, arg2);
464 }
465 };
466
467 XMLFilter gilter = new XMLFilterImpl() {
468 @Override
469 public void startElement(String arg0, String arg1, String arg2,
470 Attributes arg3) throws SAXException {
471 super.startElement(arg0, "g" + arg1, arg2, arg3);
472 }
473 @Override
474 public void endElement(String arg0, String arg1, String arg2) throws SAXException {
475 super.endElement(arg0, "g" + arg1, arg2);
476 }
477 };
478
479 filter.setParent(gilter);
480 sb.setXMLFilter(filter);
481 assertTrue(filter == sb.getXMLFilter());
482
483 try {
484 Document doc = sb.build(new CharArrayReader(testxml.toCharArray()));
485 assertTrue(doc.hasRootElement());
486 assertEquals("fgroot", doc.getRootElement().getName());
487 } catch (Exception e) {
488 e.printStackTrace();
489 fail("Could not parse XML " + testxml + ": " + e.getMessage());
490 }
491
492 }
493
494 @Test
495 public void testGetIgnoringElementContentWhitespace() throws JDOMException, IOException {
496 SAXBuilder sb = new SAXBuilder();
497 assertNull(sb.getDriverClass());
498 assertTrue(sb.getEntityResolver() == null);
499 assertTrue(sb.getErrorHandler() == null);
500 assertTrue(sb.getDTDHandler() == null);
501 assertTrue(sb.getXMLFilter() == null);
502 assertFalse(sb.isValidating());
503 assertTrue(sb.getExpandEntities());
504
505 SAXEngine se = sb.buildEngine();
506 assertFalse(se.getIgnoringBoundaryWhitespace());
507
508 sb.setIgnoringElementContentWhitespace(true);
509 assertTrue(sb.getIgnoringElementContentWhitespace());
510 se = sb.buildEngine();
511 assertTrue(se.getIgnoringElementContentWhitespace());
512 se.build(new StringReader(testxml));
513 assertTrue(se.getIgnoringElementContentWhitespace());
514 sb.setIgnoringElementContentWhitespace(false);
515 assertFalse(sb.getIgnoringElementContentWhitespace());
516 se = sb.buildEngine();
517 assertFalse(se.getIgnoringElementContentWhitespace());
518 }
519
520 @Test
521 public void testGetIgnoringBoundaryWhitespace() throws JDOMException, IOException {
522 SAXBuilder sb = new SAXBuilder();
523 SAXEngine se = sb.buildEngine();
524 assertNull(sb.getDriverClass());
525 assertTrue(sb.getEntityResolver() == null);
526 assertTrue(sb.getErrorHandler() == null);
527 assertTrue(sb.getDTDHandler() == null);
528 assertTrue(sb.getXMLFilter() == null);
529 assertFalse(sb.isValidating());
530 assertTrue(sb.getExpandEntities());
531 assertTrue(se.getEntityResolver() == null);
532 assertTrue(se.getErrorHandler() != null);
533 assertTrue(se.getDTDHandler() != null);
534 assertFalse(se.isValidating());
535 assertTrue(se.getExpandEntities());
536 sb.setIgnoringBoundaryWhitespace(true);
537 assertTrue(sb.getIgnoringBoundaryWhitespace());
538 se = sb.buildEngine();
539 assertTrue(se.getIgnoringBoundaryWhitespace());
540 se.build(new StringReader(testxml));
541 assertTrue(se.getIgnoringBoundaryWhitespace());
542 sb.setIgnoringBoundaryWhitespace(false);
543 assertFalse(sb.getIgnoringBoundaryWhitespace());
544
545 se = sb.buildEngine();
546 assertFalse(se.getIgnoringBoundaryWhitespace());
547 }
548
549 @Test
550 public void testGetExpandEntities() throws JDOMException, IOException {
551 SAXBuilder sb = new SAXBuilder();
552 assertTrue(sb.getExpandEntities());
553 sb.setExpandEntities(false);
554 SAXEngine se = sb.buildEngine();
555 assertFalse(se.getExpandEntities());
556 se = sb.buildEngine();
557 assertFalse(se.getExpandEntities());
558 se.build(new StringReader(testxml));
559 assertFalse(se.getExpandEntities());
560
561 sb.setExpandEntities(true);
562 assertTrue(sb.getExpandEntities());
563 se = sb.buildEngine();
564 assertTrue(se.getExpandEntities());
565 se.build(new StringReader(testxml));
566 assertTrue(se.getExpandEntities());
567 }
568
569 @SuppressWarnings("deprecation")
570 @Test
571 public void testGetReuseParser() {
572 SAXBuilder sb = new SAXBuilder(true);
573 assertTrue(sb.getEntityResolver() == null);
574 assertTrue(sb.getErrorHandler() == null);
575 assertTrue(sb.getDTDHandler() == null);
576 assertTrue(sb.getXMLFilter() == null);
577 assertTrue(sb.isValidating());
578 assertTrue(sb.getExpandEntities());
579
580 sb.setReuseParser(true);
581 assertTrue(sb.getReuseParser());
582 sb.setReuseParser(false);
583 assertFalse(sb.getReuseParser());
584 }
585
586 @Test
587 public void testReuseParser() throws JDOMException, IOException {
588 SAXBuilder sb = new SAXBuilder();
589 assertTrue(sb.getReuseParser());
590
591 sb.build(new StringReader("<?xml version=\"1.0\"?>\n<!-- comment -->\n<root/>"));
592 Document document = sb.build(new StringReader(testxml));
593 assertXMLMatches(null, document);
594 }
595
596 @Test
597 public void testCreateParser() {
598 MySAXBuilder sb = new MySAXBuilder();
599 try {
600 XMLReader reader = sb.createParser();
601 assertNotNull(reader);
602 } catch (JDOMException e) {
603 e.printStackTrace();
604 fail("Could not create parser: " + e.getMessage());
605 }
606 }
607
608 @Test
609 public void testSetFeature() {
610 String feature = "http://javax.xml.XMLConstants/feature/secure-processing";
611 MySAXBuilder sb = new MySAXBuilder();
612 try {
613 sb.setFeature(feature, true);
614 XMLReader reader = sb.createParser();
615 assertNotNull(reader);
616 assertTrue(reader.getFeature(feature));
617 sb.setFeature(feature, false);
618 reader = sb.createParser();
619 assertNotNull(reader);
620 assertFalse(reader.getFeature(feature));
621
622 } catch (Exception e) {
623 e.printStackTrace();
624 fail("Could not create parser: " + e.getMessage());
625 }
626 }
627
628 @Test
629 public void testSetProperty() {
630 LexicalHandler lh = new LexicalHandler() {
631 @Override
632 public void startEntity(String arg0) throws SAXException {
633 // Do nothing;
634 }
635 @Override
636 public void startDTD(String arg0, String arg1, String arg2)
637 throws SAXException {
638 // Do nothing;
639 }
640 @Override
641 public void startCDATA() throws SAXException {
642 // Do nothing;
643 }
644 @Override
645 public void endEntity(String arg0) throws SAXException {
646 // Do nothing;
647 }
648
649 @Override
650 public void endDTD() throws SAXException {
651 // Do nothing;
652 }
653
654 @Override
655 public void endCDATA() throws SAXException {
656 // Do nothing;
657 }
658
659 @Override
660 public void comment(char[] arg0, int arg1, int arg2) throws SAXException {
661 // Do nothing;
662 }
663 };
664
665 MySAXBuilder sb = new MySAXBuilder();
666 String propname = "http://xml.org/sax/properties/lexical-handler";
667 try {
668 sb.setProperty(propname, lh);
669 XMLReader reader = sb.createParser();
670 assertNotNull(reader);
671 assertTrue(lh == reader.getProperty(propname));
672 } catch (Exception e) {
673 e.printStackTrace();
674 fail("Could not create parser: " + e.getMessage());
675 }
676 sb.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "XMLSchema");
677
678 }
679
680 @Test
681 public void testSetPropertyTwo() {
682 MySAXBuilder sb = new MySAXBuilder();
683 try {
684 sb.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "XMLSchema");
685 sb.createParser();
686 fail("Should not be able to set the property");
687 } catch (JDOMException jde) {
688 // good
689 } catch (Exception e) {
690 e.printStackTrace();
691 fail("Could not create parser: " + e.getMessage());
692 }
693
694 }
695
696 /**
697 * Test that when setExpandEntities is true, enties are
698 * always expanded and when false, entities declarations
699 * are added to the DocType
700 */
701 @Test
702 public void test_TCM__void_setExpandEntities_boolean() throws JDOMException, IOException {
703 //test entity exansion on internal entity
704
705 URL src = FidoFetch.getFido().getURL("/SAXBuilderTestEntity.xml");
706
707 SAXBuilder builder = new SAXBuilder();
708
709 builder.setExpandEntities(true);
710 assertTrue(builder.getExpandEntities());
711
712 Document doc = builder.build(src);
713 assertTrue("didn't get entity text", doc.getRootElement().getText().indexOf("simple entity") == 0);
714 assertTrue("didn't get entity text", doc.getRootElement().getText().indexOf("another simple entity") > 1);
715
716 //test that entity declaration appears in doctype
717 //and EntityRef is created in content with internal entity
718 builder.setExpandEntities(false);
719 assertFalse(builder.getExpandEntities());
720
721 doc = builder.build(src);
722 assertTrue("got entity text", ! (doc.getRootElement().getText().indexOf("simple entity") > 1));
723 assertTrue("got entity text", ! (doc.getRootElement().getText().indexOf("another simple entity") > 1));
724 List<Content> content = doc.getRootElement().getContent();
725 assertTrue("didn't get EntityRef for unexpanded entities",
726 content.get(0) instanceof EntityRef);
727 assertTrue("didn't get EntityRef for unexpanded entities",
728 content.get(2) instanceof EntityRef);
729
730 //test entity expansion on external entity
731 URL src2 = FidoFetch.getFido().getURL("/SAXBuilderTestEntity2.xml");
732
733 builder.setExpandEntities(true);
734 assertTrue(builder.getExpandEntities());
735
736 doc = builder.build(src2);
737 assertTrue("didn't get entity text", doc.getRootElement().getText().indexOf("simple entity") == 0);
738 assertTrue("didn't get entity text", doc.getRootElement().getText().indexOf("another simple entity") > 1);
739
740 //test that entity declaration appears in doctype
741 //and EntityRef is created in content with external entity
742 builder.setExpandEntities(false);
743 assertFalse(builder.getExpandEntities());
744 doc = builder.build(src2);
745 assertTrue("got entity text", ! (doc.getRootElement().getText().indexOf("simple entity") > 1));
746 assertTrue("got entity text", ! (doc.getRootElement().getText().indexOf("another simple entity") > 1));
747 content = doc.getRootElement().getContent();
748 assertTrue("didn't get EntityRef for unexpanded entities",
749 content.get(0) instanceof EntityRef);
750 assertTrue("didn't get EntityRef for unexpanded entities",
751 content.get(2) instanceof EntityRef);
752
753
754
755 }
756
757 /**
758 * Test that when setExpandEntities is true, enties are
759 * always expanded and when false, entities declarations
760 * are added to the DocType
761 */
762 @Test
763 public void test_TCU__DTDComments() throws JDOMException, IOException {
764 //test entity exansion on internal entity
765
766 SAXBuilder builder = new SAXBuilder();
767 //test entity expansion on external entity
768 URL file = FidoFetch.getFido().getURL("/SAXBuilderTestDecl.xml");
769
770 //test that entity declaration appears in doctype
771 //and EntityRef is created in content with external entity
772 builder.setExpandEntities(false);
773 Document doc = builder.build(file);
774
775 assertTrue("didnt' get internal subset comments correctly", doc.getDocType().getInternalSubset().indexOf("foo") > 0);
776 //assertTrue("didn't get EntityRef for unexpanded attribute entities",
777 // doc.getRootElement().getAttribute("test").getValue().indexOf("&simple") == 0);
778
779
780
781 }
782
783 /**
784 * Test that when setExpandEntities is true, enties are
785 * always expanded and when false, entities declarations
786 * are added to the DocType
787 */
788 @Test
789 public void test_TCU__InternalAndExternalEntities() throws JDOMException, IOException {
790 //test entity exansion on internal entity
791
792 SAXBuilder builder = new SAXBuilder();
793 //test entity expansion on internal and external entity
794 URL file = FidoFetch.getFido().getURL("/SAXBuilderTestIntExtEntity.xml");
795
796 builder.setExpandEntities(true);
797 Document doc = builder.build(file);
798 assertTrue("didn't get internal entity text", doc.getRootElement().getText().indexOf("internal") >= 0);
799 assertTrue("didn't get external entity text", doc.getRootElement().getText().indexOf("external") > 0);
800 //the internal subset should be empty since entity expansion is off
801 assertTrue("invalid characters in internal subset", doc.getDocType().getInternalSubset().length() == 0);
802 assertTrue("incorrectly got entity declaration in internal subset for internal entity",
803 doc.getDocType().getInternalSubset().indexOf("internal") < 0);
804 assertTrue("incorrectly got external entity declaration in internal subset",
805 doc.getDocType().getInternalSubset().indexOf("external") < 0);
806 assertTrue("incorrectly got external entity declaration in internal subset",
807 doc.getDocType().getInternalSubset().indexOf("ldquo") < 0);
808 //test that local entity declaration appears in internal subset
809 //and EntityRef is created in content with external entity
810 builder.setExpandEntities(false);
811 doc = builder.build(file);
812
813 EntityRef internal = (EntityRef)doc.getRootElement().getContent().get(0);
814 EntityRef external = (EntityRef)doc.getRootElement().getContent().get(6);
815 assertNotNull("didn't get EntityRef for unexpanded internal entity", internal);
816 assertNotNull("didn't get EntityRef for unexpanded external entity", external);
817 assertTrue("didn't get local entity declaration in internal subset",
818 doc.getDocType().getInternalSubset().indexOf("internal") > 0);
819 assertTrue("incorrectly got external entity declaration in internal subset",
820 doc.getDocType().getInternalSubset().indexOf("external") < 0);
821 assertTrue("incorrectly got external entity declaration in internal subset",
822 doc.getDocType().getInternalSubset().indexOf("ldquo") < 0);
823 }
824
825 @Ignore
826 @Test
827 public void test_TCU__InternalSubset() throws JDOMException, IOException {
828
829 SAXBuilder builder = new SAXBuilder();
830 //test entity expansion on internal subset
831 URL file = FidoFetch.getFido().getURL("/SAXBuilderTestEntity.xml");
832
833 builder.setExpandEntities(true);
834 Document doc = builder.build(file);
835 String subset = doc.getDocType().getInternalSubset();
836 assertEquals("didn't get correct internal subset when expand entities was on"
837 , " <!NOTATION n1 SYSTEM \"http://www.w3.org/\">\n <!NOTATION n2 SYSTEM \"http://www.w3.org/\">\n <!ENTITY anotation SYSTEM \"http://www.foo.org/image.gif\" NDATA n1>\n",
838 subset);
839 //now do it with expansion off
840 builder.setExpandEntities(false);
841 doc = builder.build(file);
842 String subset2 = doc.getDocType().getInternalSubset();
843 final String expect = "<!NOTATION n2 SYSTEM \"http://www.w3.org/\">\n <!ENTITY anotation SYSTEM \"http://www.foo.org/image.gif\" NDATA n1>\n";
844 if (!expect.equals(subset2)) {
845 fail("didn't get correct internal subset when expand entities was off.\n" +
846 "Expect: " + expect + "\n" +
847 "Got: " + subset2);
848 }
849 }
850
851 @SuppressWarnings("deprecation")
852 @Test
853 public void testSetFastReconfigure() {
854 SAXBuilder sb = new SAXBuilder(true);
855 assertTrue(sb.getEntityResolver() == null);
856 assertTrue(sb.getErrorHandler() == null);
857 assertTrue(sb.getDTDHandler() == null);
858 assertTrue(sb.getXMLFilter() == null);
859 assertTrue(sb.isValidating());
860 assertTrue(sb.getExpandEntities());
861
862 sb.setFastReconfigure(true);
863
864 // TODO - Now what?
865 }
866
867 private void assertXMLMatches(String baseuri, Document doc) {
868 XMLOutputter2 out = new XMLOutputter2(Format.getCompactFormat());
869 try {
870 CharArrayWriter caw = new CharArrayWriter();
871 out.output(doc, caw);
872 String output = caw.toString();
873 if (!output.matches(testpattern)) {
874 fail ("Failed to match output:\n " + output + "\nwith pattern:\n " + testpattern);
875 }
876 } catch (IOException e) {
877 e.printStackTrace();
878 UnitTestUtil.failException("Failed to write Document " + doc + " to CharArrayWriter.", e);
879 }
880 if (baseuri == null) {
881 assertNull(doc.getBaseURI());
882 } else {
883 if (!baseuri.equals(doc.getBaseURI())) {
884 try {
885 final String moduri = baseuri.replaceFirst(":/", ":///");
886 if (!moduri.equals(doc.getBaseURI())) {
887 final String fileuri = new File(baseuri).toURI().toURL().toExternalForm();
888 if (!fileuri.equals(doc.getBaseURI())) {
889 final String modfileuri = fileuri.replaceFirst(":/", ":///");
890 if (!modfileuri.equals(doc.getBaseURI())) {
891 fail("Base URI " + doc.getBaseURI() + " is not one of " +
892 Arrays.toString(new String[]{baseuri, moduri, fileuri, modfileuri}));
893 }
894 }
895 }
896 } catch (MalformedURLException mue) {
897 UnitTestUtil.failException("Could not create File URL", mue);
898 }
899 }
900 }
901 }
902
903 @Test
904 public void testBuildInputSource() {
905 try {
906 SAXBuilder sb = new SAXBuilder();
907 InputSource is = null;
908 is = new InputSource(new CharArrayReader(testxml.toCharArray()));
909 assertXMLMatches(null, sb.build(is));
910 is = new InputSource(new CharArrayReader(testxml.toCharArray()));
911 assertXMLMatches(null, sb.build(is));
912 sb.setReuseParser(false);
913 is = new InputSource(new CharArrayReader(testxml.toCharArray()));
914 assertXMLMatches(null, sb.build(is));
915 is = new InputSource(new CharArrayReader(testxml.toCharArray()));
916 assertXMLMatches(null, sb.build(is));
917
918 is = new InputSource(new CharArrayReader(testxml.toCharArray()));
919 assertXMLMatches(null, sb.buildEngine().build(is));
920 } catch (Exception e) {
921 e.printStackTrace();
922 fail("Failed to parse document: " + e.getMessage());
923 }
924 }
925
926 @Test
927 public void testBuildInputStream() {
928 byte[] bytes = testxml.getBytes();
929 try {
930 SAXBuilder sb = new SAXBuilder();
931 assertXMLMatches(null, sb.build(new ByteArrayInputStream(bytes)));
932 assertXMLMatches(null, sb.build(new ByteArrayInputStream(bytes)));
933 sb.setReuseParser(false);
934 assertXMLMatches(null, sb.build(new ByteArrayInputStream(bytes)));
935 assertXMLMatches(null, sb.build(new ByteArrayInputStream(bytes)));
936
937 assertXMLMatches(null, sb.buildEngine().build(new ByteArrayInputStream(bytes)));
938 } catch (Exception e) {
939 e.printStackTrace();
940 fail("Failed to parse document: " + e.getMessage());
941 }
942 }
943
944 @Test
945 public void testBuildFile() {
946 File tmp = null;
947 try {
948 tmp = File.createTempFile("tst", ".xml");
949 tmp.deleteOnExit();
950 FileWriter fw = new FileWriter(tmp);
951 fw.write(testxml.toCharArray());
952 fw.flush();
953 fw.close();
954 SAXBuilder sb = new SAXBuilder();
955 assertXMLMatches(tmp.toURI().toString(), sb.build(tmp));
956 assertXMLMatches(tmp.toURI().toString(), sb.build(tmp));
957 sb.setReuseParser(false);
958 assertXMLMatches(tmp.toURI().toString(), sb.build(tmp));
959 assertXMLMatches(tmp.toURI().toString(), sb.build(tmp));
960 assertXMLMatches(tmp.toURI().toString(), sb.buildEngine().build(tmp));
961
962 } catch (Exception e) {
963 e.printStackTrace();
964 fail("Failed to write/parse document to file '" + tmp + "': " + e.getMessage());
965 } finally {
966 if (tmp != null) {
967 tmp.delete();
968 }
969 }
970 }
971
972 @Test
973 public void testBuildURL() {
974 File tmp = null;
975 try {
976 tmp = File.createTempFile("tst", ".xml");
977 tmp.deleteOnExit();
978 FileWriter fw = new FileWriter(tmp);
979 fw.write(testxml.toCharArray());
980 fw.flush();
981 fw.close();
982 SAXBuilder sb = new SAXBuilder();
983 assertXMLMatches(tmp.toURI().toString(), sb.build(tmp.toURI().toURL()));
984 assertXMLMatches(tmp.toURI().toString(), sb.build(tmp.toURI().toURL()));
985 sb.setReuseParser(false);
986 assertXMLMatches(tmp.toURI().toString(), sb.build(tmp.toURI().toURL()));
987 assertXMLMatches(tmp.toURI().toString(), sb.build(tmp.toURI().toURL()));
988
989 assertXMLMatches(tmp.toURI().toString(), sb.buildEngine().build(tmp.toURI().toURL()));
990 } catch (Exception e) {
991 e.printStackTrace();
992 fail("Failed to write/parse document to file '" + tmp + "': " + e.getMessage());
993 } finally {
994 if (tmp != null) {
995 tmp.delete();
996 }
997 }
998 }
999
1000 @Test
1001 public void testBuildInputStreamString() {
1002 byte[] bytes = testxml.getBytes();
1003
1004 try {
1005 SAXBuilder sb = new SAXBuilder();
1006 assertXMLMatches("baseID",
1007 sb.build(new ByteArrayInputStream(bytes), "baseID"));
1008 assertXMLMatches("baseID",
1009 sb.build(new ByteArrayInputStream(bytes), "baseID"));
1010 sb.setReuseParser(false);
1011 assertXMLMatches("baseID",
1012 sb.build(new ByteArrayInputStream(bytes), "baseID"));
1013 assertXMLMatches("baseID",
1014 sb.build(new ByteArrayInputStream(bytes), "baseID"));
1015 assertXMLMatches("baseID",
1016 sb.buildEngine().build(new ByteArrayInputStream(bytes), "baseID"));
1017 } catch (Exception e) {
1018 e.printStackTrace();
1019 UnitTestUtil.failException("Failed to parse document: " + e.getMessage(), e);
1020 }
1021 }
1022
1023 @Test
1024 public void testBuildReader() {
1025 char[] chars = testxml.toCharArray();
1026 try {
1027 SAXBuilder sb = new SAXBuilder();
1028 assertXMLMatches(null, sb.build(new CharArrayReader(chars)));
1029 assertXMLMatches(null, sb.build(new CharArrayReader(chars)));
1030 sb.setReuseParser(false);
1031 assertXMLMatches(null, sb.build(new CharArrayReader(chars)));
1032 assertXMLMatches(null, sb.build(new CharArrayReader(chars)));
1033
1034 assertXMLMatches(null, sb.buildEngine().build(new CharArrayReader(chars)));
1035 } catch (Exception e) {
1036 e.printStackTrace();
1037 UnitTestUtil.failException("Failed to parse document: " + e.getMessage(), e);
1038 }
1039 }
1040
1041 @Test
1042 public void testBuildReaderString() {
1043 char[] chars = testxml.toCharArray();
1044 try {
1045 SAXBuilder sb = new SAXBuilder();
1046 assertXMLMatches("baseID",
1047 sb.build(new CharArrayReader(chars), "baseID"));
1048 assertXMLMatches("baseID",
1049 sb.build(new CharArrayReader(chars), "baseID"));
1050 sb.setReuseParser(false);
1051 assertXMLMatches("baseID",
1052 sb.build(new CharArrayReader(chars), "baseID"));
1053 assertXMLMatches("baseID",
1054 sb.build(new CharArrayReader(chars), "baseID"));
1055
1056 assertXMLMatches("baseID",
1057 sb.buildEngine().build(new CharArrayReader(chars), "baseID"));
1058 } catch (Exception e) {
1059 e.printStackTrace();
1060 fail("Failed to parse document: " + e.getMessage());
1061 }
1062 }
1063
1064 @Test
1065 public void testBuildString() {
1066 File tmp = null;
1067 try {
1068 tmp = File.createTempFile("tst", ".xml");
1069 tmp.deleteOnExit();
1070 FileWriter fw = new FileWriter(tmp);
1071 fw.write(testxml.toCharArray());
1072 fw.flush();
1073 fw.close();
1074 SAXBuilder sb = new SAXBuilder();
1075 assertXMLMatches(tmp.getCanonicalFile().toURI().toURL().toString(),
1076 sb.build(tmp.toString()));
1077 assertXMLMatches(tmp.getCanonicalFile().toURI().toURL().toString(),
1078 sb.build(tmp.toString()));
1079 sb.setReuseParser(false);
1080 assertXMLMatches(tmp.getCanonicalFile().toURI().toURL().toString(),
1081 sb.build(tmp.toString()));
1082 assertXMLMatches(tmp.getCanonicalFile().toURI().toURL().toString(),
1083 sb.build(tmp.toString()));
1084
1085 assertXMLMatches(tmp.getCanonicalFile().toURI().toURL().toString(),
1086 sb.buildEngine().build(tmp.toString()));
1087 } catch (Exception e) {
1088 e.printStackTrace();
1089 fail("Failed to write/parse document to file '" + tmp + "': " + e.getMessage());
1090 } finally {
1091 if (tmp != null) {
1092 tmp.delete();
1093 }
1094 }
1095 }
1096
1097 @Test
1098 public void testBuildStringNegativeNull() {
1099 SAXBuilder sb = new SAXBuilder();
1100 try {
1101 String n = null;
1102 sb.build(n);
1103 failNoException(NullPointerException.class);
1104 } catch (Exception e) {
1105 checkException(NullPointerException.class, e);
1106 }
1107 }
1108
1109 @Test
1110 public void testBuildStringNegativeBadURI() {
1111 SAXBuilder sb = new SAXBuilder();
1112 try {
1113 sb.build(" `!@#$%^&*() is not a valid URI ");
1114 failNoException(MalformedURLException.class);
1115 } catch (Exception e) {
1116 checkException(MalformedURLException.class, e);
1117 if (e.getCause() != null) {
1118 assertFalse(e.getCause() instanceof MalformedURLException);
1119 }
1120 }
1121 }
1122
1123 @Test
1124 public void testXMLNamesVariants() throws JDOMException, IOException {
1125 String toparse = "<xMl:xml xmlns:xMl='MyURI' xml='xml'/>";
1126
1127 SAXBuilder sb = new SAXBuilder();
1128 Document doc = sb.build(new CharArrayReader(toparse.toCharArray()));
1129
1130 assertEquals("Should match: xml", "xml" , doc.getRootElement().getAttributeValue("xml"));
1131
1132
1133 }
1134
1135 @Test
1136 public void testBuildStringNegativeActualXML() {
1137 SAXBuilder sb = new SAXBuilder();
1138 try {
1139 sb.build("<root />");
1140 failNoException(IOException.class);
1141 } catch (Exception e) {
1142 checkException(IOException.class, e);
1143 // cause should also be a MalformedURLException
1144 checkException(IOException.class, e.getCause());
1145 }
1146 }
1147
1148 @Test
1149 public void testBuildStringNegativePaddedXML() {
1150 SAXBuilder sb = new SAXBuilder();
1151 try {
1152 sb.build(" <!-- comment --> ");
1153 failNoException(IOException.class);
1154 } catch (Exception e) {
1155 checkException(IOException.class, e);
1156 checkException(IOException.class, e.getCause());
1157 }
1158 }
1159
1160 @Test
1161 public void testSimpleCDATA() throws JDOMException, IOException {
1162 SAXBuilder sb = new SAXBuilder();
1163 Document doc = sb.build(new StringReader("<message><![CDATA[hello]]></message>"));
1164 List<Content> content = doc.getRootElement().getContent();
1165 assertEquals("Should be only one child: " + content, 1 , content.size());
1166 }
1167
1168 @Test
1169 public void testSplitCDATAinCDATA() throws JDOMException, IOException {
1170 // Note the ]]><![CDATA[ in the middle
1171 String toparse = "<message><![CDATA[ expected:<[[D/0]]]]><![CDATA[> but was:<[null]> ]]></message>";
1172
1173 SAXBuilder sb = new SAXBuilder();
1174 Document doc = sb.build(new CharArrayReader(toparse.toCharArray()));
1175
1176 assertEquals("Should match: expected:<[[D/0]]> but was:<[null]>", " expected:<[[D/0]]> but was:<[null]> ", doc.getRootElement().getValue());
1177 }
1178
1179 @Test
1180 public void testParserFactory() throws JDOMException, IOException {
1181 if (System.getProperty("org.jdom2.performance") == null) {
1182 // for android.
1183 //Assume.assumeNotNull(System.getProperty("org.jdom.performance"));
1184 return;
1185 }
1186 long start = 0L, time = 0L;
1187 loopParser(false, false);
1188 loopParser(false, false);
1189 loopParser(false, false);
1190 start = System.nanoTime();
1191 loopParser(false, false);
1192 time = System.nanoTime() - start;
1193 System.out.printf("SimpleLoop Recreate %.3fms\n", time / 1000000.0);
1194
1195 loopParser(true, false);
1196 loopParser(true, false);
1197 loopParser(true, false);
1198 start = System.nanoTime();
1199 loopParser(true, false);
1200 time = System.nanoTime() - start;
1201 System.out.printf("SimpleLoop Reuse %.3fms\n", time / 1000000.0);
1202
1203 loopParser(true, true);
1204 loopParser(true, true);
1205 loopParser(true, true);
1206 start = System.nanoTime();
1207 loopParser(true, true);
1208 time = System.nanoTime() - start;
1209 System.out.printf("SimpleLoop Fast %.3fms\n", time / 1000000.0);
1210 }
1211
1212
1213 @SuppressWarnings("deprecation")
1214 private void loopParser(boolean reuse, boolean fast) throws JDOMException, IOException {
1215 if (fast) {
1216 System.out.println("Fast no longer means anything.");
1217 }
1218 SAXBuilder builderval = new SAXBuilder(true);
1219 SAXBuilder buildernoval = new SAXBuilder(false);
1220 builderval.setReuseParser(reuse);
1221 buildernoval.setReuseParser(reuse);
1222 String docstr =
1223 "<?xml version='1.0'?><!DOCTYPE root [ <!ELEMENT root (#PCDATA)>]><root />";
1224 char[] chars = docstr.toCharArray();
1225 ResetReader rr = new ResetReader(chars);
1226 for (int i = 0; i < 10000; i++) {
1227 parseMem(builderval, rr);
1228 parseMem(buildernoval, rr);
1229 }
1230 //JAXPFastParserFactory.printTimes();
1231 }
1232
1233 private void parseMem(SAXBuilder builder, ResetReader reader) throws JDOMException, IOException {
1234 reader.reset();
1235 Document doc = builder.build(reader);
1236 assertTrue(doc.hasRootElement());
1237 assertEquals("root", doc.getRootElement().getName());
1238 }
1239
1240 private static final class ResetReader extends Reader {
1241
1242 private final char[] chars;
1243 private int pos = 0;
1244
1245 public ResetReader(final char[] ch) {
1246 chars = ch;
1247 }
1248
1249 @Override
1250 public int read(final CharBuffer target) throws IOException {
1251 final int got = chars.length - pos;
1252 if (got == 0) {
1253 return -1;
1254 }
1255 final int howmuch = target.remaining();
1256 final int ret = got > howmuch ? howmuch : got;
1257 target.put(chars, pos, ret);
1258 pos += ret;
1259 return ret;
1260 }
1261
1262 @Override
1263 public int read() throws IOException {
1264 if (pos >= chars.length) {
1265 return -1;
1266 }
1267 return chars[pos++];
1268 }
1269
1270 @Override
1271 public int read(final char[] cbuf) throws IOException {
1272 final int got = chars.length - pos;
1273 if (got == 0) {
1274 return -1;
1275 }
1276 final int ret = got > cbuf.length ? cbuf.length : got;
1277 System.arraycopy(chars, pos, cbuf, 0, ret);
1278 pos += ret;
1279 return ret;
1280 }
1281
1282 @Override
1283 public int read(final char[] cbuf, final int off, final int howmuch) throws IOException {
1284 final int got = chars.length - pos;
1285 if (got == 0) {
1286 return -1;
1287 }
1288 final int ret = got > howmuch ? howmuch : got;
1289 System.arraycopy(chars, pos, cbuf, off, ret);
1290 pos += ret;
1291 return ret;
1292 }
1293
1294 @Override
1295 public long skip(final long n) throws IOException {
1296 long got = chars.length - pos;
1297 if (got > n) {
1298 pos += (int)n;
1299 return n;
1300 }
1301 long ret = chars.length - pos;
1302 pos = chars.length;
1303 return ret;
1304 }
1305
1306 @Override
1307 public boolean ready() throws IOException {
1308 return true;
1309 }
1310
1311 @Override
1312 public boolean markSupported() {
1313 return false;
1314 }
1315
1316 @Override
1317 public void mark(final int readAheadLimit) throws IOException {
1318 return;
1319 }
1320
1321 @Override
1322 public void reset() throws IOException {
1323 pos = 0;
1324 }
1325
1326 @Override
1327 public void close() throws IOException {
1328 return;
1329 }
1330
1331 }
1332
1333 }
0 /**
1 *
2 */
3 package org.jdom.test.cases.input;
4
5 import static org.junit.Assert.assertFalse;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.fail;
8
9 import java.io.IOException;
10 import java.io.StringWriter;
11 import java.net.URL;
12 import java.util.Iterator;
13 import java.util.List;
14
15 import org.junit.Test;
16
17 import org.jdom.Attribute;
18 import org.jdom.Document;
19 import org.jdom.Element;
20 import org.jdom.JDOMException;
21 import org.jdom.Namespace;
22 import org.jdom.input.SAXBuilder;
23 import org.jdom.input.sax.XMLReaders;
24 import org.jdom.output.Format;
25 import org.jdom.output.XMLOutputter2;
26 import org.jdom.test.util.FidoFetch;
27
28
29 /**
30 * @author Rolf Lear
31 *
32 */
33 @SuppressWarnings("javadoc")
34 public class TestSAXComplexSchema {
35
36
37 /**
38 * Test method for {@link org.jdom.input.SAXBuilder#build(java.io.File)}.
39 */
40 @SuppressWarnings("deprecation")
41 @Test
42 public void testBuildFileOldWay() throws IOException {
43 SAXBuilder builder = new SAXBuilder(true);
44 builder.setFeature("http://xml.org/sax/features/namespaces", true);
45 builder.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
46 builder.setFeature("http://apache.org/xml/features/validation/schema", true);
47
48 URL rurl = FidoFetch.getFido().getURL("/xsdcomplex/input.xml");
49
50
51 try {
52 Document doc = builder.build(rurl);
53 XMLOutputter2 out = new XMLOutputter2(Format.getPrettyFormat());
54 StringWriter sw = new StringWriter();
55 out.output(doc, sw);
56 assertTrue(sw.toString().length() > 0);
57 //System.out.println("Document parsed. Content:\n" + xml + "\n");
58
59 Namespace defns = Namespace.getNamespace("http://www.jdom.org/tests/default");
60 Namespace impns = Namespace.getNamespace("http://www.jdom.org/tests/imp");
61
62 Element root = doc.getRootElement();
63 assertTrue(root != null);
64 assertTrue("test".equals(root.getName()));
65 List<Element> kids = root.getChildren("data", defns);
66 for (Iterator<Element> it = kids.iterator(); it.hasNext(); ) {
67 Element data = it.next();
68 assertTrue(defns.equals(data.getNamespace()));
69 Attribute att = data.getAttribute("type", Namespace.NO_NAMESPACE);
70 assertTrue("Could not find type attribute in default ns.", att != null);
71 att = data.getAttribute("type", impns);
72 assertTrue("Could not find type attribute in impns.", att != null);
73 }
74 } catch (JDOMException e) {
75 e.printStackTrace();
76 fail("Parsing failed. See stack trace.");
77 }
78
79 }
80
81 /**
82 * Test method for {@link org.jdom.input.SAXBuilder#build(java.io.File)}.
83 */
84 @Test
85 public void testBuildFileNewSAX() throws IOException {
86 SAXBuilder builder = new SAXBuilder(XMLReaders.XSDVALIDATING);
87
88 URL rurl = FidoFetch.getFido().getURL("/xsdcomplex/input.xml");
89
90
91 try {
92 Document doc = builder.build(rurl);
93 XMLOutputter2 out = new XMLOutputter2(Format.getPrettyFormat());
94 StringWriter sw = new StringWriter();
95 out.output(doc, sw);
96 assertTrue(sw.toString().length() > 0);
97 //System.out.println("Document parsed. Content:\n" + xml + "\n");
98
99 Namespace defns = Namespace.getNamespace("http://www.jdom.org/tests/default");
100 Namespace impns = Namespace.getNamespace("http://www.jdom.org/tests/imp");
101
102 Element root = doc.getRootElement();
103 assertTrue(root != null);
104 assertTrue("test".equals(root.getName()));
105 List<Element> kids = root.getChildren("data", defns);
106 for (Iterator<Element> it = kids.iterator(); it.hasNext(); ) {
107 Element data = it.next();
108 assertTrue(defns.equals(data.getNamespace()));
109 Attribute att = data.getAttribute("type", Namespace.NO_NAMESPACE);
110 assertTrue("Could not find type attribute in default ns.", att != null);
111 assertTrue(att.isSpecified());
112 att = data.getAttribute("type", impns);
113 assertTrue("Could not find type attribute in impns.", att != null);
114 assertFalse(att.isSpecified());
115 }
116 } catch (JDOMException e) {
117 e.printStackTrace();
118 fail("Parsing failed. See stack trace.");
119 }
120
121 }
122
123 }
0 package org.jdom.test.cases.input;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertNull;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.fail;
8
9 import java.util.NoSuchElementException;
10
11 import javax.xml.XMLConstants;
12
13 import org.junit.Test;
14 import org.xml.sax.SAXException;
15 import org.xml.sax.ext.Attributes2;
16 import org.xml.sax.helpers.LocatorImpl;
17
18 import org.jdom.Attribute;
19 import org.jdom.AttributeType;
20 import org.jdom.CDATA;
21 import org.jdom.Comment;
22 import org.jdom.DefaultJDOMFactory;
23 import org.jdom.DocType;
24 import org.jdom.Document;
25 import org.jdom.Element;
26 import org.jdom.EntityRef;
27 import org.jdom.JDOMFactory;
28 import org.jdom.Namespace;
29 import org.jdom.ProcessingInstruction;
30 import org.jdom.filter.ContentFilter;
31 import org.jdom.input.sax.SAXHandler;
32
33 @SuppressWarnings("javadoc")
34 public class TestSAXHandler {
35
36 private static final class AttributesSingleOnly implements Attributes2 {
37
38 private final String uri, localName, qName, type, value;
39
40 public AttributesSingleOnly(String uri, String localName, String qName, String type, String value) {
41 this.uri = uri;
42 this.localName = localName;
43 this.qName = qName;
44 this.type = type;
45 this.value = value;
46 }
47
48 private final boolean areEquals(Object a, Object b) {
49 if (a == null && b == null) {
50 return true;
51 }
52 if (a != null) {
53 return a.equals(b);
54 }
55 return false;
56 }
57
58 @Override
59 public int getIndex(String puri, String plocalName) {
60 return areEquals(uri, puri) && areEquals(localName, plocalName) ?
61 0 : -1;
62 }
63
64 @Override
65 public int getIndex(String pqName) {
66 return areEquals(qName, pqName) ? 0 : -1;
67 }
68
69 @Override
70 public int getLength() {
71 return 1;
72 }
73
74 @Override
75 public String getLocalName(int index) {
76 if (index == 0) {
77 return localName;
78 }
79 throw new NoSuchElementException();
80 }
81
82 @Override
83 public String getQName(int index) {
84 if (index == 0) {
85 return qName;
86 }
87 throw new NoSuchElementException();
88 }
89
90 @Override
91 public String getType(int index) {
92 if (index == 0) {
93 return type;
94 }
95 throw new NoSuchElementException();
96 }
97
98 @Override
99 public String getType(String puri, String plocalName) {
100 return getType(getIndex(puri, plocalName));
101 }
102
103 @Override
104 public String getType(String pqName) {
105 return getType(getIndex(pqName));
106 }
107
108 @Override
109 public String getURI(int index) {
110 if (index == 0) {
111 return uri;
112 }
113 throw new NoSuchElementException();
114 }
115
116 @Override
117 public String getValue(int index) {
118 if (index == 0) {
119 return value;
120 }
121 throw new NoSuchElementException();
122 }
123
124 @Override
125 public String getValue(String puri, String plocalName) {
126 return getValue(getIndex(puri, plocalName));
127 }
128
129 @Override
130 public String getValue(String pqName) {
131 return getType(getIndex(pqName));
132 }
133
134 @Override
135 public boolean isDeclared(int index) {
136 if (index == 0) {
137 return true;
138 }
139 throw new NoSuchElementException();
140 }
141
142 @Override
143 public boolean isDeclared(String puri, String plocalName) {
144 return isDeclared(getIndex(puri, plocalName));
145 }
146
147 @Override
148 public boolean isDeclared(String pqName) {
149 return isDeclared(getIndex(pqName));
150 }
151
152 @Override
153 public boolean isSpecified(int index) {
154 if (index == 0) {
155 return true;
156 }
157 throw new NoSuchElementException();
158 }
159
160 @Override
161 public boolean isSpecified(String puri, String plocalName) {
162 return isSpecified(getIndex(puri, plocalName));
163 }
164
165 @Override
166 public boolean isSpecified(String pqName) {
167 return isSpecified(getIndex(pqName));
168 }
169
170 }
171
172 private class MyHandler extends SAXHandler {
173 private MyHandler () {
174 super();
175 }
176 @Override
177 public void pushElement(Element element) {
178 super.pushElement(element);
179 }
180 }
181
182 private static final Attributes2 EMPTYATTRIBUTES = new org.xml.sax.ext.Attributes2Impl();
183
184 private static final void assertMatches(String pattern, String value) {
185 assertTrue("Pattern for assertMatches is null", pattern != null);
186 assertTrue("Value for assertMatches is null", value != null);
187 if (!value.matches(pattern)) {
188 fail("Value '" + value + "' does not match pattern '" + pattern +".");
189 }
190 }
191
192 private abstract class Builder {
193 public SAXHandler createHandler() {
194 return new SAXHandler();
195 }
196
197 public abstract void build(SAXHandler handler) throws SAXException;
198 }
199
200 private static final Document checkHandlerDocument(Builder cd) {
201 try {
202 SAXHandler handler = cd.createHandler();
203 handler.startDocument();
204 cd.build(handler);
205 handler.endDocument();
206 return handler.getDocument();
207 } catch (SAXException se) {
208 se.printStackTrace();
209 fail("Failed TestSAXHandler with SAXException: " + se.getMessage());
210 }
211 return null;
212
213 }
214
215 private static final Element checkHandlerElement(Builder cd) {
216 try {
217 SAXHandler handler = cd.createHandler();
218 handler.startDocument();
219 handler.startElement("", "root", "root", EMPTYATTRIBUTES);
220 cd.build(handler);
221 handler.endElement("", "root", "root");
222 handler.endDocument();
223 return handler.getDocument().getRootElement();
224 } catch (SAXException se) {
225 se.printStackTrace();
226 fail("Failed TestSAXHandler with SAXException: " + se.getMessage());
227 }
228 return null;
229
230 }
231
232 private static final String checkHandlerDTDInternalSubset(Builder cd) {
233 try {
234 SAXHandler handler = cd.createHandler();
235 handler.startDocument();
236 handler.startDTD("root", "publicID", "systemID");
237 cd.build(handler);
238 handler.endDTD();
239 handler.endDocument();
240 return handler.getDocument().getDocType().getInternalSubset().trim(); //.replaceAll("(^\\s*<\\s*)|(\\s*>\\s*$)", "");
241 } catch (SAXException se) {
242 se.printStackTrace();
243 fail("Failed TestSAXHandler with SAXException: " + se.getMessage());
244 }
245 return null;
246
247 }
248
249 @Test
250 public void testDocument() {
251 Document doc = null;
252
253 doc = checkHandlerDocument(new Builder() {
254 @Override
255 public void build(SAXHandler handler) throws SAXException {
256 // do nothing.
257 }
258 });
259 assertTrue(doc.getDocType() == null);
260 assertFalse(doc.hasRootElement());
261
262 final JDOMFactory deffac = new DefaultJDOMFactory();
263 doc = checkHandlerDocument(new Builder() {
264 @Override
265 public SAXHandler createHandler() {
266 return new SAXHandler(deffac);
267 }
268 @Override
269 public void build(SAXHandler handler) throws SAXException {
270 assertTrue(deffac == handler.getFactory());
271 }
272 });
273 assertTrue(doc.getDocType() == null);
274 assertFalse(doc.hasRootElement());
275
276 doc = checkHandlerDocument(new Builder() {
277 @Override
278 public void build(SAXHandler handler) throws SAXException {
279 handler.startDTD("dtdname", "publicID", "systemID");
280 handler.endDTD();
281 }
282 });
283 assertFalse(doc.hasRootElement());
284 assertTrue(doc.getDocType() != null);
285 assertEquals("dtdname", doc.getDocType().getElementName());
286
287 doc = checkHandlerDocument(new Builder() {
288 @Override
289 public void build(SAXHandler handler) throws SAXException {
290 handler.startDTD("dtdname", "publicID", "systemID");
291 handler.endDTD();
292 handler.comment("comment".toCharArray(), 2, 2);
293 }
294 });
295 assertFalse(doc.hasRootElement());
296 assertTrue(doc.getDocType() != null);
297 assertEquals("dtdname", doc.getDocType().getElementName());
298 assertTrue(doc.getContent(1) instanceof Comment);
299 assertEquals("mm", ((Comment)doc.getContent(1)).getText());
300
301 doc = checkHandlerDocument(new Builder() {
302 @Override
303 public void build(SAXHandler handler) throws SAXException {
304 handler.startDTD("dtdname", "publicID", "systemID");
305 handler.endDTD();
306 handler.comment("comment".toCharArray(), 2, 2);
307 handler.startElement("", "root", "", EMPTYATTRIBUTES);
308 }
309 });
310 assertTrue(doc.hasRootElement());
311 assertTrue(doc.getDocType() != null);
312 assertEquals("dtdname", doc.getDocType().getElementName());
313 assertTrue(doc.getContent(1) instanceof Comment);
314 assertEquals("mm", ((Comment)doc.getContent(1)).getText());
315 assertTrue(doc.getContent(2) instanceof Element);
316 assertEquals("root", ((Element)doc.getContent(2)).getName());
317
318 final LocatorImpl loc = new LocatorImpl();
319 loc.setSystemId("baseURL");
320 final SAXHandler handler = new SAXHandler();
321 handler.setDocumentLocator(loc);
322 doc = checkHandlerDocument(new Builder() {
323 @Override
324 public SAXHandler createHandler() {
325 return handler;
326 }
327 @Override
328 public void build(SAXHandler phandler) throws SAXException {
329 phandler.startDTD("dtdname", "publicID", "systemID");
330 phandler.endDTD();
331 phandler.comment("comment".toCharArray(), 2, 2);
332 phandler.startElement("", "root", "", EMPTYATTRIBUTES);
333 }
334 });
335 assertTrue(doc.hasRootElement());
336 assertTrue(doc.getDocType() != null);
337 assertEquals("dtdname", doc.getDocType().getElementName());
338 assertTrue(doc.getContent(1) instanceof Comment);
339 assertEquals("mm", ((Comment)doc.getContent(1)).getText());
340 assertTrue(doc.getContent(2) instanceof Element);
341 assertEquals("root", ((Element)doc.getContent(2)).getName());
342 assertEquals("baseURL", doc.getBaseURI());
343 assertTrue(loc == handler.getDocumentLocator());
344
345 }
346
347 @Test
348 public void testExpandEntities() {
349 SAXHandler handler = new SAXHandler();
350 assertTrue(handler.getExpandEntities());
351 handler.setExpandEntities(true);
352 assertTrue(handler.getExpandEntities());
353 handler.setExpandEntities(false);
354 assertFalse(handler.getExpandEntities());
355 handler.setExpandEntities(true);
356 assertTrue(handler.getExpandEntities());
357 }
358
359 @Test
360 public void testIgnoringElementContentWhitespace() {
361 SAXHandler handler = new SAXHandler();
362 assertFalse(handler.getIgnoringElementContentWhitespace());
363 handler.setIgnoringElementContentWhitespace(true);
364 assertTrue(handler.getIgnoringElementContentWhitespace());
365 handler.setIgnoringElementContentWhitespace(false);
366 assertFalse(handler.getIgnoringElementContentWhitespace());
367 handler.setIgnoringElementContentWhitespace(true);
368 assertTrue(handler.getIgnoringElementContentWhitespace());
369 }
370
371 @Test
372 public void testIgnoringBoundaryWhitespace() {
373 SAXHandler handler = new SAXHandler();
374 assertFalse(handler.getIgnoringBoundaryWhitespace());
375 handler.setIgnoringBoundaryWhitespace(true);
376 assertTrue(handler.getIgnoringBoundaryWhitespace());
377 handler.setIgnoringBoundaryWhitespace(false);
378 assertFalse(handler.getIgnoringBoundaryWhitespace());
379 handler.setIgnoringBoundaryWhitespace(true);
380 assertTrue(handler.getIgnoringBoundaryWhitespace());
381 }
382
383
384 /* **********************************
385 * LexicalHandler method tests.
386 * **********************************/
387 @Test
388 public void testDTD() {
389 Document doc = checkHandlerDocument(new Builder() {
390 @Override
391 public void build(SAXHandler handler) throws SAXException {
392 handler.startDTD("root", "publicID", "systemID");
393 // bunch of things for use during a DTD.
394 handler.elementDecl("root", "model");
395 handler.attributeDecl("root", "att", "UNKNOWN", "", "");
396 handler.externalEntityDecl("extent", "publicID", "systemID");
397 handler.comment("foo".toCharArray(), 0, 3);
398 handler.internalEntityDecl("intent", "value");
399 handler.endDTD();
400 }
401 });
402
403 assertEquals("root", doc.getDocType().getElementName());
404 assertEquals("publicID", doc.getDocType().getPublicID());
405 assertEquals("systemID", doc.getDocType().getSystemID());
406 }
407
408 @Test
409 public void testEntity() {
410 // with expandEntities set to true, we lose the entity during parsing
411 assertTrue(
412 checkHandlerElement(new Builder() {
413 @Override
414 public SAXHandler createHandler() {
415 SAXHandler handler = new SAXHandler();
416 handler.setExpandEntities(true);
417 return handler;
418 }
419 @Override
420 public void build(SAXHandler handler) throws SAXException {
421 handler.startEntity("entity");
422 handler.endEntity("entity");
423 }
424 }).getContentSize() == 0);
425
426 // with expandEntities set to false, we expect an entity
427 assertMatches(".*&entity;.*",
428 checkHandlerElement(new Builder() {
429 @Override
430 public SAXHandler createHandler() {
431 SAXHandler handler = new SAXHandler();
432 handler.setExpandEntities(false);
433 return handler;
434 }
435 @Override
436 public void build(SAXHandler handler) throws SAXException {
437 handler.startEntity("entity");
438 handler.endEntity("entity");
439 }
440 }).getContent(0).toString());
441
442 // with [dtd] we expect nothing
443 assertTrue(
444 checkHandlerElement(new Builder() {
445 @Override
446 public SAXHandler createHandler() {
447 SAXHandler handler = new SAXHandler();
448 handler.setExpandEntities(false);
449 return handler;
450 }
451 @Override
452 public void build(SAXHandler handler) throws SAXException {
453 handler.startEntity("[dtd]");
454 handler.endEntity("[dtd]");
455 }
456 }).getContentSize() == 0);
457
458 // 5 standard entities should be ignored.
459 assertTrue(
460 checkHandlerElement(new Builder() {
461 @Override
462 public SAXHandler createHandler() {
463 SAXHandler handler = new SAXHandler();
464 handler.setExpandEntities(false);
465 return handler;
466 }
467 @Override
468 public void build(SAXHandler handler) throws SAXException {
469 handler.startEntity("amp");
470 handler.endEntity("amp");
471
472 handler.startEntity("apos");
473 handler.endEntity("apos");
474
475 handler.startEntity("quot");
476 handler.endEntity("quot");
477
478 handler.startEntity("gt");
479 handler.endEntity("gt");
480
481 handler.startEntity("lt");
482 handler.endEntity("lt");
483 }
484 }).getContentSize() == 0);
485
486 // with expandEntities set to false, we expect an entity
487 EntityRef ent = (EntityRef)checkHandlerElement(new Builder() {
488 @Override
489 public SAXHandler createHandler() {
490 SAXHandler handler = new SAXHandler();
491 handler.setExpandEntities(false);
492 return handler;
493 }
494 @Override
495 public void build(SAXHandler handler) throws SAXException {
496 handler.externalEntityDecl("entity", "publicID", "systemID");
497 handler.startEntity("entity");
498 handler.endEntity("entity");
499 }
500 }).getContent(0);
501 assertEquals("entity", ent.getName());
502 assertEquals("publicID", ent.getPublicID());
503 assertEquals("systemID", ent.getSystemID());
504
505 // when processing an entity, we should ignore all other event types.
506 Element emt = checkHandlerElement(new Builder() {
507 @Override
508 public SAXHandler createHandler() {
509 SAXHandler handler = new SAXHandler();
510 handler.setExpandEntities(false);
511 return handler;
512 }
513 @Override
514 public void build(SAXHandler handler) throws SAXException {
515 handler.startEntity("entity");
516 handler.startPrefixMapping("prefix", "uri");
517 handler.startElement("", "ignore", "", EMPTYATTRIBUTES);
518 handler.endElement("", "ignore", "");
519 handler.endPrefixMapping("prefix");
520 handler.processingInstruction("target", "data");
521 handler.comment("ignore".toCharArray(), 0, 6);
522 handler.characters("ignore".toCharArray(), 0, 6);
523 handler.characters("ignore".toCharArray(), 0, 0);
524 handler.ignorableWhitespace(" ".toCharArray(), 0, 2);
525 handler.startCDATA();
526 handler.characters("ignore".toCharArray(), 0, 6);
527 handler.endCDATA();
528 handler.endEntity("entity");
529 }
530 });
531 // everything should have been ignored because of the startEntity()
532 // which just leaves the actual entity itself.
533 assertTrue(emt.getContentSize() == 1);
534 assertTrue(emt.getContent(0) instanceof EntityRef);
535 EntityRef ent2 = (EntityRef)emt.getContent(0);
536 assertEquals("entity", ent2.getName());
537
538 // when processing an entity, we should ignore all other event types.
539 Element emt2 = checkHandlerElement(new Builder() {
540 @Override
541 public SAXHandler createHandler() {
542 SAXHandler handler = new SAXHandler();
543 handler.setExpandEntities(false);
544 return handler;
545 }
546 @Override
547 public void build(SAXHandler handler) throws SAXException {
548 handler.startEntity("entity");
549 // nested should be ignored.
550 handler.startEntity("nested");
551 handler.endEntity("nested");
552 handler.endEntity("entity");
553 }
554 });
555 // everything should have been ignored because of the startEntity()
556 // which just leaves the actual entity itself.
557 assertTrue(emt2.getContentSize() == 1);
558 assertTrue(emt2.getContent(0) instanceof EntityRef);
559 EntityRef ent3 = (EntityRef)emt2.getContent(0);
560 assertEquals("entity", ent3.getName());
561
562 // when outside the roo element should be ignored...
563 Document doc = checkHandlerDocument(new Builder() {
564 @Override
565 public SAXHandler createHandler() {
566 SAXHandler handler = new SAXHandler();
567 handler.setExpandEntities(false);
568 return handler;
569 }
570 @Override
571 public void build(SAXHandler handler) throws SAXException {
572 handler.startEntity("entity");
573 handler.endEntity("entity");
574 }
575 });
576 // everything should have been ignored because of the startEntity()
577 // which just leaves the actual entity itself.
578 assertTrue(doc.getContentSize() == 0);
579
580 }
581
582 @Test
583 public void testCDATA() {
584 Element emt = checkHandlerElement(new Builder() {
585 @Override
586 public void build(SAXHandler handler) throws SAXException {
587 handler.comment("foo".toCharArray(), 0, 3);
588 handler.characters(" ".toCharArray(), 0, 2);
589 handler.startCDATA();
590 handler.characters(" foobar ".toCharArray(), 0, 10);
591 handler.endCDATA();
592 handler.characters(" ".toCharArray(), 0, 2);
593 }
594 });
595
596 assertEquals("foobar", emt.getTextTrim());
597 assertEquals(" foobar ", ((CDATA)emt.getContent(new ContentFilter(ContentFilter.CDATA)).get(0)).getText());
598
599 }
600
601 @Test
602 public void testComment() {
603 Element emt = checkHandlerElement(new Builder() {
604 @Override
605 public void build(SAXHandler handler) throws SAXException {
606 handler.comment("foo".toCharArray(), 0, 3);
607 handler.characters(" ".toCharArray(), 0, 2);
608 handler.startCDATA();
609 handler.characters(" foobar ".toCharArray(), 0, 10);
610 handler.endCDATA();
611 handler.characters(" ".toCharArray(), 0, 2);
612 handler.comment("bar".toCharArray(), 0, 3);
613 }
614 });
615
616 int cnt = 0;
617 for (Object o : emt.getContent(new ContentFilter(ContentFilter.COMMENT))) {
618 assertTrue(o instanceof Comment);
619 switch (cnt++) {
620 case 0 :
621 assertEquals("foo", ((Comment)o).getText());
622 break;
623 case 1 :
624 assertEquals("bar", ((Comment)o).getText());
625 break;
626 default :
627 fail("Expecting only two comments");
628
629 }
630 }
631
632 assertMatches("\\s*<!--\\s*comment\\s*-->\\s*",
633 checkHandlerDTDInternalSubset(new Builder() {
634 @Override
635 public SAXHandler createHandler() {
636 SAXHandler handler = new SAXHandler();
637 handler.setExpandEntities(false);
638 return handler;
639 }
640 @Override
641 public void build(SAXHandler handler) throws SAXException {
642 handler.startEntity("[dtd]");
643 handler.unparsedEntityDecl("name", null, "systemID", "notationName");
644 handler.endEntity("[dtd]");
645 handler.comment("comment".toCharArray(), 0, 7);
646 }
647 }));
648
649 }
650
651
652
653 /* **********************************
654 * DeclHandler method tests These should
655 * all be run between LexicalHandler's
656 * startDTD and endDTD events.
657 * **********************************/
658 @Test
659 public void testAttributeDecl() {
660 assertMatches("<!ATTLIST\\s+root\\s+att\\s*>",
661 checkHandlerDTDInternalSubset(new Builder() {
662 @Override
663 public void build(SAXHandler handler) throws SAXException {
664 handler.attributeDecl("root", "att", "", "", "");
665 }
666 }));
667
668 assertMatches("<!ATTLIST\\s+root\\s+att\\s+default\\s*>",
669 checkHandlerDTDInternalSubset(new Builder() {
670 @Override
671 public void build(SAXHandler handler) throws SAXException {
672 handler.attributeDecl("root", "att", "", "default", "value");
673 }
674 }));
675
676 assertMatches("<!ATTLIST\\s+root\\s+att\\s+\"value\"\\s*>",
677 checkHandlerDTDInternalSubset(new Builder() {
678 @Override
679 public void build(SAXHandler handler) throws SAXException {
680 handler.attributeDecl("root", "att", "", null, "value");
681 }
682 }));
683
684 assertMatches("<!ATTLIST\\s+root\\s+att\\s+type\\s+default\\s*>",
685 checkHandlerDTDInternalSubset(new Builder() {
686 @Override
687 public void build(SAXHandler handler) throws SAXException {
688 handler.attributeDecl("root", "att", "type", "default", "value");
689 }
690 }));
691
692 assertMatches("<!ATTLIST\\s+root\\s+att\\s+type\\s+\"value\"\\s*>",
693 checkHandlerDTDInternalSubset(new Builder() {
694 @Override
695 public void build(SAXHandler handler) throws SAXException {
696 handler.attributeDecl("root", "att", "type", null, "value");
697 }
698 }));
699
700 assertMatches("<!ATTLIST\\s+root\\s+att\\s+type\\s+#FIXED\\s+\"value\"\\s*>",
701 checkHandlerDTDInternalSubset(new Builder() {
702 @Override
703 public void build(SAXHandler handler) throws SAXException {
704 handler.attributeDecl("root", "att", "type", "#FIXED", "value");
705 }
706 }));
707
708 }
709
710 @Test
711 public void testElementDecl() {
712 assertMatches("<!ELEMENT\\s+root\\s+model\\s*>",
713 checkHandlerDTDInternalSubset(new Builder() {
714 @Override
715 public void build(SAXHandler handler) throws SAXException {
716 handler.elementDecl("root", "model");
717 }
718 }));
719 }
720
721 @Test
722 public void testInternalEntityDecl() {
723 assertMatches("<!ENTITY\\s+name\\s+\"value\"\\s*>",
724 checkHandlerDTDInternalSubset(new Builder() {
725 @Override
726 public void build(SAXHandler handler) throws SAXException {
727 handler.internalEntityDecl("name", "value");
728 }
729 }));
730
731 //Parameter Entity Declaration
732 assertMatches("<!ENTITY\\s+%\\s+name\\s+\"value\"\\s*>",
733 checkHandlerDTDInternalSubset(new Builder() {
734 @Override
735 public void build(SAXHandler handler) throws SAXException {
736 handler.internalEntityDecl("%name", "value");
737 }
738 }));
739 }
740
741 @Test
742 public void testExternalEntityDecl() {
743 assertMatches("<!ENTITY\\s+name\\s+PUBLIC\\s+\"publicID\"\\s+\"systemID\"\\s*>",
744 checkHandlerDTDInternalSubset(new Builder() {
745 @Override
746 public void build(SAXHandler handler) throws SAXException {
747 handler.externalEntityDecl("name", "publicID", "systemID");
748 }
749 }));
750
751 assertMatches("<!ENTITY\\s+name\\s+SYSTEM\\s+\"systemID\"\\s*>",
752 checkHandlerDTDInternalSubset(new Builder() {
753 @Override
754 public void build(SAXHandler handler) throws SAXException {
755 handler.externalEntityDecl("name", null, "systemID");
756 }
757 }));
758
759 }
760
761 @Test
762 public void testUnparsedEntityDecl() {
763 assertMatches("<!ENTITY\\s+name\\s+PUBLIC\\s+\"publicID\"\\s+\"systemID\"\\s+NDATA\\s+notationName\\s*>",
764 checkHandlerDTDInternalSubset(new Builder() {
765 @Override
766 public void build(SAXHandler handler) throws SAXException {
767 handler.unparsedEntityDecl("name", "publicID", "systemID", "notationName");
768 }
769 }));
770
771 assertMatches("<!ENTITY\\s+name\\s+SYSTEM\\s+\"systemID\"\\s+NDATA\\s+notationName\\s*>",
772 checkHandlerDTDInternalSubset(new Builder() {
773 @Override
774 public void build(SAXHandler handler) throws SAXException {
775 handler.unparsedEntityDecl("name", null, "systemID", "notationName");
776 }
777 }));
778 assertMatches("\\s*",
779 checkHandlerDTDInternalSubset(new Builder() {
780 @Override
781 public SAXHandler createHandler() {
782 SAXHandler handler = new SAXHandler();
783 handler.setExpandEntities(false);
784 return handler;
785 }
786 @Override
787 public void build(SAXHandler handler) throws SAXException {
788 handler.startEntity("[dtd]");
789 handler.unparsedEntityDecl("name", null, "systemID", "notationName");
790 handler.endEntity("[dtd]");
791 }
792 }));
793 }
794
795 @Test
796 public void testNotationDecl() {
797 assertMatches("<!NOTATION\\s+name\\s+PUBLIC\\s+\"publicID\"\\s+\"systemID\"\\s*>",
798 checkHandlerDTDInternalSubset(new Builder() {
799 @Override
800 public void build(SAXHandler handler) throws SAXException {
801 handler.notationDecl("name", "publicID", "systemID");
802 }
803 }));
804
805 assertMatches("<!NOTATION\\s+name\\s+SYSTEM\\s+\"systemID\"\\s*>",
806 checkHandlerDTDInternalSubset(new Builder() {
807 @Override
808 public void build(SAXHandler handler) throws SAXException {
809 handler.notationDecl("name", null, "systemID");
810 }
811 }));
812
813 assertMatches("<!NOTATION\\s+name\\s+PUBLIC\\s+\"publicID\"\\s*>",
814 checkHandlerDTDInternalSubset(new Builder() {
815 @Override
816 public void build(SAXHandler handler) throws SAXException {
817 handler.notationDecl("name", "publicID", null);
818 }
819 }));
820
821 Document doc = checkHandlerDocument(new Builder() {
822 @Override
823 public SAXHandler createHandler() {
824 SAXHandler handler = new SAXHandler();
825 handler.setExpandEntities(false);
826 return handler;
827 }
828 @Override
829 public void build(SAXHandler handler) throws SAXException {
830 handler.startDTD("name", "publicID", "systemID");
831 handler.startEntity("[dtd]");
832 handler.notationDecl("exdtd", "publicIDA", "systemIDA");
833 handler.endEntity("[dtd]");
834 handler.notationDecl("indtd", "publicIDB", "systemIDB");
835 handler.endDTD();
836 }
837 });
838
839 DocType dt = doc.getDocType();
840 assertTrue(dt != null);
841 assertMatches("<!NOTATION\\s+indtd\\s+PUBLIC\\s+\"publicIDB\"\\s+\"systemIDB\"\\s*>",
842 dt.getInternalSubset().trim());
843 }
844
845 /* **********************************
846 * ContentHandler method tests.
847 * **********************************/
848 @Test
849 public void testProcessingInstruction() {
850 Element emt = checkHandlerElement(new Builder() {
851 @Override
852 public void build(SAXHandler handler) throws SAXException {
853 handler.processingInstruction("target", "data");
854 }
855 });
856 assertTrue(emt.getContentSize() == 1);
857 assertTrue(emt.getContent(0) instanceof ProcessingInstruction);
858 ProcessingInstruction pi = (ProcessingInstruction)emt.getContent(0);
859 assertEquals("target", pi.getTarget());
860 assertEquals("data", pi.getData());
861
862 Document doc = checkHandlerDocument(new Builder() {
863 @Override
864 public void build(SAXHandler handler) throws SAXException {
865 handler.processingInstruction("target", "data");
866 }
867 });
868 assertTrue(doc.getContentSize() == 1);
869 assertTrue(doc.getContent(0) instanceof ProcessingInstruction);
870 pi = (ProcessingInstruction)emt.getContent(0);
871 assertEquals("target", pi.getTarget());
872 assertEquals("data", pi.getData());
873
874 }
875
876 @Test
877 public void testSkippedEntityString() {
878 Element emt = checkHandlerElement(new Builder() {
879 @Override
880 public void build(SAXHandler handler) throws SAXException {
881 // this one should be ignored.
882 handler.skippedEntity("%ignore");
883 // this one should be added.
884 handler.skippedEntity("entity");
885 }
886 });
887 assertTrue(emt.getContentSize() == 1);
888 assertTrue(emt.getContent(0) instanceof EntityRef);
889 EntityRef er = (EntityRef)emt.getContent(0);
890 assertEquals("entity", er.getName());
891 }
892
893 @Test
894 public void testElementSimple() {
895 Element emt = checkHandlerElement(new Builder() {
896 @Override
897 public void build(SAXHandler handler) throws SAXException {
898 handler.startElement("", "child", "", EMPTYATTRIBUTES);
899 handler.endElement("", "child", "");
900 }
901 });
902 assertTrue(emt.getContentSize() == 1);
903 assertTrue(emt.getContent(0) instanceof Element);
904 Element child = (Element)emt.getContent(0);
905 assertEquals("child", child.getName());
906 assertEquals("", child.getNamespacePrefix());
907 assertEquals("", child.getNamespaceURI());
908 }
909
910 @Test
911 public void testElementNullURI() {
912 Element emt = checkHandlerElement(new Builder() {
913 @Override
914 public void build(SAXHandler handler) throws SAXException {
915 handler.startElement(null, "child", "", EMPTYATTRIBUTES);
916 handler.endElement(null, "child", "");
917 }
918 });
919 assertTrue(emt.getContentSize() == 1);
920 assertTrue(emt.getContent(0) instanceof Element);
921 Element child = (Element)emt.getContent(0);
922 assertEquals("child", child.getName());
923 assertEquals("", child.getNamespacePrefix());
924 assertEquals("", child.getNamespaceURI());
925 }
926
927 @Test
928 public void testElementBadEndElement() {
929 try {
930 SAXHandler handler = new SAXHandler();
931 handler.startDocument();
932 handler.startElement("", "root", "root", EMPTYATTRIBUTES);
933 handler.endElement("", "root", "root");
934 handler.endElement("", "bad", "bad");
935 handler.endDocument();
936 fail("Should not have been able to create Element ");
937 } catch (SAXException se) {
938 // good
939 } catch (Exception e) {
940 fail("Expecting SAXEsception, but got " + e.getClass().getName());
941 }
942 }
943
944 @Test
945 public void testElementAttributesSimple() {
946 // simple attribute.
947 final AttributesSingleOnly atts = new AttributesSingleOnly("", "att", "att", "CDATA", "val");
948 Element emt = checkHandlerElement(new Builder() {
949 @Override
950 public void build(SAXHandler handler) throws SAXException {
951 handler.startElement("", "child", "", atts);
952 handler.endElement("", "child", "");
953 }
954 });
955
956 assertTrue(emt.getContentSize() == 1);
957 assertTrue(emt.getContent(0) instanceof Element);
958 Element child = (Element)emt.getContent(0);
959 assertEquals("child", child.getName());
960 assertEquals("", child.getNamespacePrefix());
961 assertEquals("", child.getNamespaceURI());
962 assertTrue(child.getAttributes().size() == 1);
963 assertEquals("val", child.getAttributeValue("att"));
964 assertEquals(AttributeType.CDATA, child.getAttribute("att").getAttributeType());
965 }
966
967 @Test
968 public void testElementAttributesNameXMLNS() {
969 // invalid xmlns attibute.
970 final AttributesSingleOnly atts = new AttributesSingleOnly("", "xmlns", "xmlns", "CDATA", "val");
971 Element emt = checkHandlerElement(new Builder() {
972 @Override
973 public void build(SAXHandler handler) throws SAXException {
974 handler.startElement("", "child", "", atts);
975 handler.endElement("", "child", "");
976 }
977 });
978
979 assertTrue(emt.getContentSize() == 1);
980 assertTrue(emt.getContent(0) instanceof Element);
981 Element child = (Element)emt.getContent(0);
982 assertEquals("child", child.getName());
983 assertEquals("", child.getNamespacePrefix());
984 assertEquals("", child.getNamespaceURI());
985 assertTrue(child.getAttributes().isEmpty());
986 }
987
988 @Test
989 public void testElementAttributesPrefixXMLNS() {
990 // invalid xmlns attibute.
991 final AttributesSingleOnly atts = new AttributesSingleOnly("", "ns", "xmlns:ns", "CDATA", "uri");
992 Element emt = checkHandlerElement(new Builder() {
993 @Override
994 public void build(SAXHandler handler) throws SAXException {
995 handler.startElement("", "child", "", atts);
996 handler.endElement("", "child", "");
997 }
998 });
999
1000 assertTrue(emt.getContentSize() == 1);
1001 assertTrue(emt.getContent(0) instanceof Element);
1002 Element child = (Element)emt.getContent(0);
1003 assertEquals("child", child.getName());
1004 assertEquals("", child.getNamespacePrefix());
1005 assertEquals("", child.getNamespaceURI());
1006 assertTrue(child.getAttributes().size() == 0);
1007 }
1008
1009 @Test
1010 public void testElementAttributesNoLocalName() {
1011 // no-localname, but has qname.
1012 final AttributesSingleOnly atts = new AttributesSingleOnly("", "", "att", "CDATA", "val");
1013 Element emt = checkHandlerElement(new Builder() {
1014 @Override
1015 public void build(SAXHandler handler) throws SAXException {
1016 handler.startElement("", "child", "", atts);
1017 handler.endElement("", "child", "");
1018 }
1019 });
1020
1021 assertTrue(emt.getContentSize() == 1);
1022 assertTrue(emt.getContent(0) instanceof Element);
1023 Element child = (Element)emt.getContent(0);
1024 assertEquals("child", child.getName());
1025 assertEquals("", child.getNamespacePrefix());
1026 assertEquals("", child.getNamespaceURI());
1027 assertTrue(child.getAttributes().size() == 1);
1028 assertEquals("val", child.getAttributeValue("att"));
1029 }
1030
1031
1032 @Test
1033 public void testElementAttributesSimpleInNamespace() {
1034 // normal att-in-namespace.
1035 final AttributesSingleOnly atts = new AttributesSingleOnly("nsuri", "att", "pfx:att", "CDATA", "val");
1036 Element emt = checkHandlerElement(new Builder() {
1037 @Override
1038 public void build(SAXHandler handler) throws SAXException {
1039 handler.startPrefixMapping("pfx", "nsuri");
1040 handler.startElement("", "child", "", atts);
1041 handler.endElement("", "child", "");
1042 handler.endPrefixMapping("pfx");
1043 }
1044 });
1045
1046 assertTrue(emt.getContentSize() == 1);
1047 assertTrue(emt.getContent(0) instanceof Element);
1048 Element child = (Element)emt.getContent(0);
1049 assertEquals("child", child.getName());
1050 assertEquals("", child.getNamespacePrefix());
1051 assertEquals("", child.getNamespaceURI());
1052 assertTrue(child.getAttributes().size() == 1);
1053 assertTrue(child.getAttribute("att") == null);
1054 Namespace ns = Namespace.getNamespace("pfx", "nsuri");
1055 assertTrue(child.getAttribute("att", ns) != null);
1056 assertEquals("val", child.getAttributeValue("att", ns));
1057 }
1058
1059
1060 @Test
1061 public void testElementAttributesNoPrefixNamespaceMustGeneratePrefix() {
1062 // weird att-in-namespace - no prefix.
1063 // namespace of parent element matches, but no prefix.
1064 // should invent a prefix (attns0)
1065 final AttributesSingleOnly atts = new AttributesSingleOnly("nsuri", "att", "att", "CDATA", "val");
1066 Element emt = checkHandlerElement(new Builder() {
1067 @Override
1068 public void build(SAXHandler handler) throws SAXException {
1069 handler.startElement("nsuri", "child", "child", atts);
1070 handler.endElement("nsuri", "child", "child");
1071 }
1072 });
1073
1074 assertTrue(emt.getContentSize() == 1);
1075 assertTrue(emt.getContent(0) instanceof Element);
1076 Element child = (Element)emt.getContent(0);
1077 assertEquals("child", child.getName());
1078 assertEquals("", child.getNamespacePrefix());
1079 assertEquals("nsuri", child.getNamespaceURI());
1080 assertTrue(child.getAttributes().size() == 1);
1081 assertTrue(child.getAttribute("att") == null);
1082 Attribute a = child.getAttribute("att", child.getNamespace());
1083 assertEquals("attns0", a.getNamespacePrefix());
1084 assertEquals("nsuri", a.getNamespaceURI());
1085 assertEquals("val", a.getValue());
1086 }
1087
1088 @Test
1089 public void testElementAttributesNoPrefixNamespaceMustGenerateAlternatePrefix() {
1090 // weird att-in-namespace - no prefix.
1091 // namespace of parent element matches, but no prefix.
1092 // also, attns0 is used by some other namespace.
1093 // should invent a prefix (attns1)
1094 final AttributesSingleOnly atts = new AttributesSingleOnly("nsuri", "att", "att", "CDATA", "val");
1095 Element emt = checkHandlerElement(new Builder() {
1096 @Override
1097 public void build(SAXHandler handler) throws SAXException {
1098 handler.startPrefixMapping("attns0", "otheruri");
1099 handler.startElement("nsuri", "child", "child", atts);
1100 handler.endElement("nsuri", "child", "child");
1101 handler.endPrefixMapping("atns0");
1102 }
1103 });
1104
1105 assertTrue(emt.getContentSize() == 1);
1106 assertTrue(emt.getContent(0) instanceof Element);
1107 Element child = (Element)emt.getContent(0);
1108 assertEquals("child", child.getName());
1109 assertEquals("", child.getNamespacePrefix());
1110 assertEquals("nsuri", child.getNamespaceURI());
1111 assertTrue(child.getAttributes().size() == 1);
1112 assertTrue(child.getAttribute("att") == null);
1113 Attribute a = child.getAttribute("att", child.getNamespace());
1114 assertEquals("attns1", a.getNamespacePrefix());
1115 assertEquals("nsuri", a.getNamespaceURI());
1116 assertEquals("val", a.getValue());
1117 }
1118
1119 @Test
1120 public void testElementAttributesNoPrefixNamespaceMustUseParentLevelPrefix() {
1121 // weird att-in-namespace - no prefix.
1122 // but there is a prefix declared for it at the parent level.
1123 final AttributesSingleOnly atts = new AttributesSingleOnly("nsuri", "att", "att", "CDATA", "val");
1124 Element emt = checkHandlerElement(new Builder() {
1125 @Override
1126 public void build(SAXHandler handler) throws SAXException {
1127 handler.startPrefixMapping("pfx", "nsuri");
1128 handler.startElement("", "child", "", atts);
1129 handler.endElement("", "child", "");
1130 handler.endPrefixMapping("pfx");
1131 }
1132 });
1133
1134 assertTrue(emt.getContentSize() == 1);
1135 assertTrue(emt.getContent(0) instanceof Element);
1136 Element child = (Element)emt.getContent(0);
1137 assertEquals("child", child.getName());
1138 assertEquals("", child.getNamespacePrefix());
1139 assertEquals("", child.getNamespaceURI());
1140 assertTrue(child.getAttributes().size() == 1);
1141 assertTrue(child.getAttribute("att") == null);
1142 Namespace nsd = Namespace.getNamespace("differentprefix", "nsuri");
1143 Attribute a = child.getAttribute("att", nsd);
1144 assertEquals("pfx", a.getNamespacePrefix());
1145 assertEquals("nsuri", a.getNamespaceURI());
1146 assertEquals("val", a.getValue());
1147 }
1148
1149 @Test
1150 public void testElementAttributesNoPrefixNamespaceMustUseActualParentPrefix() {
1151 // weird att-in-namespace - no prefix.
1152 // namespace of parent element matches, it has prefix.
1153 // should use parent prefix (pfx)
1154 final AttributesSingleOnly atts = new AttributesSingleOnly("nsuri", "att", "att", "CDATA", "val");
1155 Element emt = checkHandlerElement(new Builder() {
1156 @Override
1157 public void build(SAXHandler handler) throws SAXException {
1158 handler.startPrefixMapping("attns0", "otheruri");
1159 handler.startElement("nsuri", "child", "pfx:child", atts);
1160 handler.endElement("nsuri", "child", "pfx:child");
1161 handler.endPrefixMapping("atns0");
1162 }
1163 });
1164
1165 assertTrue(emt.getContentSize() == 1);
1166 assertTrue(emt.getContent(0) instanceof Element);
1167 Element child = (Element)emt.getContent(0);
1168 assertEquals("child", child.getName());
1169 assertEquals("pfx", child.getNamespacePrefix());
1170 assertEquals("nsuri", child.getNamespaceURI());
1171 assertTrue(child.getAttributes().size() == 1);
1172 assertTrue(child.getAttribute("att") == null);
1173 Attribute a = child.getAttribute("att", child.getNamespace());
1174 assertEquals("pfx", a.getNamespacePrefix());
1175 assertEquals("nsuri", a.getNamespaceURI());
1176 assertEquals("val", a.getValue());
1177 }
1178
1179
1180 @Test
1181 public void testElementAttributesNoPrefixNamespaceParentPrefixOverrides() {
1182 // weird att-in-namespace - no prefix.
1183 // also, a matching prefix was overridden.
1184 // should generate one (attns0).
1185 final AttributesSingleOnly atts = new AttributesSingleOnly("nsuri", "att", "att", "CDATA", "val");
1186 Element emt = checkHandlerElement(new Builder() {
1187 @Override
1188 public void build(SAXHandler handler) throws SAXException {
1189 handler.startPrefixMapping("pfx", "nsuri");
1190 handler.startElement("nsuri", "middle", "pfx:middle", EMPTYATTRIBUTES);
1191 // re-define the namespace prefix with a different uri
1192 handler.startElement("childuri", "child", "pfx:child", atts);
1193 handler.endElement("childuri", "child", "pfx:child");
1194 handler.endElement("", "middle", "pfx:middle");
1195 handler.endPrefixMapping("pfx");
1196 }
1197 });
1198
1199 assertTrue(emt.getContentSize() == 1);
1200 assertTrue(emt.getContent(0) instanceof Element);
1201 Element middle = (Element)emt.getContent(0);
1202 assertEquals("middle", middle.getName());
1203 assertEquals("pfx", middle.getNamespacePrefix());
1204 assertEquals("nsuri", middle.getNamespaceURI());
1205
1206 Element child = middle.getChild("child", Namespace.getNamespace("childuri"));
1207 assertEquals("child", child.getName());
1208 assertEquals("pfx", child.getNamespacePrefix());
1209 assertEquals("childuri", child.getNamespaceURI());
1210 assertTrue(child.getAttributes().size() == 1);
1211 assertTrue(child.getAttribute("att") == null);
1212 Attribute a = child.getAttribute("att", middle.getNamespace());
1213 assertEquals("attns0", a.getNamespacePrefix());
1214 assertEquals("nsuri", a.getNamespaceURI());
1215 assertEquals("val", a.getValue());
1216 }
1217
1218 @Test
1219 public void testElementAttributesNoPrefixNamespaceParentPrefixLevelOverrides() {
1220 // weird att-in-namespace - no prefix.
1221 // also, a matching prefix at the parent level was overridden.
1222 // should generate one (attns0).
1223 final AttributesSingleOnly atts = new AttributesSingleOnly("nsuri", "att", "att", "CDATA", "val");
1224 Element emt = checkHandlerElement(new Builder() {
1225 @Override
1226 public void build(SAXHandler handler) throws SAXException {
1227 handler.startPrefixMapping("pfx", "nsuri");
1228 handler.startElement("nsuri", "middle", "pfx:middle", EMPTYATTRIBUTES);
1229 // re-define the namespace prefix with a different uri
1230 handler.startPrefixMapping("pfx", "ignoreuri");
1231 handler.startElement("childuri", "child", "kid:child", atts);
1232 handler.endElement("childuri", "child", "kid:child");
1233 handler.endPrefixMapping("pfx");
1234 handler.endElement("", "middle", "pfx:middle");
1235 handler.endPrefixMapping("pfx");
1236 }
1237 });
1238
1239 assertTrue(emt.getContentSize() == 1);
1240 assertTrue(emt.getContent(0) instanceof Element);
1241 Element middle = (Element)emt.getContent(0);
1242 assertEquals("middle", middle.getName());
1243 assertEquals("pfx", middle.getNamespacePrefix());
1244 assertEquals("nsuri", middle.getNamespaceURI());
1245
1246 Element child = middle.getChild("child", Namespace.getNamespace("childuri"));
1247 assertEquals("child", child.getName());
1248 assertEquals("kid", child.getNamespacePrefix());
1249 assertEquals("childuri", child.getNamespaceURI());
1250 assertTrue(child.getAttributes().size() == 1);
1251 assertTrue(child.getAttribute("att") == null);
1252 Attribute a = child.getAttribute("att", middle.getNamespace());
1253 assertEquals("attns0", a.getNamespacePrefix());
1254 assertEquals("nsuri", a.getNamespaceURI());
1255 assertEquals("val", a.getValue());
1256 }
1257
1258
1259 @Test
1260 public void testElementAttributesTypeIsEnumeration() {
1261 // simple attribute.
1262 final AttributesSingleOnly atts = new AttributesSingleOnly("", "att", "att", "(val1,val2)", "val");
1263 Element emt = checkHandlerElement(new Builder() {
1264 @Override
1265 public void build(SAXHandler handler) throws SAXException {
1266 handler.startElement("", "child", "", atts);
1267 handler.endElement("", "child", "");
1268 }
1269 });
1270
1271 assertTrue(emt.getContentSize() == 1);
1272 assertTrue(emt.getContent(0) instanceof Element);
1273 Element child = (Element)emt.getContent(0);
1274 assertEquals("child", child.getName());
1275 assertEquals("", child.getNamespacePrefix());
1276 assertEquals("", child.getNamespaceURI());
1277 assertTrue(child.getAttributes().size() == 1);
1278 assertEquals("val", child.getAttributeValue("att"));
1279 }
1280
1281 @Test
1282 public void testElementAttributesTypeIsUnknown() {
1283 // simple attribute.
1284 final AttributesSingleOnly atts = new AttributesSingleOnly("", "att", "att", "poppygook", "val");
1285 Element emt = checkHandlerElement(new Builder() {
1286 @Override
1287 public void build(SAXHandler handler) throws SAXException {
1288 handler.startElement("", "child", "", atts);
1289 handler.endElement("", "child", "");
1290 }
1291 });
1292
1293 assertTrue(emt.getContentSize() == 1);
1294 assertTrue(emt.getContent(0) instanceof Element);
1295 Element child = (Element)emt.getContent(0);
1296 assertEquals("child", child.getName());
1297 assertEquals("", child.getNamespacePrefix());
1298 assertEquals("", child.getNamespaceURI());
1299 assertTrue(child.getAttributes().size() == 1);
1300 Attribute att = child.getAttribute("att");
1301 assertEquals("val", att.getValue());
1302 assertEquals(AttributeType.UNDECLARED, att.getAttributeType());
1303 }
1304
1305 @Test
1306 public void testElementAttributesTypeIsNull() {
1307 // null attribute type.
1308 final AttributesSingleOnly atts = new AttributesSingleOnly("", "att", "att", null, "val");
1309 Element emt = checkHandlerElement(new Builder() {
1310 @Override
1311 public void build(SAXHandler handler) throws SAXException {
1312 handler.startElement("", "child", "", atts);
1313 handler.endElement("", "child", "");
1314 }
1315 });
1316
1317 assertTrue(emt.getContentSize() == 1);
1318 assertTrue(emt.getContent(0) instanceof Element);
1319 Element child = (Element)emt.getContent(0);
1320 assertEquals("child", child.getName());
1321 assertEquals("", child.getNamespacePrefix());
1322 assertEquals("", child.getNamespaceURI());
1323 assertTrue(child.getAttributes().size() == 1);
1324 Attribute att = child.getAttribute("att");
1325 assertEquals("val", att.getValue());
1326 assertEquals(AttributeType.UNDECLARED, att.getAttributeType());
1327 }
1328
1329
1330 @Test
1331 public void testElementAttributesTypeIsEmptyString() {
1332 // "" attribute type.
1333 final AttributesSingleOnly atts = new AttributesSingleOnly("", "att", "att", "", "val");
1334 Element emt = checkHandlerElement(new Builder() {
1335 @Override
1336 public void build(SAXHandler handler) throws SAXException {
1337 handler.startElement("", "child", "", atts);
1338 handler.endElement("", "child", "");
1339 }
1340 });
1341
1342 assertTrue(emt.getContentSize() == 1);
1343 assertTrue(emt.getContent(0) instanceof Element);
1344 Element child = (Element)emt.getContent(0);
1345 assertEquals("child", child.getName());
1346 assertEquals("", child.getNamespacePrefix());
1347 assertEquals("", child.getNamespaceURI());
1348 assertTrue(child.getAttributes().size() == 1);
1349 Attribute att = child.getAttribute("att");
1350 assertEquals("val", att.getValue());
1351 assertEquals(AttributeType.UNDECLARED, att.getAttributeType());
1352 }
1353
1354
1355 @Test
1356 public void testPrefixMapping() {
1357 Element emt = checkHandlerElement(new Builder() {
1358 @Override
1359 public void build(SAXHandler handler) throws SAXException {
1360 handler.startPrefixMapping("prefix", "uri");
1361 handler.startElement("uri", "child", "prefix:uri", EMPTYATTRIBUTES);
1362 handler.endElement("uri", "child", "prefix:uri");
1363 handler.endPrefixMapping("prefix");
1364 }
1365 });
1366 assertTrue(emt.getContentSize() == 1);
1367 assertTrue(emt.getContent(0) instanceof Element);
1368 Element child = (Element)emt.getContent(0);
1369 assertEquals("child", child.getName());
1370 assertEquals("prefix", child.getNamespacePrefix());
1371 assertEquals("uri", child.getNamespaceURI());
1372 }
1373
1374 @Test
1375 public void testCharacters() {
1376 Element emt = checkHandlerElement(new Builder() {
1377 @Override
1378 public void build(SAXHandler handler) throws SAXException {
1379 handler.comment("foo".toCharArray(), 0, 3);
1380 handler.characters(" ".toCharArray(), 0, 2);
1381 // 0-length should be ignored.
1382 handler.characters("xxxx".toCharArray(), 0, 0);
1383 handler.characters(" foobar ".toCharArray(), 0, 10);
1384 handler.characters(" ".toCharArray(), 0, 2);
1385 }
1386 });
1387
1388 assertEquals(" foobar ", emt.getText());
1389 assertEquals("foobar", emt.getTextTrim());
1390 }
1391
1392 @Test
1393 public void testIgnorableWhitespaceTrue() {
1394 Element emt = checkHandlerElement(new Builder() {
1395 @Override
1396 public SAXHandler createHandler() {
1397 SAXHandler ret = new SAXHandler();
1398 ret.setIgnoringElementContentWhitespace(true);
1399 return ret;
1400 }
1401 @Override
1402 public void build(SAXHandler handler) throws SAXException {
1403 handler.comment("foo".toCharArray(), 0, 3);
1404 // 3 chars, length 2 though.
1405 handler.ignorableWhitespace(" ".toCharArray(), 0, 2);
1406 handler.characters(" foobar ".toCharArray(), 0, 10);
1407 // 0 length
1408 handler.ignorableWhitespace(" ".toCharArray(), 0, 0);
1409 handler.ignorableWhitespace(" ".toCharArray(), 0, 2);
1410 }
1411 });
1412
1413 assertEquals(" foobar ", emt.getText());
1414 assertEquals("foobar", emt.getTextTrim());
1415 }
1416
1417 @Test
1418 public void testIgnorableBoundaryWhitespaceTrue() {
1419 assertEquals("", checkHandlerElement(new Builder() {
1420 @Override
1421 public SAXHandler createHandler() {
1422 SAXHandler ret = new SAXHandler();
1423 ret.setIgnoringBoundaryWhitespace(true);
1424 return ret;
1425 }
1426 @Override
1427 public void build(SAXHandler handler) throws SAXException {
1428 handler.characters(" \n\n ".toCharArray(), 0, 6);
1429 }
1430 }).getText());
1431
1432 assertEquals(" \nx\n ", checkHandlerElement(new Builder() {
1433 @Override
1434 public SAXHandler createHandler() {
1435 SAXHandler ret = new SAXHandler();
1436 ret.setIgnoringBoundaryWhitespace(true);
1437 return ret;
1438 }
1439 @Override
1440 public void build(SAXHandler handler) throws SAXException {
1441 handler.characters(" \nx\n ".toCharArray(), 0, 5);
1442 }
1443 }).getText());
1444
1445 }
1446
1447 @Test
1448 public void testIgnorableWhitespaceFalse() {
1449 Element emt = checkHandlerElement(new Builder() {
1450 @Override
1451 public SAXHandler createHandler() {
1452 SAXHandler ret = new SAXHandler();
1453 ret.setIgnoringElementContentWhitespace(false);
1454 return ret;
1455 }
1456 @Override
1457 public void build(SAXHandler handler) throws SAXException {
1458 handler.comment("foo".toCharArray(), 0, 3);
1459 handler.ignorableWhitespace(" ".toCharArray(), 0, 2);
1460 handler.characters(" foobar ".toCharArray(), 0, 10);
1461 handler.ignorableWhitespace(" ".toCharArray(), 0, 2);
1462 }
1463 });
1464
1465 assertEquals(" foobar ", emt.getText());
1466 assertEquals("foobar", emt.getTextTrim());
1467 }
1468
1469 @Test
1470 public void testPushElement() {
1471 try {
1472 MyHandler handler = new MyHandler();
1473 handler.startDocument();
1474 handler.pushElement(new Element("root"));
1475 handler.endDocument();
1476 Document doc = handler.getDocument();
1477 assertTrue(doc.hasRootElement());
1478 assertEquals("root", doc.getRootElement().getName());
1479 } catch (SAXException se) {
1480 se.printStackTrace();
1481 fail ("Failed to load MyHandler: " + se.getMessage());
1482 }
1483 try {
1484 MyHandler handler = new MyHandler();
1485 handler.startDocument();
1486 handler.startElement("", "root", "root", EMPTYATTRIBUTES);
1487 handler.pushElement(new Element("child"));
1488 handler.endElement("", "root", "root");
1489 handler.endDocument();
1490 Document doc = handler.getDocument();
1491 assertTrue(doc.hasRootElement());
1492 assertEquals("root", doc.getRootElement().getName());
1493 assertTrue(doc.getRootElement().getChild("child") != null);
1494 } catch (SAXException se) {
1495 se.printStackTrace();
1496 fail ("Failed to load MyHandler: " + se.getMessage());
1497 }
1498 }
1499
1500 @Test
1501 public void testIllegalGetCurrentElement() {
1502 SAXHandler handler = new SAXHandler();
1503 handler.startDocument();
1504 try {
1505 handler.getCurrentElement();
1506 fail ("Should not be able to append bad element strcuture.");
1507 } catch (SAXException se) {
1508 // good/.
1509 } catch (Exception e) {
1510 fail("Expected to get SAXException but instead got " + e.getClass().getName() + "'.");
1511 }
1512
1513 }
1514
1515 @Test
1516 public void testAndroidParserIssue2LocalOnly() throws SAXException {
1517 SAXHandler handler = new SAXHandler();
1518 handler.startDocument();
1519 AttributesSingleOnly attrs = new AttributesSingleOnly("", "attname", "", "CDATA", "val");
1520 handler.startElement("", "root", "", attrs);
1521 handler.endElement("", "root", "");
1522 handler.endDocument();
1523 Document doc = handler.getDocument();
1524 Element root = doc.getRootElement();
1525 assertEquals("root", root.getName());
1526 Attribute att = root.getAttribute("attname");
1527 assertNotNull(att);
1528 assertEquals("val", att.getValue());
1529 }
1530
1531 @Test
1532 public void testAndroidParserIssue2QNameOnly() throws SAXException {
1533 SAXHandler handler = new SAXHandler();
1534 handler.startDocument();
1535 AttributesSingleOnly attrs = new AttributesSingleOnly("", "", "attname", "CDATA", "val");
1536 handler.startElement("", "", "root", attrs);
1537 handler.endElement("", "root", "");
1538 handler.endDocument();
1539 Document doc = handler.getDocument();
1540 Element root = doc.getRootElement();
1541 assertEquals("root", root.getName());
1542 Attribute att = root.getAttribute("attname");
1543 assertNotNull(att);
1544 assertEquals("val", att.getValue());
1545 }
1546
1547 @Test
1548 public void testAndroidParserIssue2AttXMLNS() throws SAXException {
1549 // test a namespace-aware parser that is not configured namespace-prefixes
1550 // in theory, it should leave the qName empty, even for an XMLNS declaration
1551 SAXHandler handler = new SAXHandler();
1552 handler.startDocument();
1553 AttributesSingleOnly attrs = new AttributesSingleOnly(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "pfx", "", "CDATA", "nsuri");
1554 handler.startElement("", "", "root", attrs);
1555 handler.endElement("", "root", "");
1556 handler.endDocument();
1557 Document doc = handler.getDocument();
1558 Element root = doc.getRootElement();
1559 assertEquals("root", root.getName());
1560 Attribute att = root.getAttribute("pfx");
1561 assertNull(att);
1562 assertTrue(root.getAttributes().isEmpty());
1563 }
1564
1565 }
0 package org.jdom.test.cases.input;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7
8 import java.io.CharArrayWriter;
9 import java.io.IOException;
10 import java.io.InputStream;
11
12 import javax.xml.stream.XMLEventReader;
13 import javax.xml.stream.XMLInputFactory;
14
15 import org.junit.Ignore;
16 import org.junit.Test;
17
18 import org.jdom.DefaultJDOMFactory;
19 import org.jdom.DocType;
20 import org.jdom.Document;
21 import org.jdom.Element;
22 import org.jdom.input.SAXBuilder;
23 import org.jdom.input.StAXEventBuilder;
24 import org.jdom.output.Format;
25 import org.jdom.output.XMLOutputter2;
26 import org.jdom.test.util.FidoFetch;
27 import org.jdom.test.util.UnitTestUtil;
28
29 @SuppressWarnings("javadoc")
30 public class TestStAXEventBuilder {
31
32 @Test
33 public void testStAXBuilder() {
34 StAXEventBuilder db = new StAXEventBuilder();
35 assertNotNull(db);
36 }
37
38 @Test
39 public void testFactory() {
40 StAXEventBuilder db = new StAXEventBuilder();
41 assertTrue(db.getFactory() instanceof DefaultJDOMFactory);
42 DefaultJDOMFactory fac = new DefaultJDOMFactory();
43 assertFalse(db.getFactory() == fac);
44 db.setFactory(fac);
45 assertTrue(db.getFactory() == fac);
46 }
47
48 @Test
49 public void testSimpleDocumentExpand() {
50 checkStAX("/DOMBuilder/simple.xml", true);
51 }
52
53 @Test
54 public void testAttributesDocumentExpand() {
55 checkStAX("/DOMBuilder/attributes.xml", true);
56 }
57
58 @Test
59 public void testNamespaceDocumentExpand() {
60 checkStAX("/DOMBuilder/namespaces.xml", true);
61 }
62
63 @Test
64 @Ignore
65 // TODO
66 public void testDocTypeDocumentExpand() {
67 checkStAX("/DOMBuilder/doctype.xml", true);
68 }
69
70 @Test
71 public void testDocTypeDocumentSimpleExpand() {
72 checkStAX("/DOMBuilder/doctypesimple.xml", true);
73 }
74
75 @Test
76 public void testComplexDocumentExpand() {
77 checkStAX("/DOMBuilder/complex.xml", true);
78 }
79
80 @Test
81 public void testXSDDocumentExpand() {
82 checkStAX("/xsdcomplex/input.xml", true);
83 }
84
85 @Test
86 public void testSimpleDocument() {
87 checkStAX("/DOMBuilder/simple.xml", false);
88 }
89
90 @Test
91 public void testAttributesDocument() {
92 checkStAX("/DOMBuilder/attributes.xml", false);
93 }
94
95 @Test
96 public void testNamespaceDocument() {
97 checkStAX("/DOMBuilder/namespaces.xml", false);
98 }
99
100 @Test
101 public void testDocTypeDocument() {
102 checkStAX("/DOMBuilder/doctype.xml", false);
103 }
104
105 @Test
106 public void testDocTypeSimpleDocument() {
107 checkStAX("/DOMBuilder/doctypesimple.xml", false);
108 }
109
110 @Test
111 public void testComplexDocument() {
112 checkStAX("/DOMBuilder/complex.xml", false);
113 }
114
115 @Test
116 public void testXSDDocument() {
117 checkStAX("/xsdcomplex/input.xml", false);
118 }
119
120 private void checkStAX(String resourcename, boolean expand) {
121 try {
122 StAXEventBuilder stxb = new StAXEventBuilder();
123 XMLInputFactory inputfac = XMLInputFactory.newInstance();
124 inputfac.setProperty(
125 "javax.xml.stream.isReplacingEntityReferences", Boolean.valueOf(expand));
126 inputfac.setProperty("http://java.sun.com/xml/stream/properties/report-cdata-event", Boolean.TRUE);
127
128 InputStream eventsource = FidoFetch.getFido().getStream(resourcename);
129 XMLEventReader events = inputfac.createXMLEventReader(eventsource);
130 Document eventbuild = stxb.build(events);
131 Element eventroot = eventbuild.hasRootElement() ? eventbuild.getRootElement() : null;
132
133 SAXBuilder sb = new SAXBuilder();
134 sb.setExpandEntities(expand);
135
136 Document saxbuild = sb.build(FidoFetch.getFido().getStream(resourcename));
137 Element saxroot = saxbuild.hasRootElement() ? saxbuild.getRootElement() : null;
138
139 assertEquals("DOC SAX to StAXEvent", toString(saxbuild), toString(eventbuild));
140 assertEquals("ROOT SAX to StAXEvent", toString(saxroot), toString(eventroot));
141
142 } catch (Exception e) {
143 e.printStackTrace();
144 fail("Could not parse resource '" + resourcename + "': " + e.getMessage());
145 }
146 }
147
148 private void normalizeDTD(DocType dt) {
149 if (dt == null) {
150 return;
151 }
152 // do some tricks so that we can compare the results.
153 // these may well break the actual syntax of DTD's but for testing
154 // purposes it is OK.
155 String internalss = dt.getInternalSubset().trim() ;
156 // the spaceing in and around the internal subset is different between
157 // our SAX parse, and the DOM parse.
158 // make all whitespace a single space.
159 internalss = internalss.replaceAll("\\s+", " ");
160 // It seems the DOM parser internally quotes entities with single quote
161 // but our sax parser uses double-quote.
162 // simply replace all " with ' and be done with it.
163 internalss = internalss.replaceAll("\"", "'");
164 dt.setInternalSubset("\n" + internalss + "\n");
165 }
166
167 private String toString(Document doc) {
168 UnitTestUtil.normalizeAttributes(doc.getRootElement());
169 normalizeDTD(doc.getDocType());
170 XMLOutputter2 out = new XMLOutputter2(Format.getPrettyFormat());
171 CharArrayWriter caw = new CharArrayWriter();
172 try {
173 out.output(doc, caw);
174 } catch (IOException e) {
175 e.printStackTrace();
176 return null;
177 }
178 return caw.toString();
179 }
180
181 private String toString(Element emt) {
182 UnitTestUtil.normalizeAttributes(emt);
183 XMLOutputter2 out = new XMLOutputter2(Format.getPrettyFormat());
184 CharArrayWriter caw = new CharArrayWriter();
185 try {
186 out.output(emt, caw);
187 } catch (IOException e) {
188 e.printStackTrace();
189 return null;
190 }
191 return caw.toString();
192 }
193
194 }
0 package org.jdom.test.cases.input;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertTrue;
6
7 import java.io.CharArrayWriter;
8 import java.io.IOException;
9 import java.util.List;
10
11 import javax.xml.stream.XMLInputFactory;
12 import javax.xml.stream.XMLStreamReader;
13
14 import org.junit.Ignore;
15 import org.junit.Test;
16
17 import org.jdom.Content;
18 import org.jdom.DefaultJDOMFactory;
19 import org.jdom.DocType;
20 import org.jdom.Document;
21 import org.jdom.Element;
22 import org.jdom.input.SAXBuilder;
23 import org.jdom.input.StAXStreamBuilder;
24 import org.jdom.input.stax.DefaultStAXFilter;
25 import org.jdom.output.Format;
26 import org.jdom.output.XMLOutputter2;
27 import org.jdom.test.util.FidoFetch;
28 import org.jdom.test.util.UnitTestUtil;
29
30 @SuppressWarnings("javadoc")
31 public class TestStAXStreamBuilder {
32
33 @Test
34 public void testStAXBuilder() {
35 StAXStreamBuilder db = new StAXStreamBuilder();
36 assertNotNull(db);
37 }
38
39 @Test
40 public void testFactory() {
41 StAXStreamBuilder db = new StAXStreamBuilder();
42 assertTrue(db.getFactory() instanceof DefaultJDOMFactory);
43 DefaultJDOMFactory fac = new DefaultJDOMFactory();
44 assertFalse(db.getFactory() == fac);
45 db.setFactory(fac);
46 assertTrue(db.getFactory() == fac);
47 }
48
49 @Test
50 public void testSimpleDocumentExpand() {
51 checkStAX("/DOMBuilder/simple.xml", true);
52 }
53
54 @Test
55 public void testAttributesDocumentExpand() {
56 checkStAX("/DOMBuilder/attributes.xml", true);
57 }
58
59 @Test
60 public void testNamespaceDocumentExpand() {
61 checkStAX("/DOMBuilder/namespaces.xml", true);
62 }
63
64 @Test
65 @Ignore
66 public void testDocTypeDocumentExpand() {
67 checkStAX("/DOMBuilder/doctype.xml", true);
68 }
69
70 @Test
71 @Ignore
72 public void testDocTypeDocumentSimpleExpand() {
73 checkStAX("/DOMBuilder/doctypesimple.xml", true);
74 }
75
76 @Test
77 public void testComplexDocumentExpand() {
78 checkStAX("/DOMBuilder/complex.xml", true);
79 }
80
81 @Test
82 public void testXSDDocumentExpand() {
83 checkStAX("/xsdcomplex/input.xml", true);
84 }
85
86 @Test
87 public void testSimpleDocument() {
88 checkStAX("/DOMBuilder/simple.xml", false);
89 }
90
91 @Test
92 public void testAttributesDocument() {
93 checkStAX("/DOMBuilder/attributes.xml", false);
94 }
95
96 @Test
97 public void testNamespaceDocument() {
98 checkStAX("/DOMBuilder/namespaces.xml", false);
99 }
100
101 @Test
102 public void testDocTypeDocument() {
103 checkStAX("/DOMBuilder/doctype.xml", false);
104 }
105
106 @Test
107 public void testDocTypeSimpleDocument() {
108 checkStAX("/DOMBuilder/doctypesimple.xml", false);
109 }
110
111 @Test
112 public void testComplexDocument() {
113 checkStAX("/DOMBuilder/complex.xml", false);
114 }
115
116 @Test
117 public void testXSDDocument() {
118 checkStAX("/xsdcomplex/input.xml", false);
119 }
120
121 private void checkStAX(String resname, boolean expand) {
122 try {
123 StAXStreamBuilder stxb = new StAXStreamBuilder();
124 XMLInputFactory inputfac = XMLInputFactory.newInstance();
125 inputfac.setProperty(
126 "javax.xml.stream.isReplacingEntityReferences", Boolean.valueOf(expand));
127 inputfac.setProperty("http://java.sun.com/xml/stream/properties/report-cdata-event", Boolean.TRUE);
128 XMLStreamReader reader = inputfac.createXMLStreamReader(FidoFetch.getFido().getStream(resname));
129 Document staxbuild = stxb.build(reader);
130 Element staxroot = staxbuild.hasRootElement() ? staxbuild.getRootElement() : null;
131
132 XMLStreamReader fragreader = inputfac.createXMLStreamReader(FidoFetch.getFido().getStream(resname));
133 List<Content> contentlist = stxb.buildFragments(fragreader, new DefaultStAXFilter());
134 Document fragbuild = new Document();
135 fragbuild.addContent(contentlist);
136 Element fragroot = fragbuild.getRootElement();
137
138 SAXBuilder sb = new SAXBuilder();
139 sb.setExpandEntities(expand);
140
141 Document saxbuild = sb.build(FidoFetch.getFido().getURL(resname));
142 Element saxroot = saxbuild.hasRootElement() ? saxbuild.getRootElement() : null;
143
144 assertEquals("DOC SAX to StAXReader", toString(saxbuild), toString(staxbuild));
145 assertEquals("ROOT SAX to StAXReader", toString(saxroot), toString(staxroot));
146 assertEquals("DOC SAX to StAXReader FragmentList", toString(saxbuild), toString(fragbuild));
147 assertEquals("ROOT SAX to StAXReader FragmentList", toString(saxroot), toString(fragroot));
148
149 } catch (Exception e) {
150 UnitTestUtil.failException("Could not parse file '" + resname + "': " + e.getMessage(), e);
151 }
152 }
153
154 private void normalizeDTD(DocType dt) {
155 if (dt == null) {
156 return;
157 }
158 // do some tricks so that we can compare the results.
159 // these may well break the actual syntax of DTD's but for testing
160 // purposes it is OK.
161 String internalss = dt.getInternalSubset().trim() ;
162 // the spaceing in and around the internal subset is different between
163 // our SAX parse, and the DOM parse.
164 // make all whitespace a single space.
165 internalss = internalss.replaceAll("\\s+", " ");
166 // It seems the DOM parser internally quotes entities with single quote
167 // but our sax parser uses double-quote.
168 // simply replace all " with ' and be done with it.
169 internalss = internalss.replaceAll("\"", "'");
170 dt.setInternalSubset("\n" + internalss + "\n");
171 }
172
173 private String toString(Document doc) {
174 UnitTestUtil.normalizeAttributes(doc.getRootElement());
175 normalizeDTD(doc.getDocType());
176 XMLOutputter2 out = new XMLOutputter2(Format.getPrettyFormat());
177 CharArrayWriter caw = new CharArrayWriter();
178 try {
179 out.output(doc, caw);
180 } catch (IOException e) {
181 e.printStackTrace();
182 return null;
183 }
184 return caw.toString();
185 }
186
187 private String toString(Element emt) {
188 UnitTestUtil.normalizeAttributes(emt);
189 XMLOutputter2 out = new XMLOutputter2(Format.getPrettyFormat());
190 CharArrayWriter caw = new CharArrayWriter();
191 try {
192 out.output(emt, caw);
193 } catch (IOException e) {
194 e.printStackTrace();
195 return null;
196 }
197 return caw.toString();
198 }
199
200 }
0 package org.jdom.test.cases.input.sax;
1
2 import static org.junit.Assert.assertFalse;
3 import static org.junit.Assert.assertNotNull;
4 import static org.junit.Assert.assertTrue;
5
6 import javax.xml.parsers.FactoryConfigurationError;
7
8 import org.junit.Test;
9
10 import org.jdom.JDOMException;
11 import org.jdom.input.sax.XMLReaderJAXPFactory;
12 import org.jdom.test.util.UnitTestUtil;
13
14 @SuppressWarnings("javadoc")
15 public class TestXMLReaderJAXPFactory {
16
17 //org.apache.xerces.jaxp.SAXParserFactoryImpl
18
19 @Test
20 public void testJAXPXMLReaderFactoryDTDVal() throws JDOMException {
21 XMLReaderJAXPFactory readerfac = new XMLReaderJAXPFactory(
22 "org.apache.xerces.jaxp.SAXParserFactoryImpl", null, true);
23 assertTrue(readerfac.isValidating());
24 assertNotNull(readerfac.createXMLReader());
25 }
26
27 @Test
28 public void testJAXPXMLReaderFactory() throws JDOMException {
29 XMLReaderJAXPFactory readerfac = new XMLReaderJAXPFactory(
30 "org.apache.xerces.jaxp.SAXParserFactoryImpl", null, false);
31 assertFalse(readerfac.isValidating());
32 assertNotNull(readerfac.createXMLReader());
33 }
34
35 @Test
36 public void testSchemaXMLReaderFactoryNull() {
37 try {
38 assertTrue(null != new XMLReaderJAXPFactory(
39 null, null, false));
40 UnitTestUtil.failNoException(FactoryConfigurationError.class);
41 } catch (Throwable e) {
42 UnitTestUtil.checkException(FactoryConfigurationError.class, e);
43 }
44 }
45
46 }
0 package org.jdom.test.cases.input.sax;
1
2 import static org.junit.Assert.*;
3
4 import java.io.IOException;
5
6 import org.junit.Test;
7 import org.xml.sax.SAXException;
8
9 import org.jdom.Document;
10 import org.jdom.JDOMException;
11 import org.jdom.input.SAXBuilder;
12 import org.jdom.input.sax.XMLReaderSAX2Factory;
13 import org.jdom.test.util.FidoFetch;
14 import org.jdom.test.util.UnitTestUtil;
15
16 @SuppressWarnings("javadoc")
17 public class TestXMLReaderSAX2Factory {
18
19 @Test
20 public void testSAX2XMLReaderFactoryBoolean() throws JDOMException {
21 XMLReaderSAX2Factory facval = new XMLReaderSAX2Factory(true);
22 assertTrue(facval.isValidating());
23 assertTrue(facval.createXMLReader() != null);
24 XMLReaderSAX2Factory facnon = new XMLReaderSAX2Factory(false);
25 assertFalse(facnon.isValidating());
26 assertTrue(facnon.createXMLReader() != null);
27 }
28
29 @Test
30 public void testSAX2XMLReaderFactoryBooleanString() throws JDOMException {
31 XMLReaderSAX2Factory facval = new XMLReaderSAX2Factory(true, null);
32 assertTrue(facval.isValidating());
33 assertTrue(facval.createXMLReader() != null);
34
35 facval = new XMLReaderSAX2Factory(true,
36 "com.sun.org.apache.xerces.internal.parsers.SAXParser");
37 assertTrue(facval.isValidating());
38 assertTrue(facval.createXMLReader() != null);
39
40 XMLReaderSAX2Factory facnon = new XMLReaderSAX2Factory(false, null);
41 assertFalse(facnon.isValidating());
42 assertTrue(facnon.createXMLReader() != null);
43
44 facnon = new XMLReaderSAX2Factory(false,
45 "com.sun.org.apache.xerces.internal.parsers.SAXParser");
46 assertFalse(facnon.isValidating());
47 assertTrue(facnon.createXMLReader() != null);
48 }
49
50 @Test
51 public void testGetDriverClassName() {
52 XMLReaderSAX2Factory facnon = new XMLReaderSAX2Factory(false,
53 "com.sun.org.apache.xerces.internal.parsers.SAXParser");
54 assertFalse(facnon.isValidating());
55 assertEquals("com.sun.org.apache.xerces.internal.parsers.SAXParser",
56 facnon.getDriverClassName());
57 }
58
59 @Test
60 public void testGetDummyDriver() {
61 XMLReaderSAX2Factory facnon = new XMLReaderSAX2Factory(false,
62 "does.not.exist");
63 assertFalse(facnon.isValidating());
64 try {
65 facnon.createXMLReader();
66 UnitTestUtil.failNoException(JDOMException.class);
67 } catch (Exception e) {
68 UnitTestUtil.checkException(JDOMException.class, e);
69 UnitTestUtil.checkException(SAXException.class, e.getCause());
70 }
71 }
72
73
74 @Test
75 public void testParseValidateWorks() throws JDOMException, IOException {
76 XMLReaderSAX2Factory fac = new XMLReaderSAX2Factory(true);
77 assertTrue(fac.isValidating());
78 SAXBuilder builder = new SAXBuilder(fac);
79 Document doc = builder.build(FidoFetch.getFido().getURL("/DOMBuilder/doctype.xml"));
80 assertEquals("root", doc.getRootElement().getName());
81 }
82
83 @Test
84 public void testParseValidateFails() {
85 XMLReaderSAX2Factory fac = new XMLReaderSAX2Factory(true);
86 assertTrue(fac.isValidating());
87 SAXBuilder builder = new SAXBuilder(fac);
88 try {
89 builder.build(FidoFetch.getFido().getURL("/DOMBuilder/attributes.xml"));
90 UnitTestUtil.failNoException(JDOMException.class);
91 } catch (Exception e) {
92 UnitTestUtil.checkException(JDOMException.class, e);
93 }
94 }
95
96 @Test
97 public void testParseNonValidateWorks() throws JDOMException, IOException {
98 XMLReaderSAX2Factory fac = new XMLReaderSAX2Factory(false);
99 assertFalse(fac.isValidating());
100 SAXBuilder builder = new SAXBuilder(fac);
101 Document doc = builder.build(FidoFetch.getFido().getURL("/DOMBuilder/attributes.xml"));
102 assertEquals("root", doc.getRootElement().getName());
103 }
104
105
106 }
0 package org.jdom.test.cases.input.sax;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertNotNull;
4 import static org.junit.Assert.assertTrue;
5
6 import java.io.IOException;
7
8 import javax.xml.XMLConstants;
9 import javax.xml.parsers.FactoryConfigurationError;
10 import javax.xml.validation.Schema;
11 import javax.xml.validation.SchemaFactory;
12
13 import org.junit.Test;
14 import org.xml.sax.SAXException;
15
16 import org.jdom.Document;
17 import org.jdom.Element;
18 import org.jdom.JDOMException;
19 import org.jdom.Namespace;
20 import org.jdom.input.SAXBuilder;
21 import org.jdom.input.sax.XMLReaderSchemaFactory;
22 import org.jdom.test.util.FidoFetch;
23 import org.jdom.test.util.UnitTestUtil;
24
25 @SuppressWarnings("javadoc")
26 public class TestXMLReaderSchemaFactory {
27
28 //org.apache.xerces.jaxp.SAXParserFactoryImpl
29
30 @Test
31 public void testSchemaXMLReaderFactory() throws SAXException, JDOMException {
32 SchemaFactory schemafac =
33 SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
34 Schema schema = schemafac.newSchema(FidoFetch.getFido().getURL("/xsdcomplex/SAXTestComplexMain.xsd"));
35 XMLReaderSchemaFactory readerfac = new XMLReaderSchemaFactory(schema);
36 assertTrue(readerfac.isValidating());
37 assertNotNull(readerfac.createXMLReader());
38 }
39
40 @Test
41 public void testSchemaXMLReaderFactoryXerces() throws SAXException, JDOMException {
42 SchemaFactory schemafac =
43 SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
44 Schema schema = schemafac.newSchema(FidoFetch.getFido().getURL("/xsdcomplex/SAXTestComplexMain.xsd"));
45 XMLReaderSchemaFactory readerfac = new XMLReaderSchemaFactory(
46 "org.apache.xerces.jaxp.SAXParserFactoryImpl", null, schema);
47 assertTrue(readerfac.isValidating());
48 assertNotNull(readerfac.createXMLReader());
49 }
50
51 @Test
52 public void testSchemaXMLReaderFactoryNull() {
53 try {
54 new XMLReaderSchemaFactory(null);
55 UnitTestUtil.failNoException(NullPointerException.class);
56 } catch (Exception e) {
57 UnitTestUtil.checkException(NullPointerException.class, e);
58 }
59 }
60
61 @Test
62 public void testSchemaXMLReaderFactoryNullFactory() {
63 try {
64 new XMLReaderSchemaFactory(null, null, null);
65 UnitTestUtil.failNoException(FactoryConfigurationError.class);
66 } catch (Throwable e) {
67 UnitTestUtil.checkException(FactoryConfigurationError.class, e);
68 }
69 }
70
71 @Test
72 public void testParseValidateWorks() throws JDOMException, IOException, SAXException {
73 SchemaFactory schemafac =
74 SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
75 Schema schema = schemafac.newSchema(FidoFetch.getFido().getURL("/xsdcomplex/SAXTestComplexMain.xsd"));
76 XMLReaderSchemaFactory readerfac = new XMLReaderSchemaFactory(schema);
77 assertTrue(readerfac.isValidating());
78 SAXBuilder builder = new SAXBuilder(readerfac);
79 Document doc = builder.build(FidoFetch.getFido().getURL("/xsdcomplex/input.xml"));
80 assertEquals("test", doc.getRootElement().getName());
81 // the whole point of this particular XML input is that it should apply
82 // default attribute values.... lets make sure they make it.
83 int count = 4;
84 for (Element data : doc.getRootElement().getChildren("data", Namespace.getNamespace("http://www.jdom.org/tests/default"))) {
85 count--;
86 assertEquals("simple", data.getAttributeValue("type", Namespace.getNamespace("http://www.jdom.org/tests/imp")));
87 }
88 assertTrue("" + count + " left", count == 0);
89 }
90
91
92 }
0 package org.jdom.test.cases.input.sax;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertTrue;
5
6 import java.io.IOException;
7
8 import org.junit.Test;
9
10 import org.jdom.Document;
11 import org.jdom.Element;
12 import org.jdom.JDOMException;
13 import org.jdom.Namespace;
14 import org.jdom.input.SAXBuilder;
15 import org.jdom.input.sax.XMLReaders;
16 import org.jdom.test.util.FidoFetch;
17 import org.jdom.test.util.UnitTestUtil;
18
19 @SuppressWarnings("javadoc")
20 public class TestXMLReaderSingletons {
21
22 @Test
23 public void testNonValidatingReader() throws JDOMException, IOException {
24 SAXBuilder builder = new SAXBuilder(XMLReaders.NONVALIDATING);
25 assertFalse(builder.isValidating());
26 Document doc = builder.build(FidoFetch.getFido().getURL("/DOMBuilder/attributes.xml"));
27 assertEquals("root", doc.getRootElement().getName());
28 }
29
30 @Test
31 public void testDTDValidatingReader() throws JDOMException, IOException {
32 SAXBuilder builder = new SAXBuilder(XMLReaders.DTDVALIDATING);
33 assertTrue(builder.isValidating());
34 Document doc = builder.build(FidoFetch.getFido().getURL("/DOMBuilder/doctype.xml"));
35 assertEquals("root", doc.getRootElement().getName());
36 }
37
38 @Test
39 public void testDTDValidatingReaderFails() {
40 SAXBuilder builder = new SAXBuilder(XMLReaders.DTDVALIDATING);
41 assertTrue(builder.isValidating());
42 try {
43 builder.build(FidoFetch.getFido().getURL("/DOMBuilder/attributes.xml"));
44 UnitTestUtil.failNoException(JDOMException.class);
45 } catch (Exception e) {
46 UnitTestUtil.checkException(JDOMException.class, e);
47 }
48 }
49
50 @Test
51 public void testXSDValidatingReader() throws JDOMException, IOException {
52 SAXBuilder builder = new SAXBuilder(XMLReaders.XSDVALIDATING);
53 assertTrue(builder.isValidating());
54 Document doc = builder.build(FidoFetch.getFido().getURL("/xsdcomplex/input.xml"));
55 assertEquals("test", doc.getRootElement().getName());
56 // the whole point of this particular XML input is that it should apply
57 // default attribute values.... lets make sure they make it.
58 int count = 4;
59 for (Element data : doc.getRootElement().getChildren("data", Namespace.getNamespace("http://www.jdom.org/tests/default"))) {
60 count--;
61 assertEquals("simple", data.getAttributeValue("type", Namespace.getNamespace("http://www.jdom.org/tests/imp")));
62 }
63 assertTrue("" + count + " left", count == 0);
64 }
65
66 @Test
67 public void testXSDValidatingReaderFails() {
68 SAXBuilder builder = new SAXBuilder(XMLReaders.XSDVALIDATING);
69 assertTrue(builder.isValidating());
70 try {
71 builder.build(FidoFetch.getFido().getURL("/DOMBuilder/attributes.xml"));
72 UnitTestUtil.failNoException(JDOMException.class);
73 } catch (Exception e) {
74 UnitTestUtil.checkException(JDOMException.class, e);
75 }
76 }
77
78 }
0 package org.jdom.test.cases.input.sax;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertTrue;
4
5 import java.io.File;
6 import java.io.IOException;
7 import java.net.URL;
8
9 import javax.xml.transform.Source;
10 import javax.xml.transform.stream.StreamSource;
11
12 import org.junit.Test;
13
14 import org.jdom.Document;
15 import org.jdom.Element;
16 import org.jdom.JDOMException;
17 import org.jdom.Namespace;
18 import org.jdom.input.SAXBuilder;
19 import org.jdom.input.sax.XMLReaderJDOMFactory;
20 import org.jdom.input.sax.XMLReaderXSDFactory;
21 import org.jdom.test.util.FidoFetch;
22 import org.jdom.test.util.UnitTestUtil;
23
24 @SuppressWarnings("javadoc")
25 public class TestXMLReaderXSDFactory {
26 //"./test/resources/xscomplex/multi_one.xsd",
27
28 private final URL filemain() {
29 return FidoFetch.getFido().getURL("/xsdcomplex/multi_main.xsd");
30 }
31 private final URL fileone() {
32 return FidoFetch.getFido().getURL("/xsdcomplex/multi_one.xsd");
33 }
34
35 private final URL filetwo() {
36 return FidoFetch.getFido().getURL("/xsdcomplex/multi_two.xsd");
37 }
38 private final URL source() {
39 return FidoFetch.getFido().getURL("/xsdcomplex/multi.xml");
40 }
41
42 private void checkXML(XMLReaderJDOMFactory fac) {
43 SAXBuilder builder = new SAXBuilder(fac);
44 try {
45 Namespace nsmain = Namespace.getNamespace("http://www.jdom.org/schema_main");
46 Namespace nsone = Namespace.getNamespace("http://www.jdom.org/schema_one");
47 Namespace nstwo = Namespace.getNamespace("http://www.jdom.org/schema_two");
48
49 Document doc = builder.build(source());
50 assertTrue(doc.hasRootElement());
51 Element root = doc.getRootElement();
52 assertTrue(nsmain == root.getNamespace());
53 Element childone = root.getChild("child", nsone);
54 Element childtwo = root.getChild("child", nstwo);
55 assertTrue(childone != null);
56 assertTrue(childtwo != null);
57
58 assertEquals("valueone", childone.getAttributeValue("attribute"));
59 assertEquals("valuetwo", childtwo.getAttributeValue("attribute"));
60 assertEquals("schema_one", childone.getAttributeValue("source"));
61 assertEquals("schema_two", childtwo.getAttributeValue("source"));
62 } catch (Exception e) {
63 UnitTestUtil.failException("Not expecting an exception", e);
64 }
65
66 }
67
68 @Test
69 public void testXMLReaderXSDFactoryStringArray() throws JDOMException {
70 XMLReaderJDOMFactory fac = new XMLReaderXSDFactory(
71 filemain().toExternalForm(),
72 fileone().toExternalForm(),
73 filetwo().toExternalForm());
74 checkXML(fac);
75 }
76
77 @Test
78 public void testXMLReaderXSDFactoryStringArrayJAXP() throws JDOMException {
79 XMLReaderJDOMFactory fac = new XMLReaderXSDFactory(
80 "org.apache.xerces.jaxp.SAXParserFactoryImpl", (ClassLoader)null,
81 filemain().toExternalForm(),
82 fileone().toExternalForm(),
83 filetwo().toExternalForm());
84 checkXML(fac);
85 }
86
87 @Test
88 public void testXMLReaderXSDFactoryURLArray() throws JDOMException {
89 XMLReaderJDOMFactory fac = new XMLReaderXSDFactory(
90 filemain(),
91 fileone(),
92 filetwo());
93 checkXML(fac);
94 }
95
96 @Test
97 public void testXMLReaderXSDFactoryURLArrayJAXP() throws JDOMException {
98 XMLReaderJDOMFactory fac = new XMLReaderXSDFactory(
99 "org.apache.xerces.jaxp.SAXParserFactoryImpl", null,
100 filemain(),
101 fileone(),
102 filetwo());
103 checkXML(fac);
104 }
105
106 @Test
107 public void testXMLReaderXSDFactoryFileArray() throws JDOMException {
108 XMLReaderJDOMFactory fac = new XMLReaderXSDFactory(
109 filemain(),
110 fileone(),
111 filetwo());
112 checkXML(fac);
113 }
114
115 @Test
116 public void testXMLReaderXSDFactoryFileArrayJAXP() throws JDOMException {
117 XMLReaderJDOMFactory fac = new XMLReaderXSDFactory(
118 "org.apache.xerces.jaxp.SAXParserFactoryImpl", null,
119 filemain(),
120 fileone(),
121 filetwo());
122 checkXML(fac);
123 }
124
125 @Test
126 public void testXMLReaderXSDFactorySourceArray() throws JDOMException, IOException {
127 XMLReaderJDOMFactory fac = new XMLReaderXSDFactory(
128 new StreamSource(filemain().openStream()),
129 new StreamSource(fileone().openStream()),
130 new StreamSource(filetwo().openStream()));
131 checkXML(fac);
132 }
133
134 @Test
135 public void testXMLReaderXSDFactorySourceArrayJJAXP() throws JDOMException, IOException {
136 XMLReaderJDOMFactory fac = new XMLReaderXSDFactory(
137 "org.apache.xerces.jaxp.SAXParserFactoryImpl", null,
138 new StreamSource(filemain().openStream()),
139 new StreamSource(fileone().openStream()),
140 new StreamSource(filetwo().openStream()));
141 checkXML(fac);
142 }
143
144 /* Broken stuff */
145
146 @Test
147 public void testXMLReaderXSDFactoryStringNull() {
148 try {
149 String n = null;
150 new XMLReaderXSDFactory(n);
151 UnitTestUtil.failNoException(NullPointerException.class);
152 } catch (Exception e) {
153 UnitTestUtil.checkException(NullPointerException.class, e);
154 }
155 }
156
157 @Test
158 public void testXMLReaderXSDFactoryURLNull() {
159 try {
160 URL n = null;
161 new XMLReaderXSDFactory(n);
162 UnitTestUtil.failNoException(NullPointerException.class);
163 } catch (Exception e) {
164 UnitTestUtil.checkException(NullPointerException.class, e);
165 }
166 }
167
168 @Test
169 public void testXMLReaderXSDFactoryFileNull() {
170 try {
171 File n = null;
172 new XMLReaderXSDFactory(n);
173 UnitTestUtil.failNoException(NullPointerException.class);
174 } catch (Exception e) {
175 UnitTestUtil.checkException(NullPointerException.class, e);
176 }
177 }
178
179 @Test
180 public void testXMLReaderXSDFactorySourceNull() {
181 try {
182 Source n = null;
183 new XMLReaderXSDFactory(n);
184 UnitTestUtil.failNoException(NullPointerException.class);
185 } catch (Exception e) {
186 UnitTestUtil.checkException(NullPointerException.class, e);
187 }
188 }
189
190
191 @Test
192 public void testXMLReaderXSDFactoryStringEmpty() {
193 try {
194 new XMLReaderXSDFactory(new String[0]);
195 UnitTestUtil.failNoException(IllegalArgumentException.class);
196 } catch (Exception e) {
197 UnitTestUtil.checkException(IllegalArgumentException.class, e);
198 }
199 }
200
201 @Test
202 public void testXMLReaderXSDFactoryURLEmpty() {
203 try {
204 new XMLReaderXSDFactory(new URL[0]);
205 UnitTestUtil.failNoException(IllegalArgumentException.class);
206 } catch (Exception e) {
207 UnitTestUtil.checkException(IllegalArgumentException.class, e);
208 }
209 }
210
211 @Test
212 public void testXMLReaderXSDFactoryFileEmpty() {
213 try {
214 new XMLReaderXSDFactory(new File[0]);
215 UnitTestUtil.failNoException(IllegalArgumentException.class);
216 } catch (Exception e) {
217 UnitTestUtil.checkException(IllegalArgumentException.class, e);
218 }
219 }
220
221 @Test
222 public void testXMLReaderXSDFactorySourceEmpty() {
223 try {
224 new XMLReaderXSDFactory(new Source[0]);
225 UnitTestUtil.failNoException(IllegalArgumentException.class);
226 } catch (Exception e) {
227 UnitTestUtil.checkException(IllegalArgumentException.class, e);
228 }
229 }
230
231
232
233 @Test
234 public void testXMLReaderXSDFactoryStringNullArray() {
235 try {
236 new XMLReaderXSDFactory((String[])null);
237 UnitTestUtil.failNoException(NullPointerException.class);
238 } catch (Exception e) {
239 UnitTestUtil.checkException(NullPointerException.class, e);
240 }
241 }
242
243 @Test
244 public void testXMLReaderXSDFactoryURLNullArray() {
245 try {
246 new XMLReaderXSDFactory((URL[])null);
247 UnitTestUtil.failNoException(NullPointerException.class);
248 } catch (Exception e) {
249 UnitTestUtil.checkException(NullPointerException.class, e);
250 }
251 }
252
253 @Test
254 public void testXMLReaderXSDFactoryFileNullArray() {
255 try {
256 new XMLReaderXSDFactory((File[])null);
257 UnitTestUtil.failNoException(NullPointerException.class);
258 } catch (Exception e) {
259 UnitTestUtil.checkException(NullPointerException.class, e);
260 }
261 }
262
263 @Test
264 public void testXMLReaderXSDFactorySourceNullArray() {
265 try {
266 new XMLReaderXSDFactory((Source[])null);
267 UnitTestUtil.failNoException(NullPointerException.class);
268 } catch (Exception e) {
269 UnitTestUtil.checkException(NullPointerException.class, e);
270 }
271 }
272
273 }
0 package org.jdom.test.cases.located;
1
2 import static org.junit.Assert.assertTrue;
3 import static org.junit.Assert.fail;
4
5 import java.io.IOException;
6
7 import org.junit.Test;
8
9 import org.jdom.Comment;
10 import org.jdom.Content;
11 import org.jdom.Document;
12 import org.jdom.Element;
13 import org.jdom.JDOMException;
14 import org.jdom.JDOMFactory;
15 import org.jdom.filter2.Filters;
16 import org.jdom.input.SAXBuilder;
17 import org.jdom.located.Located;
18 import org.jdom.located.LocatedJDOMFactory;
19 import org.jdom.test.cases.AbstractTestJDOMFactory;
20 import org.jdom.test.util.FidoFetch;
21 import org.jdom.xpath.XPathFactory;
22
23 @SuppressWarnings("javadoc")
24 public class TestLocatedJDOMFactory extends AbstractTestJDOMFactory {
25
26 /**
27 * @param located
28 */
29 public TestLocatedJDOMFactory() {
30 super(true);
31 }
32
33 @Override
34 protected JDOMFactory buildFactory() {
35 return new LocatedJDOMFactory();
36 }
37
38 private final void checkLocation(Content c, int line, int col) {
39 assertTrue(c instanceof Located);
40 Located l = (Located)c;
41 if(line != l.getLine()) {
42 fail("Expected content " + l + " to be on line " + line + " but its on " + l.getLine());
43 }
44 if(col != l.getColumn()) {
45 fail("Expected content " + l + " to be on col " + col + " but its on " + l.getColumn());
46 }
47 }
48
49 @Test
50 public void testLocation() throws JDOMException, IOException {
51 SAXBuilder sb = new SAXBuilder();
52 sb.setJDOMFactory(new LocatedJDOMFactory());
53 sb.setExpandEntities(false);
54 Document doc = sb.build(FidoFetch.getFido().getURL("/complex.xml"));
55 // it appears the location of the DocType is the start of the internal subset.
56 checkLocation(doc.getDocType(), 2, 16);
57 final Element root = doc.getRootElement();
58 checkLocation(root, 3, 32);
59
60 // content0 is first text....
61 // tab counts as 1, not 4... thus char 2, not 5....
62 checkLocation(root.getContent(0), 5, 2);
63
64 // get the comment...
65 Comment comment = root.getContent(org.jdom.filter.Filters.comment()).get(0);
66 checkLocation(comment, 12, 19);
67
68 Element leaf = XPathFactory.instance().compile("//leaf", Filters.element()).evaluateFirst(doc);
69 checkLocation(leaf, 21, 24);
70
71 }
72
73 }
0 package org.jdom.test.cases.output;
1
2 import static org.junit.Assert.assertEquals;
3
4 import java.util.ArrayList;
5 import java.util.List;
6
7 import org.junit.Test;
8
9 import org.jdom.Attribute;
10 import org.jdom.CDATA;
11 import org.jdom.Comment;
12 import org.jdom.Content;
13 import org.jdom.DocType;
14 import org.jdom.Document;
15 import org.jdom.Element;
16 import org.jdom.EntityRef;
17 import org.jdom.Namespace;
18 import org.jdom.Parent;
19 import org.jdom.ProcessingInstruction;
20 import org.jdom.Text;
21 import org.jdom.output.Format;
22 import org.jdom.output.Format.TextMode;
23
24 @SuppressWarnings("javadoc")
25 public abstract class AbstractTestOutputter {
26
27 protected static interface FormatSetup {
28 public void setup(Format fmt);
29 }
30
31
32 private final boolean cr2xD;
33 private final boolean pademptyelement;
34 private final boolean forceexpand;
35 private final boolean padpi;
36 private final boolean usesrawxmlout;
37
38 public AbstractTestOutputter(boolean cr2xD, boolean padpreempty, boolean padpi,
39 boolean forceexpand, boolean usesrawxmlout) {
40 this.cr2xD = cr2xD;
41 this.pademptyelement = padpreempty;
42 this.forceexpand = forceexpand;
43 this.padpi = padpi;
44 this.usesrawxmlout = usesrawxmlout;
45 }
46
47 protected final String expect(String expect) {
48 if (cr2xD) {
49 expect = expect.replaceAll("\r", "&#xD;");
50 }
51 if (forceexpand) {
52 expect = expect.replaceAll("<(\\w+(:\\w+)?)\\s*/>", "<$1></$1>");
53 expect = expect.replaceAll("<(\\w+(:\\w+)?)\\s+(.+?)\"\\s*/>", "<$1 $3\"></$1>");
54 }
55 if (padpi) {
56 expect = expect.replaceAll("(<\\?\\w+)(\\?>)", "$1 $2");
57 }
58 if (pademptyelement) {
59 //expect = expect.replaceAll("\">", "\" >");
60 //expect = expect.replaceAll("<(\\w+)>", "<$1 >");
61 expect = expect.replaceAll("<(\\w+(:\\w+)?)/>", "<$1 />");
62 expect = expect.replaceAll("<(\\w+(:\\w+)?\\s.+\")/>", "<$1 />");
63 } else {
64 //expect = expect.replaceAll("<(\\w+)\\s+>", "<$1>");
65 expect = expect.replaceAll("<(\\w+)(\\s+.+?)?\\s+/>", "<$1$2/>");
66 expect = expect.replaceAll("<(\\w+:\\w+)(\\s+.+?)?\\s+/>", "<$1$2/>");
67 }
68 // if (rawoutsideroot) {
69 // // outside the root element will be raw-formatted.
70 // StringBuilder sb = new StringBuilder(expect.length());
71 // int gotstuff = 0;
72 // boolean indoctype = false;
73 // boolean gotroot = false;
74 // int depth = 0;
75 // char[] chars = expect.toCharArray();
76 // int i = 0;
77 // while (i < chars.length && Verifier.isXMLWhitespace(chars[i])) {
78 // // skip initial whitespace.
79 // i++;
80 // }
81 // for (; i < chars.length; i++) {
82 // char c = chars[i];
83 // sb.append(c);
84 // if (!gotroot) {
85 // if (c == '<') {
86 // if (depth == 0) {
87 // if (i < chars.length - 2) {
88 // if (chars[i + 1] == '?') {
89 // // PI or XML Declaration
90 // gotstuff++;
91 // } else if (chars[i + 1] == '!') {
92 // // Comment of DOCTYPE
93 // gotstuff++;
94 // if (chars[i + 2] == 'D') {
95 // // DOCTYPE
96 // indoctype = true;
97 // }
98 // } else {
99 // // root element
100 // gotroot = true;
101 // }
102 // } else {
103 // gotroot = true;
104 // }
105 // }
106 // depth++;
107 // } else if (c == '>') {
108 // depth--;
109 // if (depth == 0) {
110 // if (indoctype) {
111 // sb.append('\n');
112 // indoctype = false;
113 // }
114 // while (i+1 < chars.length && Verifier.isXMLWhitespace(chars[i + 1])) {
115 // // skip whitespace after top-level content.
116 // i++;
117 // }
118 // }
119 // }
120 // }
121 // }
122 // while (Verifier.isXMLWhitespace(sb.charAt(sb.length() - 1))) {
123 // // eliminate trailing whitespace.
124 // sb.setLength(sb.length() - 1);
125 // }
126 // if (gotstuff > 1 || (gotroot && gotstuff > 0)) {
127 // // there is multiple content stuff, need to trim the whitespace....
128 // expect = sb.toString();
129 // }
130 // }
131 return expect;
132 }
133
134 /**
135 * Return a string representing a {@link Document}. Uses an internal
136 * StringWriter.
137 * <p>
138 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
139 * specified encoding.
140 *
141 * @param doc
142 * <code>Document</code> to format.
143 * @return the input content formatted as an XML String.
144 * @throws NullPointerException
145 * if the specified content is null.
146 */
147 public abstract String outputDocumentAsString(Format format, Document doc);
148
149 /**
150 * Return a string representing a {@link DocType}.
151 * <p>
152 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
153 * specified encoding.
154 *
155 * @param doctype
156 * <code>DocType</code> to format.
157 * @return the input content formatted as an XML String.
158 * @throws NullPointerException
159 * if the specified content is null.
160 */
161 public abstract String outputDocTypeAsString(Format format, DocType doctype);
162
163 /**
164 * Return a string representing an {@link Element}.
165 * <p>
166 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
167 * specified encoding.
168 *
169 * @param element
170 * <code>Element</code> to format.
171 * @return the input content formatted as an XML String.
172 * @throws NullPointerException
173 * if the specified content is null.
174 */
175 public abstract String outputElementAsString(Format format, Element element);
176
177 /**
178 * Return a string representing a List of {@link Content} nodes. <br>
179 * The list is assumed to contain legal JDOM nodes. If other content is
180 * coerced on to the list it will cause ClassCastExceptions, and null List
181 * members will cause NullPointerException.
182 * <p>
183 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
184 * specified encoding.
185 *
186 * @param list
187 * <code>List</code> to format.
188 * @return the input content formatted as an XML String.
189 * @throws ClassCastException
190 * if non-{@link Content} is forced in to the list
191 * @throws NullPointerException
192 * if the List is null or contains null members.
193 */
194 public abstract String outputListAsString(Format format, List<? extends Content> list);
195
196 /**
197 * Return a string representing a {@link CDATA} node.
198 * <p>
199 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
200 * specified encoding.
201 *
202 * @param cdata
203 * <code>CDATA</code> to format.
204 * @return the input content formatted as an XML String.
205 * @throws NullPointerException
206 * if the specified content is null.
207 */
208 public abstract String outputCDataAsString(Format format, CDATA cdata);
209
210 /**
211 * Return a string representing a {@link Text} node.
212 * <p>
213 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
214 * specified encoding.
215 *
216 * @param text
217 * <code>Text</code> to format.
218 * @return the input content formatted as an XML String.
219 * @throws NullPointerException
220 * if the specified content is null.
221 */
222 public abstract String outputTextAsString(Format format, Text text);
223
224 /**
225 * Return a string representing a {@link Comment}.
226 * <p>
227 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
228 * specified encoding.
229 *
230 * @param comment
231 * <code>Comment</code> to format.
232 * @return the input content formatted as an XML String.
233 * @throws NullPointerException
234 * if the specified content is null.
235 */
236 public abstract String outputCommentAsString(Format format, Comment comment);
237
238 /**
239 * Return a string representing a {@link ProcessingInstruction}.
240 * <p>
241 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
242 * specified encoding.
243 *
244 * @param pi
245 * <code>ProcessingInstruction</code> to format.
246 * @return the input content formatted as an XML String.
247 * @throws NullPointerException
248 * if the specified content is null.
249 */
250 public abstract String outputPIAsString(Format format, ProcessingInstruction pi);
251
252 /**
253 * Return a string representing an {@link EntityRef}.
254 * <p>
255 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
256 * specified encoding.
257 *
258 * @param entity
259 * <code>EntityRef</code> to format.
260 * @return the input content formatted as an XML String.
261 * @throws NullPointerException
262 * if the specified content is null.
263 */
264 public abstract String outputEntityRefAsString(Format format, EntityRef entity);
265
266 /**
267 * This will handle printing out an <code>{@link
268 * Element}</code>'s content only, not including its tag, and attributes.
269 * This can be useful for printing the content of an element that contains
270 * HTML, like "&lt;description&gt;JDOM is
271 * &lt;b&gt;fun&gt;!&lt;/description&gt;".
272 * <p>
273 * <b>Warning</b>: a String is Unicode, which may not match the outputter's
274 * specified encoding.
275 *
276 * @param element
277 * <code>Element</code> to output.
278 * @return the input content formatted as an XML String.
279 * @throws NullPointerException
280 * if the specified content is null.
281 */
282 public abstract String outputElementContentString(Format format, Element element);
283
284 protected static final Format fraw = Format.getRawFormat();
285 protected static final Format frawfp = Format.getPrettyFormat().setTextMode(TextMode.PRESERVE);
286 protected static final Format fcompact = Format.getCompactFormat();
287 protected static final Format fpretty = Format.getPrettyFormat();
288 protected static final Format ftso = Format.getPrettyFormat();
289 protected static final Format ftfw = Format.getPrettyFormat();
290
291 static {
292 fraw.setLineSeparator("\n");
293 frawfp.setLineSeparator("\n");
294 fcompact.setLineSeparator("\n");
295 fpretty.setLineSeparator("\n");
296 ftso.setLineSeparator("\n");
297 ftso.setSpecifiedAttributesOnly(true);
298 ftfw.setLineSeparator("\n");
299 ftfw.setTextMode(TextMode.TRIM_FULL_WHITE);
300 }
301
302
303 @Test
304 public void testTextEmpty() {
305 Text content = new Text("");
306 assertEquals("", outputTextAsString(fraw, content));
307 assertEquals("", outputTextAsString(frawfp, content));
308 assertEquals("", outputTextAsString(fcompact, content));
309 assertEquals("", outputTextAsString(fpretty, content));
310 assertEquals("", outputTextAsString(ftso, content));
311 assertEquals("", outputTextAsString(ftfw, content));
312 }
313
314 @Test
315 public void testTextWhitespace() {
316 Text content = new Text(" \r \n \t ");
317 assertEquals(expect(" \r \n \t "),
318 outputTextAsString(fraw, content));
319 assertEquals(expect(" \r \n \t "),
320 outputTextAsString(frawfp, content));
321 assertEquals("",
322 outputTextAsString(fcompact, content));
323 assertEquals("",
324 outputTextAsString(fpretty, content));
325 assertEquals("",
326 outputTextAsString(ftso, content));
327 assertEquals("",
328 outputTextAsString(ftfw, content));
329 }
330
331 @Test
332 public void testTextWithText() {
333 Text content = new Text(" \r & \n \t ");
334 assertEquals(expect(" \r &amp; \n \t "),
335 outputTextAsString(fraw, content));
336 assertEquals(expect(" \r &amp; \n \t "),
337 outputTextAsString(frawfp, content));
338 assertEquals(expect("&amp;"),
339 outputTextAsString(fcompact, content));
340 assertEquals(expect("&amp;"),
341 outputTextAsString(fpretty, content));
342 assertEquals(expect("&amp;"),
343 outputTextAsString(ftso, content));
344 assertEquals(expect(" \r &amp; \n \t "),
345 outputTextAsString(ftfw, content));
346 }
347
348 @Test
349 public void testCDATAEmpty() {
350 CDATA content = new CDATA("");
351 assertEquals("<![CDATA[]]>",
352 outputCDataAsString(fraw, content));
353 assertEquals("<![CDATA[]]>",
354 outputCDataAsString(frawfp, content));
355 assertEquals("",
356 outputCDataAsString(fcompact, content));
357 assertEquals("",
358 outputCDataAsString(fpretty, content));
359 assertEquals("",
360 outputCDataAsString(ftso, content));
361 assertEquals("",
362 outputCDataAsString(ftfw, content));
363 }
364
365 @Test
366 public void testCDATAWhitespace() {
367 CDATA content = new CDATA(" \r \n \t ");
368 assertEquals("<![CDATA[ \r \n \t ]]>",
369 outputCDataAsString(fraw, content));
370 assertEquals("<![CDATA[ \r \n \t ]]>",
371 outputCDataAsString(frawfp, content));
372 assertEquals("",
373 outputCDataAsString(fcompact, content));
374 assertEquals("",
375 outputCDataAsString(fpretty, content));
376 assertEquals("",
377 outputCDataAsString(ftso, content));
378 assertEquals("",
379 outputCDataAsString(ftfw, content));
380 }
381
382 @Test
383 public void testCDATAWithText() {
384 CDATA content = new CDATA(" \r & \n \t ");
385 assertEquals("<![CDATA[ \r & \n \t ]]>",
386 outputCDataAsString(fraw, content));
387 assertEquals("<![CDATA[ \r & \n \t ]]>",
388 outputCDataAsString(frawfp, content));
389 assertEquals("<![CDATA[&]]>",
390 outputCDataAsString(fcompact, content));
391 assertEquals("<![CDATA[&]]>",
392 outputCDataAsString(fpretty, content));
393 assertEquals("<![CDATA[&]]>",
394 outputCDataAsString(ftso, content));
395 assertEquals("<![CDATA[ \r & \n \t ]]>",
396 outputCDataAsString(ftfw, content));
397 }
398
399 @Test
400 public void testEntityRef() {
401 EntityRef content = new EntityRef("ref");
402 assertEquals("&ref;",
403 outputEntityRefAsString(fraw, content));
404 assertEquals("&ref;",
405 outputEntityRefAsString(frawfp, content));
406 assertEquals("&ref;",
407 outputEntityRefAsString(fcompact, content));
408 assertEquals("&ref;",
409 outputEntityRefAsString(fpretty, content));
410 assertEquals("&ref;",
411 outputEntityRefAsString(ftso, content));
412 assertEquals("&ref;",
413 outputEntityRefAsString(ftfw, content));
414 }
415
416 @Test
417 public void testProcessingInstructionTargetOnly() {
418 ProcessingInstruction content = new ProcessingInstruction("target");
419 assertEquals(expect("<?target?>"),
420 outputPIAsString(fraw, content));
421 assertEquals(expect("<?target?>"),
422 outputPIAsString(frawfp, content));
423 assertEquals(expect("<?target?>"),
424 outputPIAsString(fcompact, content));
425 assertEquals(expect("<?target?>"),
426 outputPIAsString(fpretty, content));
427 assertEquals(expect("<?target?>"),
428 outputPIAsString(ftfw, content));
429 }
430
431 @Test
432 public void testProcessingInstructionTargetWithData() {
433 ProcessingInstruction content =
434 new ProcessingInstruction("target", "data");
435 assertEquals("<?target data?>",
436 outputPIAsString(fraw, content));
437 assertEquals("<?target data?>",
438 outputPIAsString(frawfp, content));
439 assertEquals("<?target data?>",
440 outputPIAsString(fcompact, content));
441 assertEquals("<?target data?>",
442 outputPIAsString(fpretty, content));
443 assertEquals("<?target data?>",
444 outputPIAsString(ftso, content));
445 assertEquals("<?target data?>",
446 outputPIAsString(ftfw, content));
447 }
448
449 @Test
450 public void testComment() {
451 Comment content = new Comment("comment");
452 assertEquals("<!--comment-->",
453 outputCommentAsString(fraw, content));
454 assertEquals("<!--comment-->",
455 outputCommentAsString(frawfp, content));
456 assertEquals("<!--comment-->",
457 outputCommentAsString(fcompact, content));
458 assertEquals("<!--comment-->",
459 outputCommentAsString(fpretty, content));
460 assertEquals("<!--comment-->",
461 outputCommentAsString(ftso, content));
462 assertEquals("<!--comment-->",
463 outputCommentAsString(ftfw, content));
464 }
465
466
467 @Test
468 public void testDocTypeSimple() {
469 DocType content = new DocType("root");
470 assertEquals("<!DOCTYPE root>",
471 outputDocTypeAsString(fraw, content));
472 assertEquals("<!DOCTYPE root>",
473 outputDocTypeAsString(frawfp, content));
474 assertEquals("<!DOCTYPE root>",
475 outputDocTypeAsString(fcompact, content));
476 assertEquals("<!DOCTYPE root>",
477 outputDocTypeAsString(fpretty, content));
478 assertEquals("<!DOCTYPE root>",
479 outputDocTypeAsString(ftso, content));
480 assertEquals("<!DOCTYPE root>",
481 outputDocTypeAsString(ftfw, content));
482 }
483
484 @Test
485 public void testDocTypeSimpleISS() {
486 DocType content = new DocType("root");
487 content.setInternalSubset("<!ENTITY name \"value\">");
488 assertEquals("<!DOCTYPE root [\n<!ENTITY name \"value\">]>",
489 outputDocTypeAsString(fraw, content));
490 assertEquals("<!DOCTYPE root [\n<!ENTITY name \"value\">]>",
491 outputDocTypeAsString(frawfp, content));
492 assertEquals("<!DOCTYPE root [\n<!ENTITY name \"value\">]>",
493 outputDocTypeAsString(fcompact, content));
494 assertEquals("<!DOCTYPE root [\n<!ENTITY name \"value\">]>",
495 outputDocTypeAsString(fpretty, content));
496 assertEquals("<!DOCTYPE root [\n<!ENTITY name \"value\">]>",
497 outputDocTypeAsString(ftso, content));
498 assertEquals("<!DOCTYPE root [\n<!ENTITY name \"value\">]>",
499 outputDocTypeAsString(ftfw, content));
500 }
501
502 @Test
503 public void testDocTypeSystemID() {
504 DocType content = new DocType("root", "sysid");
505 assertEquals("<!DOCTYPE root SYSTEM \"sysid\">",
506 outputDocTypeAsString(fraw, content));
507 assertEquals("<!DOCTYPE root SYSTEM \"sysid\">",
508 outputDocTypeAsString(frawfp, content));
509 assertEquals("<!DOCTYPE root SYSTEM \"sysid\">",
510 outputDocTypeAsString(fcompact, content));
511 assertEquals("<!DOCTYPE root SYSTEM \"sysid\">",
512 outputDocTypeAsString(fpretty, content));
513 assertEquals("<!DOCTYPE root SYSTEM \"sysid\">",
514 outputDocTypeAsString(ftso, content));
515 assertEquals("<!DOCTYPE root SYSTEM \"sysid\">",
516 outputDocTypeAsString(ftfw, content));
517 }
518
519 @Test
520 public void testDocTypeSystemIDISS() {
521 DocType content = new DocType("root", "sysid");
522 content.setInternalSubset("internal");
523 assertEquals("<!DOCTYPE root SYSTEM \"sysid\" [\ninternal]>",
524 outputDocTypeAsString(fraw, content));
525 assertEquals("<!DOCTYPE root SYSTEM \"sysid\" [\ninternal]>",
526 outputDocTypeAsString(frawfp, content));
527 assertEquals("<!DOCTYPE root SYSTEM \"sysid\" [\ninternal]>",
528 outputDocTypeAsString(fcompact, content));
529 assertEquals("<!DOCTYPE root SYSTEM \"sysid\" [\ninternal]>",
530 outputDocTypeAsString(fpretty, content));
531 assertEquals("<!DOCTYPE root SYSTEM \"sysid\" [\ninternal]>",
532 outputDocTypeAsString(ftso, content));
533 assertEquals("<!DOCTYPE root SYSTEM \"sysid\" [\ninternal]>",
534 outputDocTypeAsString(ftfw, content));
535 }
536
537 @Test
538 public void testDocTypePublicSystemID() {
539 DocType content = new DocType("root", "pubid", "sysid");
540 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\">",
541 outputDocTypeAsString(fraw, content));
542 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\">",
543 outputDocTypeAsString(frawfp, content));
544 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\">",
545 outputDocTypeAsString(fcompact, content));
546 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\">",
547 outputDocTypeAsString(fpretty, content));
548 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\">",
549 outputDocTypeAsString(ftso, content));
550 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\">",
551 outputDocTypeAsString(ftfw, content));
552 }
553
554 @Test
555 public void testDocTypePublicSystemIDISS() {
556 DocType content = new DocType("root", "pubid", "sysid");
557 content.setInternalSubset("internal");
558 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\" [\ninternal]>",
559 outputDocTypeAsString(fraw, content));
560 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\" [\ninternal]>",
561 outputDocTypeAsString(frawfp, content));
562 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\" [\ninternal]>",
563 outputDocTypeAsString(fcompact, content));
564 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\" [\ninternal]>",
565 outputDocTypeAsString(fpretty, content));
566 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\" [\ninternal]>",
567 outputDocTypeAsString(ftso, content));
568 assertEquals("<!DOCTYPE root PUBLIC \"pubid\" \"sysid\" [\ninternal]>",
569 outputDocTypeAsString(ftfw, content));
570 }
571
572 @Test
573 public void testMultiWhiteText() {
574 Element root = new Element("root");
575 root.addContent(new CDATA(" "));
576 root.addContent(new Text(" "));
577 root.addContent(new Text(" "));
578 root.addContent(new Text(""));
579 root.addContent(new Text(" "));
580 root.addContent(new Text(" \n \n "));
581 root.addContent(new Text(" \t "));
582 root.addContent(new Text(" "));
583 assertEquals(expect("<root><![CDATA[ ]]> \n \n \t </root>"),
584 outputElementAsString(fraw, root));
585 assertEquals(expect("<root><![CDATA[ ]]> \n \n \t </root>"),
586 outputElementAsString(frawfp, root));
587 assertEquals(expect("<root/>"),
588 outputElementAsString(fcompact, root));
589 assertEquals(expect("<root/>"),
590 outputElementAsString(fpretty, root));
591 assertEquals(expect("<root/>"),
592 outputElementAsString(ftso, root));
593 assertEquals(expect("<root/>"),
594 outputElementAsString(ftfw, root));
595 }
596
597 @Test
598 public void testMultiText() {
599 Element root = new Element("root");
600 root.addContent(new CDATA(" "));
601 root.addContent(new Text(" "));
602 root.addContent(new Text(" "));
603 root.addContent(new Text(""));
604 root.addContent(new Text("X"));
605 root.addContent(new Text(" \n \n "));
606 root.addContent(new Text(" \t "));
607 root.addContent(new Text(" "));
608 assertEquals(expect("<root><![CDATA[ ]]> X \n \n \t </root>"),
609 outputElementAsString(fraw, root));
610 assertEquals(expect("<root><![CDATA[ ]]> X \n \n \t </root>"),
611 outputElementAsString(frawfp, root));
612 assertEquals(expect("<root>X</root>"),
613 outputElementAsString(fcompact, root));
614 assertEquals(expect("<root>X</root>"),
615 outputElementAsString(fpretty, root));
616 assertEquals(expect("<root>X</root>"),
617 outputElementAsString(ftso, root));
618 assertEquals(expect("<root><![CDATA[ ]]> X \n \n \t </root>"),
619 outputElementAsString(ftfw, root));
620 }
621
622 @Test
623 public void testDocumentSimple() {
624 Document content = new Document();
625 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
626 outputDocumentAsString(fraw, content));
627 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
628 outputDocumentAsString(frawfp, content));
629 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
630 outputDocumentAsString(fcompact, content));
631 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
632 outputDocumentAsString(fpretty, content));
633 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
634 outputDocumentAsString(ftso, content));
635 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
636 outputDocumentAsString(ftfw, content));
637 }
638
639 @Test
640 public void testDocumentDocType() {
641 Document content = new Document();
642 content.setDocType(new DocType("root"));
643 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE root>\n",
644 outputDocumentAsString(fraw, content));
645 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE root>\n",
646 outputDocumentAsString(frawfp, content));
647 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE root>\n",
648 outputDocumentAsString(fcompact, content));
649 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE root>\n",
650 outputDocumentAsString(fpretty, content));
651 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE root>\n",
652 outputDocumentAsString(ftso, content));
653 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE root>\n",
654 outputDocumentAsString(ftfw, content));
655 }
656
657 @Test
658 public void testDocumentComment() {
659 Document content = new Document();
660 content.addContent(new Comment("comment"));
661 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--comment-->\n",
662 outputDocumentAsString(fraw, content));
663 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--comment-->\n",
664 outputDocumentAsString(frawfp, content));
665 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--comment-->\n",
666 outputDocumentAsString(fcompact, content));
667 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--comment-->\n",
668 outputDocumentAsString(fpretty, content));
669 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--comment-->\n",
670 outputDocumentAsString(ftso, content));
671 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--comment-->\n",
672 outputDocumentAsString(ftfw, content));
673 }
674
675
676
677
678
679
680
681
682
683
684 @Test
685 public void testXXX() {
686 Text content = new Text("");
687 assertEquals("",
688 outputTextAsString(fraw, content));
689 assertEquals("",
690 outputTextAsString(frawfp, content));
691 assertEquals("",
692 outputTextAsString(fcompact, content));
693 assertEquals("",
694 outputTextAsString(fpretty, content));
695 assertEquals("",
696 outputTextAsString(ftfw, content));
697 }
698
699
700
701
702
703 @Test
704 public void testOutputText() {
705 checkOutput(new Text(" hello there "), " hello there ", "hello there", "hello there", "hello there", " hello there ");
706 }
707
708 @Test
709 public void testOutputCDATA() {
710 String indata = " hello there bozo ! ";
711 String rawcdata = "<![CDATA[ hello there bozo ! ]]>";
712 String compdata = "<![CDATA[hello there bozo !]]>";
713 String prettydata = "<![CDATA[hello there bozo !]]>";
714 String trimdata = "<![CDATA[ hello there bozo ! ]]>";
715
716 checkOutput(new CDATA(indata), rawcdata, compdata, prettydata, prettydata, trimdata);
717 }
718
719 @Test
720 public void testOutputComment() {
721 String incomment = " hello there bozo ! ";
722 String outcomment = "<!--" + incomment + "-->";
723 checkOutput(new Comment(incomment), outcomment, outcomment, outcomment, outcomment, outcomment);
724 }
725
726 @Test
727 public void testOutputProcessingInstructionSimple() {
728 ProcessingInstruction inpi = new ProcessingInstruction("jdomtest", "");
729 String outpi = "<?jdomtest?>";
730 checkOutput(inpi, outpi, outpi, outpi, outpi, outpi);
731 }
732
733 @Test
734 public void testOutputProcessingInstructionData() {
735 String pi = " hello there ";
736 ProcessingInstruction inpi = new ProcessingInstruction("jdomtest", pi);
737 String outpi = "<?jdomtest " + pi + "?>";
738 checkOutput(inpi, outpi, outpi, outpi, outpi, outpi);
739 }
740
741 @Test
742 public void testOutputEntityRef() {
743 checkOutput(new EntityRef("name", "publicID", "systemID"),
744 "&name;", "&name;", "&name;", "&name;", "&name;");
745 }
746
747 @Test
748 public void testOutputElementSimple() {
749 String txt = "<root/>";
750 checkOutput(new Element("root"), txt, txt, txt, txt, txt);
751 }
752
753 @Test
754 public void testOutputElementAttribute() {
755 String txt = "<root att=\"val\" />";
756 checkOutput(new Element("root").setAttribute("att", "val"), txt, txt, txt, txt, txt);
757 }
758
759 @Test
760 public void testOutputElementAttributeNotSpecifiedA() {
761 String txt = "<root att=\"val\" />";
762 final Element root = new Element("root");
763 final Attribute att = new Attribute("att", "val");
764 root.setAttribute(att);
765 att.setSpecified(false);
766 checkOutput(root, txt, txt, txt, "<root />", txt);
767 }
768
769 @Test
770 public void testOutputElementAttributeNotSpecifiedB() {
771 String txt = "<root atta=\"val\" attb=\"attb\" />";
772 final Element root = new Element("root");
773 final Attribute atta = new Attribute("atta", "val");
774 final Attribute attb = new Attribute("attb", "attb");
775 root.setAttribute(atta);
776 root.setAttribute(attb);
777 atta.setSpecified(false);
778 checkOutput(root, txt, txt, txt, "<root attb=\"attb\" />", txt);
779 }
780
781 @Test
782 public void testOutputElementCDATA() {
783 String txt = "<root><![CDATA[xx]]></root>";
784 Element root = new Element("root");
785 root.addContent(new CDATA("xx"));
786 checkOutput(root, txt, txt, txt, txt, txt);
787 }
788
789 @Test
790 public void testOutputElementExpandEmpty() {
791 String txt = "<root></root>";
792 FormatSetup setup = new FormatSetup() {
793 @Override
794 public void setup(Format fmt) {
795 fmt.setExpandEmptyElements(true);
796 }
797 };
798 checkOutput(new Element("root"), setup, txt, txt, txt, txt, txt);
799 }
800
801 @Test
802 public void testOutputElementPreserveSpace() {
803 String txt = "<root xml:space=\"preserve\"> <child xml:space=\"default\">abc</child> </root>";
804 Element root = new Element("root");
805 root.setAttribute("space", "preserve", Namespace.XML_NAMESPACE);
806 root.addContent(" ");
807 Element child = new Element("child");
808 child.setAttribute("space", "default", Namespace.XML_NAMESPACE);
809 child.addContent("abc");
810 root.addContent(child);
811 root.addContent(" ");
812 checkOutput(root, txt, txt, txt, txt, txt);
813 }
814
815 @Test
816 public void testOutputElementPreserveSpaceComplex() {
817 // the purpose of this test is to ensure that the different
818 // formatting values are used when going down one level,
819 // back up, then in to 'preserve', back up, and then again
820 // down in to normal (not preserve).
821
822 // this is essentially a test of the FormatStack code....
823
824 Element tst = new Element("child");
825 Comment cmt = new Comment("comment");
826 tst.addContent(cmt);
827 String spaced = " <child>\n <!--comment-->\n </child>\n";
828 String compact = "<child><!--comment--></child>";
829 String preserved = "<child xml:space=\"preserve\"><!--comment--></child>";
830 Element root = new Element("root");
831 root.addContent(tst.clone());
832 root.addContent(tst.clone().setAttribute("space", "preserve", Namespace.XML_NAMESPACE));
833 root.addContent(tst.clone());
834 String rawcompact = "<root>" + compact + preserved + compact + "</root>";
835 String pretty = "<root>\n" + spaced + " " + preserved + "\n" + spaced + "</root>";
836 checkOutput(root, rawcompact, rawcompact, pretty, pretty, pretty);
837 }
838
839
840 @Test
841 public void testOutputElementMultiText() {
842 Element root = new Element("root");
843 root.addContent(new CDATA(" "));
844 root.addContent(new Text(" xx "));
845 root.addContent(new Text("yy"));
846 root.addContent(new Text(" "));
847 root.addContent(new Text("zz"));
848 root.addContent(new Text(" ww"));
849 root.addContent(new EntityRef("amp"));
850 root.addContent(new Text("vv"));
851 root.addContent(new Text(" "));
852 checkOutput(root,
853 "<root><![CDATA[ ]]> xx yy zz ww&amp;vv </root>",
854 "<root>xx yy zz ww&amp;vv</root>",
855 "<root>xx yy zz ww&amp;vv</root>",
856 "<root>xx yy zz ww&amp;vv</root>",
857 // This should be changed with issue #31.
858 // The real value should have one additional
859 // space at the beginning and two at the end
860 // for now we leave the broken test here because it
861 // helps with the coverage reports.
862 // the next test is added to be a failing test.
863 "<root><![CDATA[ ]]> xx yy zz ww&amp;vv </root>");
864 }
865
866 @Test
867 public void testOutputElementMultiAllWhite() {
868 Element root = new Element("root");
869 root.addContent(new CDATA(" "));
870 root.addContent(new Text(" "));
871 root.addContent(new Text(" "));
872 root.addContent(new Text(""));
873 root.addContent(new Text(" "));
874 root.addContent(new Text(" \n \n "));
875 root.addContent(new Text(" \t "));
876 root.addContent(new Text(" "));
877 checkOutput(root,
878 "<root><![CDATA[ ]]> \n \n \t </root>",
879 "<root />",
880 "<root />",
881 "<root />",
882 "<root />");
883 }
884
885 @Test
886 public void testOutputElementMultiAllWhiteExpandEmpty() {
887 Element root = new Element("root");
888 root.addContent(new CDATA(" "));
889 root.addContent(new Text(" "));
890 root.addContent(new Text(" "));
891 root.addContent(new Text(""));
892 root.addContent(new Text(" "));
893 root.addContent(new Text(" \n \n "));
894 root.addContent(new Text(" \t "));
895 root.addContent(new Text(" "));
896 FormatSetup fs = new FormatSetup() {
897 @Override
898 public void setup(Format fmt) {
899 fmt.setExpandEmptyElements(true);
900 }
901 };
902 checkOutput(root, fs,
903 "<root><![CDATA[ ]]> \n \n \t </root>",
904 "<root></root>",
905 "<root></root>",
906 "<root></root>",
907 "<root></root>");
908 }
909
910 @Test
911 public void testOutputElementMultiMostWhiteExpandEmpty() {
912 // this test has mixed content (text-type and not text type).
913 // and, it has a multi-text-type at the end.
914 Element root = new Element("root");
915 root.addContent(new CDATA(" "));
916 root.addContent(new Text(" "));
917 root.addContent(new Text(" "));
918 root.addContent(new Text(""));
919 root.addContent(new Text(" "));
920 root.addContent(new Text(" \n \n "));
921 root.addContent(new Comment("Boo"));
922 root.addContent(new Text(" \t "));
923 root.addContent(new Text(" "));
924 FormatSetup fs = new FormatSetup() {
925 @Override
926 public void setup(Format fmt) {
927 fmt.setExpandEmptyElements(true);
928 }
929 };
930 checkOutput(root, fs,
931 "<root><![CDATA[ ]]> \n \n <!--Boo--> \t </root>",
932 "<root><!--Boo--></root>",
933 "<root>\n <!--Boo-->\n</root>",
934 "<root>\n <!--Boo-->\n</root>",
935 "<root>\n <!--Boo-->\n</root>");
936 }
937
938 @Test
939 public void testOutputElementMixedMultiCDATA() {
940 // this test has mixed content (text-type and not text type).
941 // and, it has a multi-text-type at the end.
942 Element root = new Element("root");
943 root.addContent(new Comment("Boo"));
944 root.addContent(new Text(" "));
945 root.addContent(new CDATA("A"));
946 FormatSetup fs = new FormatSetup() {
947 @Override
948 public void setup(Format fmt) {
949 fmt.setExpandEmptyElements(true);
950 }
951 };
952 checkOutput(root, fs,
953 "<root><!--Boo--> <![CDATA[A]]></root>",
954 "<root><!--Boo--><![CDATA[A]]></root>",
955 "<root>\n <!--Boo-->\n <![CDATA[A]]>\n</root>",
956 "<root>\n <!--Boo-->\n <![CDATA[A]]>\n</root>",
957 "<root>\n <!--Boo-->\n <![CDATA[A]]>\n</root>");
958 }
959
960 @Test
961 public void testOutputElementMixedMultiEntityRef() {
962 // this test has mixed content (text-type and not text type).
963 // and, it has a multi-text-type at the end.
964 Element root = new Element("root");
965 root.addContent(new Comment("Boo"));
966 root.addContent(new Text(" "));
967 root.addContent(new EntityRef("aer"));
968 FormatSetup fs = new FormatSetup() {
969 @Override
970 public void setup(Format fmt) {
971 fmt.setExpandEmptyElements(true);
972 }
973 };
974 checkOutput(root, fs,
975 "<root><!--Boo--> &aer;</root>",
976 "<root><!--Boo-->&aer;</root>",
977 "<root>\n <!--Boo-->\n &aer;\n</root>",
978 "<root>\n <!--Boo-->\n &aer;\n</root>",
979 "<root>\n <!--Boo-->\n &aer;\n</root>");
980 }
981
982 @Test
983 public void testOutputElementMixedMultiText() {
984 // this test has mixed content (text-type and not text type).
985 // and, it has a multi-text-type at the end.
986 Element root = new Element("root");
987 root.addContent(new Comment("Boo"));
988 root.addContent(new Text(" "));
989 root.addContent(new Text("txt"));
990 FormatSetup fs = new FormatSetup() {
991 @Override
992 public void setup(Format fmt) {
993 fmt.setExpandEmptyElements(true);
994 }
995 };
996 checkOutput(root, fs,
997 "<root><!--Boo--> txt</root>",
998 "<root><!--Boo-->txt</root>",
999 "<root>\n <!--Boo-->\n txt\n</root>",
1000 "<root>\n <!--Boo-->\n txt\n</root>",
1001 "<root>\n <!--Boo-->\n txt\n</root>");
1002 }
1003
1004 @Test
1005 public void testOutputElementMixedMultiZeroText() {
1006 // this test has mixed content (text-type and not text type).
1007 // and, it has a multi-text-type at the end.
1008 Element root = new Element("root");
1009 root.addContent(new Comment("Boo"));
1010 root.addContent(new Text(""));
1011 root.addContent(new Text(" "));
1012 root.addContent(new Text(""));
1013 root.addContent(new Text("txt"));
1014 root.addContent(new Text(""));
1015 FormatSetup fs = new FormatSetup() {
1016 @Override
1017 public void setup(Format fmt) {
1018 fmt.setExpandEmptyElements(true);
1019 }
1020 };
1021 checkOutput(root, fs,
1022 "<root><!--Boo--> txt</root>",
1023 "<root><!--Boo-->txt</root>",
1024 "<root>\n <!--Boo-->\n txt\n</root>",
1025 "<root>\n <!--Boo-->\n txt\n</root>",
1026 "<root>\n <!--Boo-->\n txt\n</root>");
1027 }
1028
1029 @Test
1030 public void testOutputElementInterleavedEmptyText() {
1031 // this is to test issue #72
1032 // Compact format only prints first child.
1033 // and, it has a multi-text-type at the end.
1034 Element root = new Element("root");
1035 root.addContent(new Text(" "));
1036 root.addContent(new Comment("Boo"));
1037 root.addContent(new Text(" "));
1038 root.addContent(new Element("child"));
1039 root.addContent(new Text(" "));
1040 root.addContent(new ProcessingInstruction("pitarget"));
1041 root.addContent(new Text(" "));
1042 checkOutput(root,
1043 "<root> <!--Boo--> <child /> <?pitarget?> </root>",
1044 "<root><!--Boo--><child /><?pitarget?></root>",
1045 "<root>\n <!--Boo-->\n <child />\n <?pitarget?>\n</root>",
1046 "<root>\n <!--Boo-->\n <child />\n <?pitarget?>\n</root>",
1047 "<root>\n <!--Boo-->\n <child />\n <?pitarget?>\n</root>");
1048 }
1049
1050 @Test
1051 public void testOutputElementMultiEntityLeftRight() {
1052 Element root = new Element("root");
1053 root.addContent(new EntityRef("erl"));
1054 root.addContent(new Text(" "));
1055 root.addContent(new Text(" "));
1056 root.addContent(new EntityRef("err"));
1057 checkOutput(root,
1058 "<root>&erl; &err;</root>",
1059 "<root>&erl; &err;</root>",
1060 "<root>&erl; &err;</root>",
1061 "<root>&erl; &err;</root>",
1062 "<root>&erl; &err;</root>");
1063 }
1064
1065 @Test
1066 public void testOutputElementMultiTrimLeftRight() {
1067 Element root = new Element("root");
1068 root.addContent(new Text(" tl "));
1069 root.addContent(new Text(" mid "));
1070 root.addContent(new Text(" tr "));
1071 checkOutput(root,
1072 "<root> tl mid tr </root>",
1073 "<root>tl mid tr</root>",
1074 "<root>tl mid tr</root>",
1075 "<root>tl mid tr</root>",
1076 "<root> tl mid tr </root>");
1077 }
1078
1079 @Test
1080 public void testOutputElementMultiCDATALeftRight() {
1081 Element root = new Element("root");
1082 root.addContent(new CDATA(" tl "));
1083 root.addContent(new Text(" mid "));
1084 root.addContent(new CDATA(" tr "));
1085 checkOutput(root,
1086 "<root><![CDATA[ tl ]]> mid <![CDATA[ tr ]]></root>",
1087 "<root><![CDATA[tl]]> mid <![CDATA[tr]]></root>",
1088 "<root><![CDATA[tl ]]> mid <![CDATA[ tr]]></root>",
1089 "<root><![CDATA[tl ]]> mid <![CDATA[ tr]]></root>",
1090 "<root><![CDATA[ tl ]]> mid <![CDATA[ tr ]]></root>");
1091 }
1092
1093
1094
1095 @Test
1096 public void testOutputElementNamespaces() {
1097 String txt = "<ns:root xmlns:ns=\"myns\" xmlns:ans=\"attributens\" xmlns:two=\"two\" ans:att=\"val\"/>";
1098 Element emt = new Element("root", Namespace.getNamespace("ns", "myns"));
1099 Namespace ans = Namespace.getNamespace("ans", "attributens");
1100 emt.setAttribute(new Attribute("att", "val", ans));
1101 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
1102 checkOutput(emt,
1103 txt, txt,txt, txt, txt);
1104 }
1105
1106 @Test
1107 public void testOutputDocTypeSimple() {
1108 checkOutput(new DocType("root"), "<!DOCTYPE root>", "<!DOCTYPE root>", "<!DOCTYPE root>",
1109 "<!DOCTYPE root>", "<!DOCTYPE root>");
1110 }
1111
1112 @Test
1113 public void testOutputDocTypeInternalSubset() {
1114 String dec = "<!DOCTYPE root [\ninternal]>";
1115 DocType dt = new DocType("root");
1116 dt.setInternalSubset("internal");
1117 checkOutput(dt, dec, dec, dec, dec, dec);
1118 }
1119
1120 @Test
1121 public void testOutputDocTypeSystem() {
1122 String dec = "<!DOCTYPE root SYSTEM \"systemID\">";
1123 checkOutput(new DocType("root", "systemID"), dec, dec, dec, dec, dec);
1124 }
1125
1126 @Test
1127 public void testOutputDocTypePublic() {
1128 String dec = "<!DOCTYPE root PUBLIC \"publicID\">";
1129 checkOutput(new DocType("root", "publicID", null), dec, dec, dec, dec, dec);
1130 }
1131
1132 @Test
1133 public void testOutputDocTypePublicSystem() {
1134 String dec = "<!DOCTYPE root PUBLIC \"publicID\" \"systemID\">";
1135 checkOutput(new DocType("root", "publicID", "systemID"), dec, dec, dec, dec, dec);
1136 }
1137
1138 @Test
1139 public void testOutputDocumentSimple() {
1140 Document doc = new Document();
1141 doc.addContent(new Element("root"));
1142 String xmldec = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1143 String rtdec = "<root />";
1144 checkOutput(doc,
1145 xmldec + "\n" + rtdec + "\n",
1146 xmldec + "\n" + rtdec + "\n",
1147 xmldec + "\n" + rtdec + "\n",
1148 xmldec + "\n" + rtdec + "\n",
1149 xmldec + "\n" + rtdec + "\n");
1150 }
1151
1152 @Test
1153 public void testOutputDocumentOmitEncoding() {
1154 Document doc = new Document();
1155 doc.addContent(new Element("root"));
1156 String xmldec = "<?xml version=\"1.0\"?>";
1157 FormatSetup setup = new FormatSetup() {
1158 @Override
1159 public void setup(Format fmt) {
1160 fmt.setOmitEncoding(true);
1161 }
1162 };
1163 String rtdec = "<root />";
1164 checkOutput(doc, setup,
1165 xmldec + "\n" + rtdec + "\n",
1166 xmldec + "\n" + rtdec + "\n",
1167 xmldec + "\n" + rtdec + "\n",
1168 xmldec + "\n" + rtdec + "\n",
1169 xmldec + "\n" + rtdec + "\n");
1170 }
1171
1172 @Test
1173 public void testOutputDocumentOmitDeclaration() {
1174 Document doc = new Document();
1175 doc.addContent(new Element("root"));
1176 FormatSetup setup = new FormatSetup() {
1177 @Override
1178 public void setup(Format fmt) {
1179 fmt.setOmitDeclaration(true);
1180 }
1181 };
1182 String rtdec = "<root />";
1183 checkOutput(doc, setup,
1184 rtdec + "\n",
1185 rtdec + "\n",
1186 rtdec + "\n",
1187 rtdec + "\n",
1188 rtdec + "\n");
1189 }
1190
1191 @Test
1192 public void testOutputDocumentFull() {
1193 DocType dt = new DocType("root");
1194 Comment comment = new Comment("comment");
1195 ProcessingInstruction pi = new ProcessingInstruction("jdomtest", "");
1196 Element root = new Element("root");
1197 Document doc = new Document();
1198 doc.addContent(dt);
1199 doc.addContent(comment);
1200 doc.addContent(pi);
1201 doc.addContent(root);
1202 String xmldec = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1203 String dtdec = "<!DOCTYPE root>";
1204 String commentdec = "<!--comment-->";
1205 String pidec = "<?jdomtest?>";
1206 String rtdec = "<root />";
1207 String lf = "\n";
1208 String dlf = usesrawxmlout ? "" : lf;
1209 checkOutput(doc,
1210 xmldec + lf + dtdec + commentdec + pidec + rtdec + lf,
1211 xmldec + lf + dtdec + commentdec + pidec + rtdec + lf,
1212 xmldec + lf + dtdec + dlf + commentdec + dlf + pidec + dlf + rtdec + lf,
1213 xmldec + lf + dtdec + dlf + commentdec + dlf + pidec + dlf + rtdec + lf,
1214 xmldec + lf + dtdec + dlf + commentdec + dlf + pidec + dlf + rtdec + lf);
1215 }
1216
1217 @Test
1218 public void testDeepNesting() {
1219 // need to get beyond 16 levels of XML.
1220 DocType dt = new DocType("root");
1221 Element root = new Element("root");
1222 Document doc = new Document();
1223 doc.addContent(dt);
1224 doc.addContent(root);
1225 String xmldec = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1226 String dtdec = "<!DOCTYPE root>";
1227 String lf = "\n";
1228
1229 StringBuilder raw = new StringBuilder();
1230 raw.append(xmldec).append(lf).append(dtdec);
1231 StringBuilder pretty = new StringBuilder();
1232 pretty.append(xmldec).append(lf).append(dtdec);
1233 if (!usesrawxmlout) {
1234 // most test systems use the XMLOutputter in raw mode to output
1235 // the results of the conversion. In Raw mode the XMLOutputter will
1236 // not make pretty content outside of the root element (but it will
1237 // put the XMLDeclaration on it's own line).
1238 // so, in the cases where the actual pretty format is used, we add
1239 // this newline after the DocType...
1240 pretty.append(lf);
1241 }
1242 raw.append("<root>");
1243 pretty.append("<root>");
1244 pretty.append(lf);
1245 final int depth = 40;
1246 int cnt = depth;
1247 Parent parent = root;
1248 StringBuilder indent = new StringBuilder();
1249 while (--cnt > 0) {
1250 Element emt = new Element("emt");
1251 parent.getContent().add(emt);
1252 parent = emt;
1253 raw.append("<emt>");
1254 indent.append(" ");
1255 pretty.append(indent.toString());
1256 pretty.append("<emt>");
1257 pretty.append(lf);
1258 }
1259
1260 parent.getContent().add(new Element("bottom"));
1261 raw.append("<bottom />");
1262 pretty.append(indent.toString());
1263 pretty.append(" <bottom />");
1264 pretty.append(lf);
1265
1266 cnt = depth;
1267 while (--cnt > 0) {
1268 raw.append("</emt>");
1269 pretty.append(indent.toString());
1270 pretty.append("</emt>");
1271 indent.setLength(indent.length() - 2);
1272 pretty.append(lf);
1273 }
1274 raw.append("</root>");
1275 raw.append(lf);
1276 pretty.append("</root>");
1277 pretty.append(lf);
1278
1279 checkOutput(doc, raw.toString(), raw.toString(), pretty.toString(), pretty.toString(), pretty.toString());
1280 }
1281
1282 @Test
1283 public void testOutputElementContent() {
1284 Element root = new Element("root");
1285 root.addContent(new Element("child"));
1286 checkOutput(root, "outputElementContent", Element.class, null, "<child />", "<child />", "<child />", "<child />", "<child />");
1287 }
1288
1289 @Test
1290 public void testOutputList() {
1291 List<Object> c = new ArrayList<Object>();
1292 c.add(new Element("root"));
1293 checkOutput(c, "output", List.class, null, "<root />", "<root />", "<root />", "<root />", "<root />");
1294 }
1295
1296
1297 @Test
1298 public void testOutputEscapedMixedMultiText() {
1299 // this test has mixed content (text-type and not text type).
1300 // and, it has a multi-text-type at the end.
1301 Element root = new Element("root");
1302 root.addContent(new Comment("Boo"));
1303 root.addContent(new Text(" xx "));
1304 root.addContent(new Text("<emb>"));
1305 root.addContent(new Text(" xx "));
1306 FormatSetup fs = new FormatSetup() {
1307 @Override
1308 public void setup(Format fmt) {
1309 fmt.setExpandEmptyElements(true);
1310 }
1311 };
1312 checkOutput(root, fs,
1313 "<root><!--Boo--> xx &lt;emb&gt; xx </root>",
1314 "<root><!--Boo-->xx &lt;emb&gt; xx</root>",
1315 "<root>\n <!--Boo-->\n xx &lt;emb&gt; xx\n</root>",
1316 "<root>\n <!--Boo-->\n xx &lt;emb&gt; xx\n</root>",
1317 "<root>\n <!--Boo-->\n xx &lt;emb&gt; xx \n</root>");
1318 }
1319
1320 @Test
1321 public void testOutputLotsOfMixedMultiText() {
1322 // this test has many text content members.
1323 Element root = new Element("root");
1324 StringBuilder sb = new StringBuilder();
1325 sb.append("<root>i");
1326 root.addContent("i");
1327 for (int i = 0; i < 100; i++) {
1328 sb.append("&ent;");
1329 sb.append(i);
1330 root.addContent(new EntityRef("ent"));
1331 root.addContent("" + i);
1332 }
1333 sb.append("</root>");
1334 FormatSetup fs = new FormatSetup() {
1335 @Override
1336 public void setup(Format fmt) {
1337 fmt.setExpandEmptyElements(true);
1338 }
1339 };
1340 final String expect = sb.toString();
1341 checkOutput(root, fs, expect, expect, expect, expect, expect);
1342 }
1343
1344
1345
1346 protected void checkOutput(Object content, String raw, String compact, String pretty, String tso, String trimfw) {
1347 Class<?> clazz = content.getClass();
1348 checkOutput(content, "output", clazz, null, raw, compact, pretty, tso, trimfw);
1349 }
1350
1351 protected void checkOutput(Object content, FormatSetup setup, String raw, String compact, String pretty, String tso, String trimfw) {
1352 Class<?> clazz = content.getClass();
1353 checkOutput(content, "output", clazz, setup, raw, compact, pretty, tso, trimfw);
1354 }
1355
1356 private interface OutputRunner {
1357 boolean matches(Class<?> claxx);
1358 String outputString(AbstractTestOutputter tester, Format format, Object data);
1359 }
1360
1361 private static abstract class AbstractRunner implements OutputRunner {
1362 private final Class<?> clazz;
1363
1364 public AbstractRunner(Class<?> claxx) {
1365 this.clazz = claxx;
1366 }
1367
1368 @Override
1369 public boolean matches(Class<?> claxx) {
1370 return this.clazz.isAssignableFrom(claxx);
1371 }
1372
1373 }
1374
1375 OutputRunner ECRUNNER = new AbstractRunner(Element.class) {
1376
1377 @Override
1378 public String outputString(AbstractTestOutputter tester, Format format,
1379 Object data) {
1380 return tester.outputElementContentString(format, (Element)data);
1381 }
1382 };
1383
1384
1385 private static final OutputRunner[] RUNNERS = {
1386
1387 new AbstractRunner(Document.class) {
1388
1389 @Override
1390 public String outputString(AbstractTestOutputter tester, Format format,
1391 Object data) {
1392 return tester.outputDocumentAsString(format, (Document)data);
1393 }
1394 },
1395
1396 new AbstractRunner(Element.class) {
1397
1398 @Override
1399 public String outputString(AbstractTestOutputter tester, Format format,
1400 Object data) {
1401 return tester.outputElementAsString(format, (Element)data);
1402 }
1403 },
1404
1405 new AbstractRunner(EntityRef.class) {
1406
1407 @Override
1408 public String outputString(AbstractTestOutputter tester, Format format,
1409 Object data) {
1410 return tester.outputEntityRefAsString(format, (EntityRef)data);
1411 }
1412 },
1413 new AbstractRunner(CDATA.class) {
1414
1415 @Override
1416 public String outputString(AbstractTestOutputter tester, Format format,
1417 Object data) {
1418 return tester.outputCDataAsString(format, (CDATA)data);
1419 }
1420 },
1421 new AbstractRunner(Comment.class) {
1422
1423 @Override
1424 public String outputString(AbstractTestOutputter tester, Format format,
1425 Object data) {
1426 return tester.outputCommentAsString(format, (Comment)data);
1427 }
1428 },
1429 new AbstractRunner(DocType.class) {
1430
1431 @Override
1432 public String outputString(AbstractTestOutputter tester, Format format,
1433 Object data) {
1434 return tester.outputDocTypeAsString(format, (DocType)data);
1435 }
1436 },
1437 new AbstractRunner(ProcessingInstruction.class) {
1438
1439 @Override
1440 public String outputString(AbstractTestOutputter tester, Format format,
1441 Object data) {
1442 return tester.outputPIAsString(format, (ProcessingInstruction)data);
1443 }
1444 },
1445 new AbstractRunner(Text.class) {
1446
1447 @Override
1448 public String outputString(AbstractTestOutputter tester, Format format,
1449 Object data) {
1450 return tester.outputTextAsString(format, (Text)data);
1451 }
1452 },
1453 new AbstractRunner(List.class) {
1454
1455 @SuppressWarnings("unchecked")
1456 @Override
1457 public String outputString(AbstractTestOutputter tester, Format format,
1458 Object data) {
1459 return tester.outputListAsString(format, (List<? extends Content>)data);
1460 }
1461 }
1462 };
1463
1464 /**
1465 * The following method will run the output data through each of the three base
1466 * formatters, raw, compact, and pretty. It will also run each of those
1467 * formatters as the outputString(content), output(content, OutputStream)
1468 * and output(content, Writer).
1469 *
1470 * The expectation is that the results of the three output forms (String,
1471 * OutputStream, and Writer) will be identical, and that it will match
1472 * the expected value for the appropriate formatter.
1473 *
1474 * @param content The content to output
1475 * @param methodprefix What the methods are called
1476 * @param clazz The class used as the parameter for the methods.
1477 * @param setup A callback mechanism to modify the formatters
1478 * @param raw What we expect the content to look like with the RAW format
1479 * @param compact What we expect the content to look like with the COMPACT format
1480 * @param pretty What we expect the content to look like with the PRETTY format
1481 * @param trimfw What we expect the content to look like with the TRIM_FULL_WHITE format
1482 */
1483 protected void checkOutput(Object content, String methodprefix, Class<?> clazz,
1484 FormatSetup setup, String raw, String compact, String pretty, String tso, String trimfw) {
1485 OutputRunner meth = getMyMethod(methodprefix, clazz);
1486
1487 String[] descn = new String[] {"Raw", "PrettyPreserve", "Compact", "Pretty", "PrettySpecifiedOnly", "TrimFullWhite"};
1488
1489 Format ftrimfw = Format.getPrettyFormat();
1490 ftrimfw.setTextMode(TextMode.TRIM_FULL_WHITE);
1491 Format fattspec = Format.getPrettyFormat();
1492 fattspec.setSpecifiedAttributesOnly(true);
1493 Format[] formats = new Format[] {
1494 getFormat(setup, Format.getRawFormat()),
1495 getFormat(setup, Format.getPrettyFormat().setTextMode(TextMode.PRESERVE)),
1496 getFormat(setup, Format.getCompactFormat()),
1497 getFormat(setup, Format.getPrettyFormat()),
1498 getFormat(setup, fattspec),
1499 getFormat(setup, ftrimfw)};
1500 String[] result = new String[] {raw, raw, compact, pretty, tso, trimfw};
1501
1502 for (int i = 0; i < result.length; i++) {
1503
1504 String mstring;
1505 try {
1506 mstring = meth.outputString(this, formats[i], content);
1507 } catch (Exception e) {
1508 e.printStackTrace();
1509 throw new IllegalStateException(e);
1510 }
1511 String msg = "outputString Format " + descn[i];
1512 assertEquals(msg, expect(result[i]), mstring);
1513 }
1514 }
1515
1516 protected Format getFormat(FormatSetup setup, Format input) {
1517 if (setup == null) {
1518 input.setLineSeparator("\n");
1519 return input;
1520 }
1521 input.setLineSeparator("\n");
1522 setup.setup(input);
1523 return input;
1524 }
1525
1526 private OutputRunner getMyMethod(String methpfx, Class<?> claxx) {
1527 if ("outputElementContent".equals(methpfx)) {
1528 return ECRUNNER;
1529 }
1530 for (OutputRunner runner : RUNNERS) {
1531 if (runner.matches(claxx)) {
1532 return runner;
1533 }
1534 }
1535 throw new IllegalStateException("Unable to find a runner for type " + claxx);
1536 }
1537
1538 }
0 package org.jdom.test.cases.output;
1
2 /* Please run replic.pl on me ! */
3 /**
4 * Please put a description of your test here.
5 *
6 * @author unascribed
7 * @version 0.1
8 */
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertTrue;
13 import static org.junit.Assert.fail;
14
15 import java.util.List;
16
17 import org.junit.Ignore;
18 import org.junit.Test;
19 import org.junit.runner.JUnitCore;
20 import org.w3c.dom.Attr;
21
22 import org.jdom.Attribute;
23 import org.jdom.CDATA;
24 import org.jdom.Comment;
25 import org.jdom.Content;
26 import org.jdom.DocType;
27 import org.jdom.Document;
28 import org.jdom.Element;
29 import org.jdom.EntityRef;
30 import org.jdom.JDOMException;
31 import org.jdom.Namespace;
32 import org.jdom.ProcessingInstruction;
33 import org.jdom.Text;
34 import org.jdom.adapters.DOMAdapter;
35 import org.jdom.adapters.JAXPDOMAdapter;
36 import org.jdom.input.DOMBuilder;
37 import org.jdom.output.DOMOutputter;
38 import org.jdom.output.Format;
39 import org.jdom.output.LineSeparator;
40 import org.jdom.output.XMLOutputter2;
41 import org.jdom.output.support.AbstractDOMOutputProcessor;
42 import org.jdom.output.support.DOMOutputProcessor;
43 import org.jdom.test.util.UnitTestUtil;
44
45 @SuppressWarnings("javadoc")
46 public final class TestDOMOutputter extends AbstractTestOutputter {
47
48 /**
49 * The main method runs all the tests in the text ui
50 */
51 public static void main (String args[])
52 {
53 JUnitCore.runClasses(TestDOMOutputter.class);
54 }
55
56 private interface DOMSetup {
57 public DOMOutputter buildOutputter();
58 }
59
60 public TestDOMOutputter() {
61 super(true, true, false, false, true);
62 }
63
64 @SuppressWarnings("deprecation")
65 @Test
66 public void test_ForceNamespaces() throws JDOMException {
67 Document doc = new Document();
68 Element root = new Element("root");
69 Element el = new Element("a");
70 el.setText("abc");
71 root.addContent(el);
72 doc.setRootElement(root);
73
74 DOMOutputter out = new DOMOutputter();
75 // deprecated stuff..
76 assertTrue(out.getForceNamespaceAware());
77 out.setForceNamespaceAware(false);
78 assertTrue(out.getForceNamespaceAware());
79 org.w3c.dom.Document dom = out.output(doc);
80 org.w3c.dom.Element domel = dom.getDocumentElement();
81 //System.out.println("Dom impl: "+ domel.getClass().getName());
82 assertNotNull(domel.getLocalName());
83 }
84
85 private void roundTrip(Document doc) {
86 roundTrip(null, doc);
87 }
88
89 private void roundTrip(DOMSetup setup, Document doc) {
90 XMLOutputter2 xout = new XMLOutputter2(Format.getRawFormat());
91 // create a String representation of the input.
92 if (doc.hasRootElement()) {
93 UnitTestUtil.normalizeAttributes(doc.getRootElement());
94 }
95 String expect = xout.outputString(doc);
96
97 String actual = null;
98 try {
99 // convert the input to a DOM document
100 DOMOutputter domout = setup == null ? new DOMOutputter() : setup.buildOutputter();
101 org.w3c.dom.Document outonce = domout.output(doc);
102
103 // convert the DOM document back again.
104 DOMBuilder builder = new DOMBuilder();
105 Document backagain = builder.build(outonce);
106
107 // get a String representation of the round-trip.
108 if (backagain.hasRootElement()) {
109 UnitTestUtil.normalizeAttributes(backagain.getRootElement());
110 }
111 actual = xout.outputString(backagain);
112 } catch (JDOMException e) {
113 e.printStackTrace();
114 fail("Failed to round-trip the document with exception: "
115 + e.getMessage() + "\n" + expect);
116 }
117 assertEquals(expect, actual);
118 }
119
120 @Test
121 public void testDOMAdapter() {
122 Document doc = new Document(new Element("root"));
123 DOMSetup setup = new DOMSetup() {
124 @Override
125 public DOMOutputter buildOutputter() {
126 return new DOMOutputter();
127 }
128 };
129 roundTrip(setup, doc);
130 }
131
132 @Test
133 public void testDOMOutputDocumentSimple() {
134 Document doc = new Document();
135 doc.addContent(new Element("root"));
136 roundTrip(doc);
137 }
138
139 @Test
140 public void testDOMOutputDocumentFull() {
141 Document doc = new Document();
142 doc.addContent(new DocType("root"));
143 doc.addContent(new Comment("This is a document"));
144 doc.addContent(new ProcessingInstruction("jdomtest", ""));
145 doc.addContent(new Element("root"));
146 roundTrip(doc);
147 }
148
149 @Test
150 public void testDOMOutputElementAttributes() {
151 Element emt = new Element("root");
152 emt.setAttribute("att", "val");
153 Document doc = new Document(emt);
154 roundTrip(doc);
155 }
156
157 @Test
158 public void testDOMOutputElementNamespaces() {
159 Element emt = new Element("root", Namespace.getNamespace("ns", "myns"));
160 Namespace ans = Namespace.getNamespace("ans", "attributens");
161 emt.addNamespaceDeclaration(ans);
162 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
163 emt.setAttribute(new Attribute("att", "val", ans));
164 Document doc = new Document(emt);
165 roundTrip(doc);
166 }
167
168 @Test
169 public void testOutputElementNamespaceNoPrefix() {
170 Element emt = new Element("root", Namespace.getNamespace("", "myns"));
171 Namespace ans = Namespace.getNamespace("ans", "attributens");
172 emt.addNamespaceDeclaration(ans);
173 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
174 emt.setAttribute(new Attribute("att", "val", ans));
175 Document doc = new Document(emt);
176 roundTrip(doc);
177 }
178
179 @Test
180 public void testOutputElementNamespacesForceNS() {
181 Element emt = new Element("root", Namespace.getNamespace("ns", "myns"));
182 Namespace ans = Namespace.getNamespace("ans", "attributens");
183 emt.addNamespaceDeclaration(ans);
184 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
185 emt.setAttribute(new Attribute("att", "val", ans));
186 Document doc = new Document(emt);
187 DOMSetup setup = new DOMSetup() {
188 @SuppressWarnings("deprecation")
189 @Override
190 public DOMOutputter buildOutputter() {
191 DOMOutputter dom = new DOMOutputter();
192 dom.setForceNamespaceAware(true);
193 return dom;
194 }
195 };
196 roundTrip(setup, doc);
197 }
198
199 @Test
200 public void testOutputElementFull() {
201 Element emt = new Element("root");
202 emt.setAttribute("att1", "val1");
203 emt.setAttribute("att2", "val2");
204 emt.addContent(new Comment("comment"));
205 emt.addContent(new Text("txt"));
206 emt.addContent(new ProcessingInstruction("jdomtest", ""));
207 emt.addContent(new Element("child"));
208 emt.addContent(new EntityRef("ref"));
209 emt.addContent(new CDATA("cdata"));
210 Document doc = new Document(emt);
211 roundTrip(doc);
212 }
213
214 @Test
215 public void testOutputElementFullForceNS() {
216 Element emt = new Element("root");
217 emt.setAttribute("att1", "val1");
218 emt.setAttribute("att2", "val2");
219 emt.addContent(new Comment("comment"));
220 emt.addContent(new Text("txt"));
221 emt.addContent(new ProcessingInstruction("jdomtest", ""));
222 emt.addContent(new Element("child"));
223 emt.addContent(new EntityRef("ref"));
224 emt.addContent(new CDATA("cdata"));
225 Document doc = new Document(emt);
226 DOMSetup setup = new DOMSetup() {
227 @SuppressWarnings("deprecation")
228 @Override
229 public DOMOutputter buildOutputter() {
230 DOMOutputter dom = new DOMOutputter();
231 dom.setForceNamespaceAware(true);
232 return dom;
233 }
234 };
235 roundTrip(setup, doc);
236 }
237
238 @Test
239 public void testWithDocType() {
240 DocType dt = new DocType("root");
241 dt.setInternalSubset("<!ELEMENT root (#PCDATA)>");
242 Element root = new Element("root");
243 Document doc = new Document(root, dt);
244
245 roundTrip(doc);
246 }
247
248
249 @Test
250 public void testGetSetFormat() {
251 DOMOutputter dout = new DOMOutputter();
252 Format def = dout.getFormat();
253 assertTrue(def != null);
254 Format f = Format.getPrettyFormat();
255 dout.setFormat(f);
256 assertTrue(f == dout.getFormat());
257 dout.setFormat(null);
258 TestFormat.checkEquals(def, dout.getFormat());
259 }
260
261 @Test
262 public void testGetSetDOMOutputProcessor() {
263 DOMOutputProcessor dop = new AbstractDOMOutputProcessor() {
264 // nothing.
265 };
266
267 DOMOutputter dout = new DOMOutputter();
268 DOMOutputProcessor def = dout.getDOMOutputProcessor();
269 assertTrue(def != null);
270 dout.setDOMOutputProcessor(dop);
271 assertTrue(dop == dout.getDOMOutputProcessor());
272 dout.setDOMOutputProcessor(null);
273 assertEquals(def, dout.getDOMOutputProcessor());
274 }
275
276 @Test
277 public void testGetSetDOMAdapter() {
278 DOMAdapter dop = new JAXPDOMAdapter();
279
280 DOMOutputter dout = new DOMOutputter();
281 DOMAdapter def = dout.getDOMAdapter();
282 assertTrue(def != null);
283 dout.setDOMAdapter(dop);
284 assertTrue(dop == dout.getDOMAdapter());
285 dout.setDOMAdapter(null);
286 assertEquals(def, dout.getDOMAdapter());
287 }
288
289 @Test
290 public void testFullConstructor() {
291 DOMOutputProcessor dop = new AbstractDOMOutputProcessor() {
292 // nothing.
293 };
294
295 DOMAdapter dap = new JAXPDOMAdapter();
296
297 Format fmt = Format.getPrettyFormat();
298
299 DOMOutputter out = new DOMOutputter(null, null, null);
300
301 DOMOutputProcessor defop = out.getDOMOutputProcessor();
302 DOMAdapter defap = out.getDOMAdapter();
303 Format defmt = out.getFormat();
304
305 out = new DOMOutputter(dap, fmt, dop);
306
307 assertTrue(dap == out.getDOMAdapter());
308 assertTrue(dop == out.getDOMOutputProcessor());
309 assertTrue(fmt == out.getFormat());
310
311 out = new DOMOutputter(null, null, null);
312 assertTrue(defap == out.getDOMAdapter());
313 assertTrue(defop == out.getDOMOutputProcessor());
314 TestFormat.checkEquals(defmt , out.getFormat());
315 }
316
317 @Test
318 public void testDOMOutputProcessorConstructor() {
319 DOMOutputProcessor dop = new AbstractDOMOutputProcessor() {
320 // nothing to add
321 };
322
323 DOMOutputter out = new DOMOutputter((DOMOutputProcessor)null);
324
325 DOMOutputProcessor defap = out.getDOMOutputProcessor();
326
327 out = new DOMOutputter(dop);
328
329 assertTrue(dop == out.getDOMOutputProcessor());
330
331 out = new DOMOutputter((DOMOutputProcessor)null);
332 assertTrue(defap == out.getDOMOutputProcessor());
333 }
334
335 @Test
336 public void testDOMAdapterConstructor() {
337 DOMAdapter dap = new JAXPDOMAdapter();
338
339 DOMOutputter out = new DOMOutputter((DOMAdapter)null);
340
341 DOMAdapter defap = out.getDOMAdapter();
342
343 out = new DOMOutputter(dap);
344
345 assertTrue(dap == out.getDOMAdapter());
346
347 out = new DOMOutputter((DOMAdapter)null);
348 assertTrue(defap == out.getDOMAdapter());
349 }
350
351 @Test
352 @SuppressWarnings("deprecation")
353 public void testDOMAdapterNameConstructor() {
354 DOMOutputter out = new DOMOutputter((String)null);
355 assertTrue(out.getDOMAdapter() instanceof JAXPDOMAdapter);
356 out = new DOMOutputter(JAXPDOMAdapter.class.getName());
357 assertTrue(out.getDOMAdapter() instanceof JAXPDOMAdapter);
358 }
359
360 @Test
361 public void testOutputAttribute() throws JDOMException {
362 DOMOutputter out = getOutputter(Format.getRawFormat());
363 org.w3c.dom.Document domdoc = out.getDOMAdapter().createDocument();
364 Attribute att = new Attribute("name", "val");
365
366 Attr doma = out.output(att);
367 assertEquals("name", doma.getNodeName());
368 assertEquals("name", doma.getLocalName());
369 assertEquals("val", doma.getNodeValue());
370 // Android can have "" values, xerces has null. Technically it is implementation dependant
371 assertTrue(null == doma.getPrefix() || "".equals(doma.getPrefix()));
372 // Android can have "" values, xerces has null. Technically it is implementation dependant
373 assertTrue(null == doma.getNamespaceURI() || "".equals(doma.getNamespaceURI()));
374 assertTrue(domdoc != doma.getOwnerDocument());
375
376 doma = out.output(domdoc, att);
377 assertEquals("name", doma.getNodeName());
378 assertEquals("name", doma.getLocalName());
379 assertEquals("val", doma.getNodeValue());
380 assertTrue(null == doma.getPrefix() || "".equals(doma.getPrefix()));
381 assertTrue(null == doma.getNamespaceURI() || "".equals(doma.getNamespaceURI()));
382 assertTrue(domdoc == doma.getOwnerDocument());
383
384 att = new Attribute("name", "val", Namespace.getNamespace("ns", "http://jdom.org/junit/ns"));
385
386 doma = out.output(att);
387 assertEquals("ns:name", doma.getNodeName());
388 assertEquals("name", doma.getLocalName());
389 assertEquals("val", doma.getNodeValue());
390 assertEquals("ns", doma.getPrefix());
391 assertEquals("http://jdom.org/junit/ns", doma.getNamespaceURI());
392 assertTrue(domdoc != doma.getOwnerDocument());
393
394 doma = out.output(domdoc, att);
395 assertEquals("ns:name", doma.getNodeName());
396 assertEquals("name", doma.getLocalName());
397 assertEquals("val", doma.getNodeValue());
398 assertEquals("ns", doma.getPrefix());
399 assertEquals("http://jdom.org/junit/ns", doma.getNamespaceURI());
400 assertTrue(domdoc == doma.getOwnerDocument());
401
402 }
403
404 private final DOMOutputter getOutputter(Format format) {
405 DOMOutputter outputter = new DOMOutputter();
406 outputter.setFormat(format);
407 return outputter;
408 }
409
410 private final String nodeToString (Object input) {
411 try {
412 // Do not use Transforms, messes up end-of-lines, etc.
413 // instead, reuse the DOMBuilder and convert back to string using
414 // XMLOutputter.
415 if (input == null) {
416 return "";
417 }
418 XMLOutputter2 xout = new XMLOutputter2();
419 xout.getFormat().setLineSeparator(LineSeparator.NL);
420 DOMBuilder builder = new DOMBuilder();
421
422 if (input instanceof List) {
423 StringBuilder sb = new StringBuilder();
424 for (Object o : (List<?>)input) {
425 sb.append(nodeToString(o));
426 }
427 return sb.toString();
428 }
429 if (input instanceof org.w3c.dom.Document) {
430 return xout.outputString(builder.build((org.w3c.dom.Document)input));
431 }
432 if (input instanceof org.w3c.dom.CDATASection) {
433 return xout.outputString(builder.build((org.w3c.dom.CDATASection)input));
434 }
435 if (input instanceof org.w3c.dom.Comment) {
436 return xout.outputString(builder.build((org.w3c.dom.Comment)input));
437 }
438 if (input instanceof org.w3c.dom.DocumentType) {
439 return xout.outputString(builder.build((org.w3c.dom.DocumentType)input));
440 }
441 if (input instanceof org.w3c.dom.Element) {
442 return xout.outputString(builder.build((org.w3c.dom.Element)input));
443 }
444 if (input instanceof org.w3c.dom.EntityReference) {
445 return xout.outputString(builder.build((org.w3c.dom.EntityReference)input));
446 }
447 if (input instanceof org.w3c.dom.ProcessingInstruction) {
448 return xout.outputString(builder.build((org.w3c.dom.ProcessingInstruction)input));
449 }
450 if (input instanceof org.w3c.dom.Text) {
451 return xout.outputString(builder.build((org.w3c.dom.Text)input));
452 }
453
454 return null;
455 // TransformerFactory factory = TransformerFactory.newInstance();
456 // Transformer transformer = factory.newTransformer();
457 // transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator","\n");
458 // StringWriter writer = new StringWriter();
459 // for (Node node : nodes) {
460 // if (node instanceof org.w3c.dom.Document) {
461 // ((org.w3c.dom.Document)node).setXmlStandalone(true);
462 // transformer.setOutputProperty("omit-xml-declaration", "no");
463 // } else {
464 // transformer.setOutputProperty("omit-xml-declaration", "yes");
465 // }
466 // Result result = new StreamResult(writer);
467 // Source source = new DOMSource(node);
468 // transformer.transform(source, result);
469 // }
470 // writer.close();
471 // String xml = writer.toString();
472 // return xml;
473 } catch (Exception e) {
474 throw new IllegalStateException(e);
475 }
476 }
477
478 @Override
479 public String outputDocumentAsString(Format format, Document doc) {
480 try {
481 DOMOutputter out = getOutputter(format);
482 String opta = nodeToString(out.output(doc));
483 return opta;
484 } catch (JDOMException e) {
485 UnitTestUtil.failException("Unexpected JDOMException", e);
486 return null;
487 }
488 }
489
490 @Override
491 public String outputDocTypeAsString(Format format, DocType doctype) {
492 try {
493 DOMOutputter out = getOutputter(format);
494 // org.w3c.dom.Document doc = out.getDOMAdapter().createDocument();
495 String opta = nodeToString(out.output(doctype));
496 // String optb = nodeToString(out.output(doc, doctype));
497 // assertEquals(opta, optb);
498 return opta;
499 } catch (JDOMException e) {
500 UnitTestUtil.failException("Unexpected JDOMException", e);
501 return null;
502 }
503 }
504
505 @Override
506 public String outputElementAsString(Format format, Element element) {
507 try {
508 DOMOutputter out = getOutputter(format);
509 org.w3c.dom.Document doc = out.getDOMAdapter().createDocument();
510 String opta = nodeToString(out.output(element));
511 String optb = nodeToString(out.output(doc, element));
512 assertEquals(opta, optb);
513 return opta;
514 } catch (JDOMException e) {
515 UnitTestUtil.failException("Unexpected JDOMException", e);
516 return null;
517 }
518 }
519
520 @Override
521 public String outputListAsString(Format format, List<? extends Content> list) {
522 try {
523 DOMOutputter out = getOutputter(format);
524 org.w3c.dom.Document doc = out.getDOMAdapter().createDocument();
525 String opta = nodeToString(out.output(list));
526 String optb = nodeToString(out.output(doc, list));
527 assertEquals(opta, optb);
528 return opta;
529 } catch (JDOMException e) {
530 UnitTestUtil.failException("Unexpected JDOMException", e);
531 return null;
532 }
533 }
534
535 @Override
536 public String outputCDataAsString(Format format, CDATA cdata) {
537 try {
538 DOMOutputter out = getOutputter(format);
539 org.w3c.dom.Document doc = out.getDOMAdapter().createDocument();
540 String opta = nodeToString(out.output(cdata));
541 String optb = nodeToString(out.output(doc, cdata));
542 assertEquals(opta, optb);
543 return opta;
544 } catch (JDOMException e) {
545 UnitTestUtil.failException("Unexpected JDOMException", e);
546 return null;
547 }
548 }
549
550 @Override
551 public String outputTextAsString(Format format, Text text) {
552 try {
553 DOMOutputter out = getOutputter(format);
554 org.w3c.dom.Document doc = out.getDOMAdapter().createDocument();
555 String opta = nodeToString(out.output(text));
556 String optb = nodeToString(out.output(doc, text));
557 assertEquals(opta, optb);
558 return opta;
559 } catch (JDOMException e) {
560 UnitTestUtil.failException("Unexpected JDOMException", e);
561 return null;
562 }
563 }
564
565 @Override
566 public String outputCommentAsString(Format format, Comment comment) {
567 try {
568 DOMOutputter out = getOutputter(format);
569 org.w3c.dom.Document doc = out.getDOMAdapter().createDocument();
570 String opta = nodeToString(out.output(comment));
571 String optb = nodeToString(out.output(doc, comment));
572 assertEquals(opta, optb);
573 return opta;
574 } catch (JDOMException e) {
575 UnitTestUtil.failException("Unexpected JDOMException", e);
576 return null;
577 }
578 }
579
580 @Override
581 public String outputPIAsString(Format format, ProcessingInstruction pi) {
582 try {
583 DOMOutputter out = getOutputter(format);
584 org.w3c.dom.Document doc = out.getDOMAdapter().createDocument();
585 String opta = nodeToString(out.output(pi));
586 String optb = nodeToString(out.output(doc, pi));
587 assertEquals(opta, optb);
588 return opta;
589 } catch (JDOMException e) {
590 UnitTestUtil.failException("Unexpected JDOMException", e);
591 return null;
592 }
593 }
594
595 @Override
596 public String outputEntityRefAsString(Format format, EntityRef entity) {
597 try {
598 DOMOutputter out = getOutputter(format);
599 org.w3c.dom.Document doc = out.getDOMAdapter().createDocument();
600 String opta = nodeToString(out.output(entity));
601 String optb = nodeToString(out.output(doc, entity));
602 assertEquals(opta, optb);
603 return opta;
604 } catch (JDOMException e) {
605 UnitTestUtil.failException("Unexpected JDOMException", e);
606 return null;
607 }
608 }
609
610 @Override
611 public String outputElementContentString(Format format, Element element) {
612 try {
613 DOMOutputter out = getOutputter(format);
614 org.w3c.dom.Document doc = out.getDOMAdapter().createDocument();
615 String opta = nodeToString(out.output(element.getContent()));
616 String optb = nodeToString(out.output(doc, element.getContent()));
617 assertEquals(opta, optb);
618 return opta;
619 } catch (JDOMException e) {
620 UnitTestUtil.failException("Unexpected JDOMException", e);
621 return null;
622 }
623 }
624
625 @Override
626 @Ignore // we can't control expand in DOM.
627 public void testOutputElementExpandEmpty() {
628 // pass this test always.
629 }
630
631 @Override
632 @Ignore // we can't control expand in DOM.
633 public void testOutputElementMultiAllWhiteExpandEmpty() {
634 // nothing.
635 }
636
637 @Override
638 @Ignore // we can't control expand in DOM.
639 public void testOutputDocumentOmitEncoding() {
640 // nothing.
641 }
642
643 @Override
644 @Ignore // we can't control expand in DOM.
645 public void testOutputDocumentOmitDeclaration() {
646 // nothing.
647 }
648
649 }
0 package org.jdom.test.cases.output;
1
2 /* Please run replic.pl on me ! */
3 /**
4 * Tests that the namespace of xmlns attributes from DOMOutputter are correct
5 *
6 * @author unascribed
7 * @version 0.1
8 */
9
10 import org.jdom.Element;
11 import org.jdom.JDOMConstants;
12 import org.jdom.input.DOMBuilder;
13 import org.jdom.input.SAXBuilder;
14 import org.jdom.output.DOMOutputter;
15
16 import org.w3c.dom.Document;
17 import org.xml.sax.InputSource;
18
19 import javax.xml.parsers.DocumentBuilder;
20 import javax.xml.parsers.DocumentBuilderFactory;
21 import java.io.StringReader;
22
23 import org.junit.Test;
24 import static org.junit.Assert.assertEquals;
25 import org.junit.runner.JUnitCore;
26
27 @SuppressWarnings("javadoc")
28 public class TestDOMOutputterXmlnsNamespaces
29 {
30 /**
31 * The XML document to test - this document
32 */
33 private static final String XML = "<el xmlns:test=\"urn:test\" />";
34
35 /**
36 * The main method runs all the tests in the text ui
37 */
38 public static void main (String args[])
39 {
40 JUnitCore.runClasses(TestDOMOutputterXmlnsNamespaces.class);
41 }
42
43
44 /**
45 * Parse the XML using DOM
46 *
47 * @throws Exception
48 */
49 @Test
50 public void testDocumentBuilderSource() throws Exception
51 {
52 org.w3c.dom.Element element = parseDOM(XML);
53
54 final String namespace = element.getAttributeNode("xmlns:test").getNamespaceURI();
55
56 assertEquals("DocumentBuilder output", JDOMConstants.NS_URI_XMLNS, namespace);
57 }
58
59
60 /**
61 * Parse the XML using JDOM, convert to DOM
62 *
63 * @throws Exception
64 */
65 @Test
66 public void testJdomToDom() throws Exception
67 {
68 org.w3c.dom.Element element = jdomToDom(parseJDOM(XML)); // load JDOM and convert to DOM
69
70 final String namespace = element.getAttributeNode("xmlns:test").getNamespaceURI();
71
72 assertEquals("SAXBuilder->DOMOutputter output", JDOMConstants.NS_URI_XMLNS, namespace);
73 }
74
75
76 /**
77 * Parse the XML using DOM, then convert to JDOM and then finally back to DOM
78 *
79 * @throws Exception
80 */
81
82 @Test
83 public void testDomToJdomToDom() throws Exception
84 {
85 org.w3c.dom.Element element = jdomToDom(domToJdom(parseDOM(XML))); // load DOM, convert to JDOM and back to DOM
86
87 final String namespace = element.getAttributeNode("xmlns:test").getNamespaceURI();
88
89 assertEquals("DocumentBuilder->DOMBuilder->DOMOutputter output", JDOMConstants.NS_URI_XMLNS, namespace);
90 }
91
92
93 private Element parseJDOM(String xml) throws Exception
94 {
95 final StringReader src = new StringReader(xml);
96
97 return new SAXBuilder().build(src).getRootElement();
98 }
99
100
101 private org.w3c.dom.Element parseDOM(String xml) throws Exception
102 {
103 InputSource src = new InputSource(new StringReader(xml));
104
105 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
106 factory.setNamespaceAware(true);
107
108 DocumentBuilder documentBuilder = factory.newDocumentBuilder();
109
110 Document result = documentBuilder.parse(src);
111
112 return result.getDocumentElement();
113 }
114
115
116 /**
117 * Converts a JDOM Element to a DOM Element
118 *
119 * @param element
120 *
121 * @return
122 *
123 * @throws Exception
124 */
125 private org.w3c.dom.Element jdomToDom(org.jdom.Element element) throws Exception
126 {
127 return new DOMOutputter().output(element);
128 }
129
130
131 /**
132 * Converts a DOM Element to a JDOM Element
133 *
134 * @param element
135 *
136 * @return
137 *
138 * @throws Exception
139 */
140 private org.jdom.Element domToJdom(org.w3c.dom.Element element) throws Exception
141 {
142 final DOMBuilder builder = new DOMBuilder();
143
144 return builder.build(element);
145 }
146 }
0 package org.jdom.test.cases.output;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertTrue;
5
6 import org.jdom.output.EscapeStrategy;
7 import org.jdom.output.Format;
8 import org.jdom.output.Format.TextMode;
9 import org.junit.Test;
10
11 @SuppressWarnings("javadoc")
12 public class TestFormat {
13
14 public static final void checkEquals(Format a, Format b) {
15 assertEquals("Expect formatters to have the same Encoding",
16 a.getEncoding(), b.getEncoding());
17 //assertEquals("Expect formatters to have the same EscapeStrategy",
18 // a.getEscapeStrategy(), b.getEscapeStrategy());
19 assertEquals("Expect formatters to have the same ExpandEmptyElements",
20 a.getExpandEmptyElements(), b.getExpandEmptyElements());
21 assertEquals("Expect formatters to have the same TrAXEscapingPIs",
22 a.getIgnoreTrAXEscapingPIs(), b.getIgnoreTrAXEscapingPIs());
23 assertEquals("Expect formatters to have the same Indent",
24 a.getIndent(), b.getIndent());
25 assertEquals("Expect formatters to have the same LineSeparator",
26 a.getLineSeparator(), b.getLineSeparator());
27 assertEquals("Expect formatters to have the same OmitDeclaration",
28 a.getOmitDeclaration(), b.getOmitDeclaration());
29 assertEquals("Expect formatters to have the same OmitEncoding",
30 a.getOmitEncoding(), b.getOmitEncoding());
31 assertEquals("Expect formatters to have the same TextMode",
32 a.getTextMode(), b.getTextMode());
33
34 }
35
36
37
38 @Test
39 public void testGetRawFormat() {
40 Format mine = Format.getRawFormat();
41 assertTrue(mine.getTextMode() == TextMode.PRESERVE);
42 assertEquals(mine.getEncoding(), "UTF-8");
43 }
44
45 @Test
46 public void testGetPrettyFormat() {
47 Format mine = Format.getPrettyFormat();
48 assertTrue(mine.getTextMode() == TextMode.TRIM);
49 assertEquals(mine.getEncoding(), "UTF-8");
50 }
51
52 @Test
53 public void testGetCompactFormat() {
54 Format mine = Format.getCompactFormat();
55 assertTrue(mine.getTextMode() == TextMode.NORMALIZE);
56 assertEquals(mine.getEncoding(), "UTF-8");
57 }
58
59 @Test
60 public void testEscapeStrategy() {
61 EscapeStrategy es = new EscapeStrategy() {
62 @Override
63 public boolean shouldEscape(char ch) {
64 return false;
65 }
66 };
67 Format mine = Format.getRawFormat();
68 assertTrue(mine.getEscapeStrategy() != es);
69 mine.setEscapeStrategy(es);
70 assertTrue(mine.getEscapeStrategy() == es);
71 }
72
73 @Test
74 public void testLineSeparator() {
75 assertEquals("\r\n", Format.getPrettyFormat().getLineSeparator());
76 assertEquals("\r\n", Format.getCompactFormat().getLineSeparator());
77
78 Format mine = Format.getRawFormat();
79 assertEquals("\r\n", mine.getLineSeparator());
80 mine.setLineSeparator(" \n ");
81 assertEquals(" \n ", mine.getLineSeparator());
82 }
83
84 @Test
85 public void testOmitEncoding() {
86 assertFalse(Format.getPrettyFormat().getOmitEncoding());
87 assertFalse(Format.getCompactFormat().getOmitEncoding());
88 Format mine = Format.getRawFormat();
89 assertFalse(mine.getOmitEncoding());
90 mine.setOmitEncoding(true);
91 assertTrue (mine.getOmitEncoding());
92 }
93
94 @Test
95 public void testOmitDeclaration() {
96 assertFalse(Format.getPrettyFormat().getOmitDeclaration());
97 assertFalse(Format.getCompactFormat().getOmitDeclaration());
98 Format mine = Format.getRawFormat();
99 assertFalse(mine.getOmitDeclaration());
100 mine.setOmitDeclaration(true);
101 assertTrue (mine.getOmitDeclaration());
102 }
103
104 @Test
105 public void testSpecifiedAttributesOnly() {
106 assertFalse(Format.getPrettyFormat().isSpecifiedAttributesOnly());
107 assertFalse(Format.getCompactFormat().isSpecifiedAttributesOnly());
108 Format mine = Format.getRawFormat();
109 assertFalse(mine.isSpecifiedAttributesOnly());
110 mine.setSpecifiedAttributesOnly(true);
111 assertTrue (mine.isSpecifiedAttributesOnly());
112 }
113
114 @Test
115 public void testExpandEmptyElements() {
116 assertFalse(Format.getPrettyFormat().getExpandEmptyElements());
117 assertFalse(Format.getCompactFormat().getExpandEmptyElements());
118 Format mine = Format.getRawFormat();
119 assertFalse(mine.getExpandEmptyElements());
120 mine.setExpandEmptyElements(true);
121 assertTrue (mine.getExpandEmptyElements());
122 }
123
124 @Test
125 public void testIgnoreTrAXEscapingPIs() {
126 assertFalse(Format.getPrettyFormat().getIgnoreTrAXEscapingPIs());
127 assertFalse(Format.getCompactFormat().getIgnoreTrAXEscapingPIs());
128 Format mine = Format.getRawFormat();
129 assertFalse(mine.getIgnoreTrAXEscapingPIs());
130 mine.setIgnoreTrAXEscapingPIs(true);
131 assertTrue (mine.getIgnoreTrAXEscapingPIs());
132 }
133
134 @Test
135 public void testTextMode() {
136 assertEquals(TextMode.TRIM, Format.getPrettyFormat().getTextMode());
137 assertEquals(TextMode.NORMALIZE, Format.getCompactFormat().getTextMode());
138
139 Format mine = Format.getRawFormat();
140 assertEquals(TextMode.PRESERVE, mine.getTextMode());
141 mine.setTextMode(TextMode.TRIM_FULL_WHITE);
142 assertEquals(TextMode.TRIM_FULL_WHITE, mine.getTextMode());
143
144 assertEquals("TRIM", TextMode.TRIM.toString());
145 }
146
147 @Test
148 public void testIndent() {
149 assertEquals(" ", Format.getPrettyFormat().getIndent());
150 assertEquals(null, Format.getCompactFormat().getIndent());
151
152 Format mine = Format.getRawFormat();
153 assertEquals(null, mine.getIndent());
154 mine.setIndent(" ");
155 assertEquals(" ", mine.getIndent());
156 }
157
158 @Test
159 public void testEncoding() {
160 assertEquals("UTF-8", Format.getPrettyFormat().getEncoding());
161 assertEquals("UTF-8", Format.getCompactFormat().getEncoding());
162
163 Format mine = Format.getRawFormat();
164 assertEquals("UTF-8", mine.getEncoding());
165 mine.setEncoding("US-ASCII");
166 assertEquals("US-ASCII", mine.getEncoding());
167 }
168
169 @Test
170 public void testClone() {
171 Format mine = Format.getRawFormat();
172 Format clone = mine.clone();
173 assertFalse(mine == clone);
174 checkEquals(mine, clone);
175 }
176
177 @Test
178 public void test7BitEscapes() {
179 checkBitEscape("US-ASCII",
180 new char[] {'a', 'b', '\n', '!'},
181 new char[] {(char)128, (char)255, (char)1234});
182 }
183
184 @Test
185 public void testASCIIBitEscapes() {
186 // ISO646-US is another name for US-ASCII
187 // JDOM does not know that, but Java does.
188 checkBitEscape("ISO646-US",
189 new char[] {'a', 'b', '\n', '!'},
190 new char[] {(char)128, (char)255, (char)1234});
191 }
192
193 @Test
194 public void test8BitEscapes() {
195 checkBitEscape("Latin1",
196 new char[] {'a', 'b', '\n', '!', (char)128, (char)255},
197 new char[] {(char)1234});
198 }
199
200 @Test
201 public void test16BitEscapes() {
202 checkBitEscape("UTF-16",
203 new char[] {'a', 'b', '\n', '!', (char)128, (char)255, (char)1234},
204 new char[] {(char)0xD800});
205 }
206
207 @Test
208 public void testCharsetEncodingEscapes() {
209 checkBitEscape("windows-1252",
210 new char[] {'a', 'b', '\n', '!', (char)127, (char)255},
211 new char[] {(char)0xD800, (char)1234});
212 }
213
214 @Test
215 public void testIllegalEncodingEscapes() {
216 checkBitEscape("junk",
217 new char[] {'a', 'b', '\n', '!', (char)128, (char)255, (char)1234},
218 new char[] {(char)0xD800});
219 }
220
221 private void checkBitEscape(String encoding,
222 char[] keep, char[] escape) {
223 Format form = Format.getPrettyFormat();
224 form.setEncoding(encoding);
225 EscapeStrategy es = form.getEscapeStrategy();
226 for (char ch : keep) {
227 assertFalse("Should Not Escape " + ch, es.shouldEscape(ch));
228 }
229 for (char ch : escape) {
230 assertTrue("Should Escape " + ch, es.shouldEscape(ch));
231 }
232 }
233
234 private void checkTrim(String base, String both, String left, String right, String compact) {
235 assertEquals(both, Format.trimBoth(base));
236 assertEquals(left, Format.trimLeft(base));
237 assertEquals(right, Format.trimRight(base));
238 assertEquals(compact, Format.compact(base));
239 }
240
241 @Test
242 public void testTrimming() {
243 checkTrim("", "", "", "", "");
244 checkTrim(" ", "", "", "", "");
245 checkTrim("x", "x", "x", "x", "x");
246 checkTrim("foo", "foo", "foo", "foo", "foo");
247 checkTrim(" \r\n ", "", "", "", "");
248 checkTrim(" \rx\n ", "x", "x\n ", " \rx", "x");
249 checkTrim(" \rx \t y\n ", "x \t y", "x \t y\n ", " \rx \t y", "x y");
250 }
251
252 private void checkEscapes(String eol, String base, String txt, String att) {
253 EscapeStrategy strategy = Format.getPrettyFormat().getEscapeStrategy();
254 assertEquals(txt, Format.escapeText(strategy, eol, base));
255 assertEquals(att, Format.escapeAttribute(strategy, base));
256 }
257
258 @Test
259 public void testEscapeText() {
260 checkEscapes(null, "", "", "");
261 checkEscapes(null, " \n ", " \n ", " &#xA; ");
262 checkEscapes("\r\n", " \n ", " \r\n ", " &#xA; ");
263 checkEscapes(null, " \" \n ", " \" \n ", " &quot; &#xA; ");
264 checkEscapes("\r\n", " \" \n ", " \" \r\n ", " &quot; &#xA; ");
265 }
266
267 }
0 package org.jdom.test.cases.output;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertNull;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.fail;
8
9 import java.util.ArrayList;
10 import java.util.List;
11 import java.util.concurrent.atomic.AtomicBoolean;
12 import java.util.concurrent.atomic.AtomicInteger;
13
14 import org.junit.Ignore;
15 import org.junit.Test;
16 import org.xml.sax.Attributes;
17 import org.xml.sax.ContentHandler;
18 import org.xml.sax.DTDHandler;
19 import org.xml.sax.EntityResolver;
20 import org.xml.sax.ErrorHandler;
21 import org.xml.sax.Locator;
22 import org.xml.sax.SAXException;
23 import org.xml.sax.SAXNotRecognizedException;
24 import org.xml.sax.SAXNotSupportedException;
25 import org.xml.sax.SAXParseException;
26 import org.xml.sax.ext.DeclHandler;
27 import org.xml.sax.ext.DefaultHandler2;
28 import org.xml.sax.ext.LexicalHandler;
29 import org.xml.sax.helpers.AttributesImpl;
30 import org.xml.sax.helpers.LocatorImpl;
31
32 import org.jdom.Attribute;
33 import org.jdom.AttributeType;
34 import org.jdom.CDATA;
35 import org.jdom.Comment;
36 import org.jdom.Content;
37 import org.jdom.DocType;
38 import org.jdom.Document;
39 import org.jdom.Element;
40 import org.jdom.EntityRef;
41 import org.jdom.JDOMException;
42 import org.jdom.Namespace;
43 import org.jdom.ProcessingInstruction;
44 import org.jdom.Text;
45 import org.jdom.input.sax.SAXHandler;
46 import org.jdom.output.Format;
47 import org.jdom.output.JDOMLocator;
48 import org.jdom.output.LineSeparator;
49 import org.jdom.output.SAXOutputter;
50 import org.jdom.output.XMLOutputter2;
51 import org.jdom.output.support.AbstractSAXOutputProcessor;
52 import org.jdom.output.support.SAXOutputProcessor;
53 import org.jdom.test.util.UnitTestUtil;
54
55
56 @SuppressWarnings("javadoc")
57 public class TestSAXOutputter extends AbstractTestOutputter {
58
59 private interface SAXSetup {
60 public SAXOutputter buildOutputter(SAXHandler handler);
61 }
62
63
64
65 /**
66 * @param cr2xD
67 * @param padpreempty
68 * @param padpi
69 * @param forceexpand
70 * @param forceplatformeol
71 */
72 public TestSAXOutputter() {
73 super(true, true, false, false, true);
74 }
75
76 private void roundTrip(Document doc) {
77 roundTrip(null, doc);
78 }
79
80 private void roundTrip(SAXSetup setup, Document doc) {
81 XMLOutputter2 xout = new XMLOutputter2(Format.getRawFormat());
82 // create a String representation of the input.
83 if (doc.hasRootElement()) {
84 UnitTestUtil.normalizeAttributes(doc.getRootElement());
85 }
86 String expect = xout.outputString(doc);
87
88 String actual = null;
89 try {
90 // convert the input to a SAX Stream
91 SAXHandler handler = new SAXHandler();
92 SAXOutputter saxout = setup == null
93 ? new SAXOutputter(handler, handler, handler, handler, handler)
94 : setup.buildOutputter(handler);
95
96 saxout.output(doc);
97
98 Document backagain = handler.getDocument();
99
100 // get a String representation of the round-trip.
101 if (backagain.hasRootElement()) {
102 UnitTestUtil.normalizeAttributes(backagain.getRootElement());
103 }
104 actual = xout.outputString(backagain);
105 } catch (JDOMException e) {
106 e.printStackTrace();
107 fail("Failed to round-trip the document with exception: "
108 + e.getMessage() + "\n" + expect);
109 }
110 assertEquals(expect, actual);
111 }
112
113 private void roundTrip(SAXSetup setup, Element emt) {
114 XMLOutputter2 xout = new XMLOutputter2(Format.getRawFormat());
115 Document tstdoc = new Document();
116 tstdoc.addContent(emt.clone());
117 String expect = xout.outputString(tstdoc);
118
119 String actual = null;
120 try {
121 // convert the input to a SAX Stream
122 SAXHandler handler = new SAXHandler();
123 SAXOutputter saxout = setup == null
124 ? new SAXOutputter(handler, handler, handler, handler, handler)
125 : setup.buildOutputter(handler);
126
127 saxout.output(emt);
128
129 Document backagain = handler.getDocument();
130
131 // get a String representation of the round-trip.
132 if (backagain.hasRootElement()) {
133 UnitTestUtil.normalizeAttributes(backagain.getRootElement());
134 }
135 actual = xout.outputString(backagain);
136 } catch (JDOMException e) {
137 e.printStackTrace();
138 fail("Failed to round-trip the document with exception: "
139 + e.getMessage() + "\n" + expect);
140 }
141 assertEquals(expect, actual);
142 }
143
144 private void roundTripFragment(SAXSetup setup, List<Content> content) {
145 XMLOutputter2 xout = new XMLOutputter2(Format.getRawFormat());
146 Element root = new Element("root");
147 Document tstdoc = new Document(root);
148
149 for (Content c : content) {
150 root.addContent(c);
151 }
152
153 String expect = xout.outputString(tstdoc);
154
155 String actual = null;
156 try {
157 // convert the input to a SAX Stream
158 SAXHandler handler = new SAXHandler();
159 SAXOutputter saxout = setup == null
160 ? new SAXOutputter(handler, handler, handler, handler, handler)
161 : setup.buildOutputter(handler);
162
163 Locator loc = new LocatorImpl();
164 handler.setDocumentLocator(loc);
165 handler.startDocument();
166 handler.startElement("", "root", "root", new AttributesImpl());
167 saxout.outputFragment(content);
168 handler.endElement("", "root", "root");
169 handler.endDocument();
170
171 Document backagain = handler.getDocument();
172
173 // get a String representation of the round-trip.
174 if (backagain.hasRootElement()) {
175 UnitTestUtil.normalizeAttributes(backagain.getRootElement());
176 }
177 actual = xout.outputString(backagain);
178 } catch (Exception e) {
179 e.printStackTrace();
180 fail("Failed to round-trip the document with exception: "
181 + e.getMessage() + "\n" + expect);
182 }
183 assertEquals(expect, actual);
184 }
185
186 private void roundTripFragment(SAXSetup setup, Content content) {
187 XMLOutputter2 xout = new XMLOutputter2(Format.getRawFormat());
188 Element root = new Element("root");
189 Document tstdoc = new Document(root);
190
191 root.addContent(content);
192
193 String expect = xout.outputString(tstdoc);
194
195 String actual = null;
196 try {
197 // convert the input to a SAX Stream
198 SAXHandler handler = new SAXHandler();
199 SAXOutputter saxout = setup == null
200 ? new SAXOutputter(handler, handler, handler, handler, handler)
201 : setup.buildOutputter(handler);
202
203 Locator loc = new LocatorImpl();
204 handler.setDocumentLocator(loc);
205 handler.startDocument();
206 handler.startElement("", "root", "root", new AttributesImpl());
207 saxout.outputFragment(content);
208 handler.endElement("", "root", "root");
209 handler.endDocument();
210
211 Document backagain = handler.getDocument();
212
213 // get a String representation of the round-trip.
214 if (backagain.hasRootElement()) {
215 UnitTestUtil.normalizeAttributes(backagain.getRootElement());
216 }
217 actual = xout.outputString(backagain);
218 } catch (Exception e) {
219 e.printStackTrace();
220 fail("Failed to round-trip the document with exception: "
221 + e.getMessage() + "\n" + expect);
222 }
223 assertEquals(expect, actual);
224 }
225
226 private void roundTrip(SAXSetup setup, List<? extends Content> content) {
227 XMLOutputter2 xout = new XMLOutputter2(Format.getRawFormat());
228 Document tstdoc = new Document();
229 for (Object o : content) {
230 tstdoc.addContent((Content)o);
231 }
232 String expect = xout.outputString(tstdoc);
233
234 String actual = null;
235 try {
236 // convert the input to a SAX Stream
237 SAXHandler handler = new SAXHandler();
238 SAXOutputter saxout = setup == null
239 ? new SAXOutputter(handler, handler, handler, handler, handler)
240 : setup.buildOutputter(handler);
241
242 saxout.output(content);
243
244 Document backagain = handler.getDocument();
245
246 // get a String representation of the round-trip.
247 if (backagain.hasRootElement()) {
248 UnitTestUtil.normalizeAttributes(backagain.getRootElement());
249 }
250 actual = xout.outputString(backagain);
251 } catch (JDOMException e) {
252 e.printStackTrace();
253 fail("Failed to round-trip the document with exception: "
254 + e.getMessage() + "\n" + expect);
255 }
256 assertEquals(expect, actual);
257 }
258
259
260 @Test
261 public void testSAXOutputter() {
262 SAXOutputter saxout = new SAXOutputter(null, null, null, null);
263 assertTrue(null == saxout.getContentHandler());
264 assertTrue(null == saxout.getDTDHandler());
265 assertTrue(null == saxout.getLexicalHandler());
266 assertTrue(null == saxout.getErrorHandler());
267 assertTrue(null == saxout.getDeclHandler());
268 assertTrue(null == saxout.getEntityResolver());
269 }
270
271 @Test
272 public void testSAXOutputterContentHandler() {
273 SAXOutputter saxout = new SAXOutputter(null);
274 assertTrue(null == saxout.getContentHandler());
275 assertTrue(null == saxout.getDTDHandler());
276 assertTrue(null == saxout.getLexicalHandler());
277 assertTrue(null == saxout.getErrorHandler());
278 assertTrue(null == saxout.getDeclHandler());
279 assertTrue(null == saxout.getEntityResolver());
280
281 DefaultHandler2 handler = new DefaultHandler2();
282 saxout = new SAXOutputter(handler);
283 assertTrue(handler == saxout.getContentHandler());
284 assertTrue(null == saxout.getDTDHandler());
285 assertTrue(null == saxout.getLexicalHandler());
286 assertTrue(null == saxout.getErrorHandler());
287 assertTrue(null == saxout.getDeclHandler());
288 assertTrue(null == saxout.getEntityResolver());
289 }
290
291 @Test
292 public void testSAXOutputterContentHandlerErrorHandlerDTDHandlerEntityResolver() {
293 SAXOutputter saxout = new SAXOutputter(null, null, null, null);
294 assertTrue(null == saxout.getContentHandler());
295 assertTrue(null == saxout.getDTDHandler());
296 assertTrue(null == saxout.getLexicalHandler());
297 assertTrue(null == saxout.getErrorHandler());
298 assertTrue(null == saxout.getDeclHandler());
299 assertTrue(null == saxout.getEntityResolver());
300
301 DefaultHandler2 handler = new DefaultHandler2();
302 saxout = new SAXOutputter(handler, handler, handler, handler);
303 assertTrue(handler == saxout.getContentHandler());
304 assertTrue(handler == saxout.getDTDHandler());
305 assertTrue(null == saxout.getLexicalHandler());
306 assertTrue(handler == saxout.getErrorHandler());
307 assertTrue(null == saxout.getDeclHandler());
308 assertTrue(handler == saxout.getEntityResolver());
309 }
310
311 @Test
312 public void testSAXOutputterContentHandlerErrorHandlerDTDHandlerEntityResolverLexicalHandler() {
313 SAXOutputter saxout = new SAXOutputter(null, null, null, null, null);
314 assertTrue(null == saxout.getContentHandler());
315 assertTrue(null == saxout.getDTDHandler());
316 assertTrue(null == saxout.getLexicalHandler());
317 assertTrue(null == saxout.getErrorHandler());
318 assertTrue(null == saxout.getDeclHandler());
319 assertTrue(null == saxout.getEntityResolver());
320
321 DefaultHandler2 handler = new DefaultHandler2();
322 saxout = new SAXOutputter(handler, handler, handler, handler, handler);
323 assertTrue(handler == saxout.getContentHandler());
324 assertTrue(handler == saxout.getDTDHandler());
325 assertTrue(handler == saxout.getLexicalHandler());
326 assertTrue(handler == saxout.getErrorHandler());
327 assertTrue(null == saxout.getDeclHandler());
328 assertTrue(handler == saxout.getEntityResolver());
329 }
330
331 @Test
332 public void testContentHandler() {
333 ContentHandler handler = new DefaultHandler2();
334 SAXOutputter saxout = new SAXOutputter();
335 assertNull(saxout.getContentHandler());
336 saxout.setContentHandler(handler);
337 assertTrue(saxout.getContentHandler() == handler);
338 }
339
340 @Test
341 public void testErrorHandler() {
342 ErrorHandler handler = new DefaultHandler2();
343 SAXOutputter saxout = new SAXOutputter();
344 assertNull(saxout.getErrorHandler());
345 saxout.setErrorHandler(handler);
346 assertTrue(saxout.getErrorHandler() == handler);
347 }
348
349 @Test
350 public void testDTDHandler() {
351 DTDHandler handler = new DefaultHandler2();
352 SAXOutputter saxout = new SAXOutputter();
353 assertNull(saxout.getDTDHandler());
354 saxout.setDTDHandler(handler);
355 assertTrue(saxout.getDTDHandler() == handler);
356 }
357
358 @Test
359 public void testEntityResolver() {
360 EntityResolver handler = new DefaultHandler2();
361 SAXOutputter saxout = new SAXOutputter();
362 assertNull(saxout.getEntityResolver());
363 saxout.setEntityResolver(handler);
364 assertTrue(saxout.getEntityResolver() == handler);
365 }
366
367 @Test
368 public void testLexicalHandler() {
369 LexicalHandler handler = new DefaultHandler2();
370 SAXOutputter saxout = new SAXOutputter();
371 assertNull(saxout.getLexicalHandler());
372 saxout.setLexicalHandler(handler);
373 assertTrue(saxout.getLexicalHandler() == handler);
374 }
375
376 @Test
377 public void testDeclHandler() {
378 DeclHandler handler = new DefaultHandler2();
379 SAXOutputter saxout = new SAXOutputter();
380 assertNull(saxout.getDeclHandler());
381 saxout.setDeclHandler(handler);
382 assertTrue(saxout.getDeclHandler() == handler);
383 }
384
385 @Test
386 public void testReportNamespaceDeclarations() throws JDOMException {
387 final AtomicInteger includesxmlns = new AtomicInteger(0);
388 DefaultHandler2 handler = new DefaultHandler2() {
389 @Override
390 public void startElement(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {
391 super.startElement(arg0, arg1, arg2, arg3);
392 for (int i = arg3.getLength() - 1; i >= 0; i--) {
393 if (arg3.getQName(i).startsWith("xmlns")) {
394 includesxmlns.incrementAndGet();
395 }
396 }
397 }
398 };
399 Element root = new Element("root", Namespace.getNamespace("", "rooturi"));
400 root.addContent(new Element("child", Namespace.getNamespace("pfx", "childuri")));
401 Document doc = new Document(root);
402 SAXOutputter saxout = new SAXOutputter(handler, handler, handler, handler, handler);
403 assertFalse(saxout.getReportNamespaceDeclarations());
404 saxout.output(doc);
405 // we should not have reported a separate namespace xmlns:pfx="uri"
406 // thus, includesxmlns == 0
407 assertTrue(includesxmlns.get() == 0);
408 saxout.setReportNamespaceDeclarations(true);
409 assertTrue(saxout.getReportNamespaceDeclarations());
410 saxout.output(doc);
411 // we should have reported a separate namespace xmlns:pfx="childuri"
412 // and also xmlns="rooturi"
413 // thus, includesxmlns == 2
414 assertTrue(includesxmlns.get() == 2);
415 }
416
417 @Test
418 public void testReportDTDEvents() throws JDOMException {
419 final AtomicInteger includesdtd = new AtomicInteger(0);
420 DefaultHandler2 handler = new DefaultHandler2() {
421 @Override
422 public void notationDecl(String arg0, String arg1, String arg2)
423 throws SAXException {
424 super.notationDecl(arg0, arg1, arg2);
425 includesdtd.incrementAndGet();
426 }
427 @Override
428 public void unparsedEntityDecl(String arg0, String arg1,
429 String arg2, String arg3) throws SAXException {
430 super.unparsedEntityDecl(arg0, arg1, arg2, arg3);
431 includesdtd.incrementAndGet();
432 }
433 };
434 DocType dt = new DocType("root");
435 dt.setInternalSubset("<!ELEMENT root EMPTY>" +
436 "<!ENTITY junk SYSTEM \"junk\" NDATA junk>" +
437 "<!NOTATION junk PUBLIC \"junk\">");
438 Document doc = new Document(new Element("root"), dt);
439 SAXOutputter saxout = new SAXOutputter(handler, handler, handler, handler, handler);
440 assertTrue(saxout.getReportDTDEvents());
441 saxout.setReportDTDEvents(false);
442 assertFalse(saxout.getReportDTDEvents());
443 saxout.output(doc);
444 // we should not have reported start/end DTD
445 // thus, includesdtd == 0
446 assertTrue(includesdtd.get() == 0);
447 saxout.setReportDTDEvents(true);
448 assertTrue(saxout.getReportDTDEvents());
449 saxout.output(doc);
450 // we should not have reported start/end DTD
451 // thus, includesdtd == 2
452 assertTrue(includesdtd.get() == 2);
453 }
454
455 @Test
456 public void testFeature() throws SAXNotRecognizedException, SAXNotSupportedException {
457 String NAMESPACES_SAX_FEATURE = "http://xml.org/sax/features/namespaces";
458 String NS_PREFIXES_SAX_FEATURE = "http://xml.org/sax/features/namespace-prefixes";
459 String VALIDATION_SAX_FEATURE = "http://xml.org/sax/features/validation";
460 String JUNK_FEATURE = "http://xml.org/sax/features/junk";
461
462
463 SAXOutputter saxout = new SAXOutputter();
464
465 assertFalse(saxout.getFeature(NS_PREFIXES_SAX_FEATURE));
466 assertFalse(saxout.getReportNamespaceDeclarations());
467
468 assertTrue(saxout.getFeature(VALIDATION_SAX_FEATURE));
469 assertTrue(saxout.getReportDTDEvents());
470
471 assertTrue(saxout.getFeature(NAMESPACES_SAX_FEATURE));
472
473 saxout.setReportDTDEvents(false);
474 saxout.setReportNamespaceDeclarations(true);
475
476 assertTrue(saxout.getFeature(NS_PREFIXES_SAX_FEATURE));
477 assertTrue(saxout.getReportNamespaceDeclarations());
478
479 assertFalse(saxout.getFeature(VALIDATION_SAX_FEATURE));
480 assertFalse(saxout.getReportDTDEvents());
481
482 assertTrue(saxout.getFeature(NAMESPACES_SAX_FEATURE));
483
484 saxout.setFeature(NS_PREFIXES_SAX_FEATURE, false);
485 saxout.setFeature(VALIDATION_SAX_FEATURE, true);
486
487 assertFalse(saxout.getFeature(NS_PREFIXES_SAX_FEATURE));
488 assertFalse(saxout.getReportNamespaceDeclarations());
489
490 assertTrue(saxout.getFeature(VALIDATION_SAX_FEATURE));
491 assertTrue(saxout.getReportDTDEvents());
492
493 assertTrue(saxout.getFeature(NAMESPACES_SAX_FEATURE));
494
495 // can re-set the feature to true.
496 saxout.setFeature(NAMESPACES_SAX_FEATURE, true);
497
498 try {
499 saxout.setFeature(NAMESPACES_SAX_FEATURE, false);
500 fail("Should not be able to set Feature" + NAMESPACES_SAX_FEATURE + " to false");
501 } catch (SAXNotSupportedException e) {
502 // good
503 } catch (Exception e) {
504 fail ("Expecting SAXNotSupportedException, not " + e.getClass().getName());
505 }
506
507 try {
508 saxout.getFeature(JUNK_FEATURE);
509 fail("Should not be able to get Feature" + JUNK_FEATURE);
510 } catch (SAXNotRecognizedException e) {
511 // good
512 } catch (Exception e) {
513 fail ("Expecting SAXNotRecognizedException, not " + e.getClass().getName());
514 }
515
516 try {
517 saxout.setFeature(JUNK_FEATURE, true);
518 fail("Should not be able to set Feature" + JUNK_FEATURE);
519 } catch (SAXNotRecognizedException e) {
520 // good
521 } catch (Exception e) {
522 fail ("Expecting SAXNotRecognizedException, not " + e.getClass().getName());
523 }
524
525 }
526
527 @Test
528 public void testProperty() throws SAXNotRecognizedException, SAXNotSupportedException {
529 String lhs = "http://xml.org/sax/properties/lexical-handler";
530 String dhs = "http://xml.org/sax/properties/declaration-handler";
531 String jhs = "http://xml.org/sax/properties/junk-handler";
532 SAXOutputter saxout = new SAXOutputter();
533 DefaultHandler2 handler = new DefaultHandler2();
534 assertNull(saxout.getProperty(lhs));
535 assertNull(saxout.getProperty(dhs));
536 assertNull(saxout.getLexicalHandler());
537 assertNull(saxout.getDeclHandler());
538
539 saxout.setDeclHandler(handler);
540 saxout.setLexicalHandler(handler);
541 assertTrue(handler == saxout.getProperty(lhs));
542 assertTrue(handler == saxout.getProperty(dhs));
543 assertTrue(handler == saxout.getLexicalHandler());
544 assertTrue(handler == saxout.getDeclHandler());
545
546 saxout.setDeclHandler(null);
547 saxout.setLexicalHandler(null);
548 assertNull(saxout.getProperty(lhs));
549 assertNull(saxout.getProperty(dhs));
550
551 saxout.setProperty(lhs, handler);
552 saxout.setProperty(dhs, handler);
553 assertTrue(handler == saxout.getProperty(lhs));
554 assertTrue(handler == saxout.getProperty(dhs));
555 assertTrue(handler == saxout.getLexicalHandler());
556 assertTrue(handler == saxout.getDeclHandler());
557
558 try {
559 saxout.getProperty(jhs);
560 fail("Should not be able to get " + jhs);
561 } catch (SAXNotRecognizedException e) {
562 // good
563 } catch (Exception e) {
564 fail ("Expecting SAXNotRecognizedException, not " + e.getClass().getName());
565 }
566 try {
567 saxout.setProperty(jhs, new Object());
568 fail("Should not be able to set " + jhs);
569 } catch (SAXNotRecognizedException e) {
570 // good
571 } catch (Exception e) {
572 fail ("Expecting SAXNotRecognizedException, not " + e.getClass().getName());
573 }
574 }
575
576 @Test
577 public void testSAXOutputDocumentSimple() {
578 Document doc = new Document(new Element("root"));
579 roundTrip(doc);
580 }
581
582 @Test
583 public void testSAXOutputDocumentFull() {
584 Document doc = new Document();
585 doc.addContent(new DocType("root"));
586 doc.addContent(new Comment("This is a document"));
587 doc.addContent(new ProcessingInstruction("jdomtest", ""));
588 Element e = new Element("root");
589 e.addContent(new EntityRef("ref"));
590 doc.addContent(e);
591 roundTrip(doc);
592 }
593
594 @Test
595 public void testOutputDocumentRootAttNS() {
596 Document doc = new Document();
597 Element e = new Element("root");
598 e.setAttribute(new Attribute("att", "val", Namespace.getNamespace("ans", "mynamespace")));
599 doc.addContent(e);
600 roundTrip(doc);
601 }
602
603 @Test
604 public void testOutputDocumentFullNoLexical() throws JDOMException {
605 Document doc = new Document();
606 doc.addContent(new ProcessingInstruction("jdomtest", ""));
607 Element e = new Element("root");
608 doc.addContent(e);
609 e.addContent(new Text("text"));
610 e.addContent(new EntityRef("ref"));
611
612 // the Lexical handler is what helps track comments,
613 // and identifies CDATA sections.
614 // as a result the output of CDATA structures appears as plain text.
615 // and comments are dropped....
616 e.addContent(new Text("cdata"));
617 String expect = new XMLOutputter2().outputString(doc);
618 e.removeContent(2);
619 e.addContent(new CDATA("cdata"));
620 e.addContent(new Comment("This is a document"));
621
622 SAXHandler handler = new SAXHandler();
623 SAXOutputter saxout = new SAXOutputter(handler, handler, handler, handler);
624 saxout.output(doc);
625
626 Document act = handler.getDocument();
627 String actual = new XMLOutputter2().outputString(act);
628
629 assertEquals(expect, actual);
630
631 }
632
633 @Test
634 public void testOutputDocumentNoErrorHandler() {
635 DefaultHandler2 handler = new DefaultHandler2() {
636 @Override
637 public void error(SAXParseException arg0) throws SAXException {
638 throw new SAXException ("foo!");
639 }
640 };
641
642 SAXOutputter saxout = new SAXOutputter(handler);
643
644 try {
645 saxout.outputFragment(new DocType("rootemt"));
646 fail("SHould have exception!");
647 } catch (JDOMException e) {
648 assertTrue(e.getMessage().indexOf("rootemt") >= 0);
649 }
650
651 saxout.setErrorHandler(handler);
652
653 try {
654 saxout.outputFragment(new DocType("rootemt"));
655 fail("SHould have exception!");
656 } catch (JDOMException e) {
657 assertTrue(e.getMessage().endsWith("foo!"));
658 }
659
660 }
661
662 @Test
663 public void testOutputDocumentAttributes() {
664 Element emt = new Element("root");
665 emt.setAttribute("att", "val");
666 Document doc = new Document(emt);
667 roundTrip(doc);
668 }
669
670 @Test
671 public void testOutputDocumentNamespaces() {
672 Element emt = new Element("root", Namespace.getNamespace("ns", "myns"));
673 Namespace ans = Namespace.getNamespace("ans", "attributens");
674 emt.addNamespaceDeclaration(ans);
675 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
676 emt.setAttribute(new Attribute("att", "val", ans));
677 emt.addContent(new Element("child", Namespace.getNamespace("", "childuri")));
678 Document doc = new Document(emt);
679 roundTrip(doc);
680 }
681
682 @Test
683 public void testSAXOutputList() {
684 List<Content> list = new ArrayList<Content>();
685 list.add(new ProcessingInstruction("jdomtest", ""));
686 list.add(new Comment("comment"));
687 list.add(new Element("root"));
688 roundTrip(null, list);
689 }
690
691 @Test
692 public void testOutputElementAttributes() {
693 Element emt = new Element("root");
694 emt.setAttribute("att", "val");
695 emt.setAttribute(new Attribute("attx", "valx", AttributeType.UNDECLARED));
696 roundTrip(null, emt);
697 }
698
699 @Test
700 public void testSAXOutputElementNamespaces() {
701 Element emt = new Element("root", Namespace.getNamespace("ns", "myns"));
702 Namespace ans = Namespace.getNamespace("ans", "attributens");
703 emt.addNamespaceDeclaration(ans);
704 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
705 emt.setAttribute(new Attribute("att", "val", ans));
706 emt.addContent(new Element("child", Namespace.getNamespace("", "childns")));
707 roundTrip(null, emt);
708 }
709
710 @Test
711 public void testOutputFragmentList() {
712 List<Content> list = new ArrayList<Content>();
713 list.add(new ProcessingInstruction("jdomtest", ""));
714 list.add(new Comment("comment"));
715 list.add(new CDATA("foo"));
716 list.add(new Element("root"));
717 list.add(new Text("bar"));
718 roundTripFragment(null, list);
719 }
720
721 @Test
722 public void testOutputFragmentContent() {
723 roundTripFragment(null, new ProcessingInstruction("jdomtest", ""));
724 roundTripFragment(null, new Comment("comment"));
725 roundTripFragment(null, new CDATA("foo"));
726 roundTripFragment(null, new Element("root"));
727 roundTripFragment(null, new Text("bar"));
728 }
729
730 @Test
731 public void testOutputNullContent() throws JDOMException {
732 DefaultHandler2 handler = new DefaultHandler2() {
733 @Override
734 public void startDocument() throws SAXException {
735 throw new SAXException("SHould not be reaching this, ever");
736 }
737 };
738 SAXOutputter saxout = new SAXOutputter(handler, handler, handler, handler, handler);
739
740 Document doc = null;
741 Element emt = null;
742 List<Content> list = null;
743 List<Content> empty = new ArrayList<Content>();
744 saxout.output(doc);
745 saxout.output(emt);
746 saxout.output(list);
747 saxout.output(empty);
748 saxout.outputFragment(emt);
749 saxout.outputFragment(list);
750 saxout.outputFragment(empty);
751 }
752
753 @SuppressWarnings("deprecation")
754 @Test
755 public void testGetLocator() throws JDOMException {
756 SAXOutputter saxout = new SAXOutputter();
757 final AtomicBoolean coderan = new AtomicBoolean(false);
758 assertTrue(saxout.getLocator() == null);
759 DefaultHandler2 handler = new DefaultHandler2() {
760 JDOMLocator locator = null;
761 @Override
762 public void setDocumentLocator(Locator loc) {
763 if (loc instanceof JDOMLocator) {
764 locator = (JDOMLocator)loc;
765 } else {
766 fail ("We excpected the locator to be a JDOMLocator, not " + loc);
767 }
768 }
769 @Override
770 public void endElement(String uri, String localname, String qname) {
771 assertNotNull(locator);
772 assertTrue(locator.getNode() != null);
773 assertTrue(locator.getNode() instanceof Element);
774 Element emt = (Element)locator.getNode();
775 assertEquals(emt.getName(), localname);
776 coderan.set(true);
777 }
778 };
779 saxout.setContentHandler(handler);
780 saxout.setDTDHandler(handler);
781 saxout.setEntityResolver(handler);
782 saxout.setLexicalHandler(handler);
783 saxout.setDeclHandler(handler);
784 saxout.setErrorHandler(handler);
785 Document doc = new Document(new Element("root"));
786 saxout.output(doc);
787 assertTrue(coderan.get());
788 }
789
790
791
792
793 @Test
794 public void testGetSetFormat() {
795 SAXOutputter sout = new SAXOutputter();
796 Format def = sout.getFormat();
797 assertTrue(def != null);
798 Format f = Format.getPrettyFormat();
799 sout.setFormat(f);
800 assertTrue(f == sout.getFormat());
801 sout.setFormat(null);
802 TestFormat.checkEquals(def, sout.getFormat());
803 }
804
805 @Test
806 public void testGetSetDOMOutputProcessor() {
807 SAXOutputProcessor dop = new AbstractSAXOutputProcessor() {
808 // nothing.
809 };
810
811 SAXOutputter dout = new SAXOutputter();
812 SAXOutputProcessor def = dout.getSAXOutputProcessor();
813 assertTrue(def != null);
814 dout.setSAXOutputProcessor(dop);
815 assertTrue(dop == dout.getSAXOutputProcessor());
816 dout.setSAXOutputProcessor(null);
817 assertEquals(def, dout.getSAXOutputProcessor());
818 }
819
820 @Override
821 public String outputDocumentAsString(Format format, Document doc) {
822 SAXHandler handler = new SAXHandler();
823 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
824 handler, handler, handler);
825 try {
826 saxout.output(doc);
827 } catch (Exception e) {
828 throw new IllegalStateException("Could not output", e);
829 }
830 XMLOutputter2 xout = new XMLOutputter2();
831 xout.getFormat().setLineSeparator(LineSeparator.NL);
832 return xout.outputString(handler.getDocument());
833 }
834
835 @Override
836 public String outputDocTypeAsString(Format format, DocType doctype) {
837 SAXHandler handler = new SAXHandler();
838 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
839 handler, handler, handler);
840 List<Content> list = new ArrayList<Content>(1);
841 list.add(doctype);
842 //list.add(new Element("root"));
843
844 try {
845 saxout.output(list);
846 } catch (Exception e) {
847 throw new IllegalStateException("Could not output", e);
848 }
849 XMLOutputter2 xout = new XMLOutputter2();
850 xout.getFormat().setLineSeparator(LineSeparator.NL);
851 return xout.outputString(handler.getDocument().getDocType());
852 }
853
854 @Override
855 public String outputElementAsString(Format format, Element element) {
856 SAXHandler handler = new SAXHandler();
857 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
858 handler, handler, handler);
859
860 try {
861 saxout.output(element);
862 } catch (Exception e) {
863 throw new IllegalStateException("Could not output", e);
864 }
865 XMLOutputter2 xout = new XMLOutputter2();
866 xout.getFormat().setLineSeparator(LineSeparator.NL);
867 return xout.outputString(handler.getDocument().getRootElement());
868 }
869
870 @Override
871 public String outputListAsString(Format format, List<? extends Content> list) {
872 SAXHandler handler = new SAXHandler();
873 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
874 handler, handler, handler);
875
876 try {
877 handler.startDocument();
878 handler.startElement("", "root", "root", new AttributesImpl());
879 saxout.outputFragment(list);
880 handler.endElement("", "root", "root");
881 handler.endDocument();
882 } catch (Exception e) {
883 throw new IllegalStateException("Could not output", e);
884 }
885 XMLOutputter2 xout = new XMLOutputter2();
886 xout.getFormat().setLineSeparator(LineSeparator.NL);
887 return xout.outputString(handler.getDocument().getRootElement().getContent());
888 }
889
890 @Override
891 public String outputCDataAsString(Format format, CDATA cdata) {
892 SAXHandler handler = new SAXHandler();
893 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
894 handler, handler, handler);
895
896 try {
897 handler.startDocument();
898 handler.startElement("", "root", "root", new AttributesImpl());
899 saxout.outputFragment(cdata);
900 handler.endElement("", "root", "root");
901 handler.endDocument();
902 } catch (Exception e) {
903 throw new IllegalStateException("Could not output", e);
904 }
905 XMLOutputter2 xout = new XMLOutputter2();
906 xout.getFormat().setLineSeparator(LineSeparator.NL);
907 return xout.outputString(handler.getDocument().getRootElement().getContent());
908 }
909
910 @Override
911 public String outputTextAsString(Format format, Text text) {
912 SAXHandler handler = new SAXHandler();
913 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
914 handler, handler, handler);
915
916 try {
917 handler.startDocument();
918 handler.startElement("", "root", "root", new AttributesImpl());
919 saxout.outputFragment(text);
920 handler.endElement("", "root", "root");
921 handler.endDocument();
922 } catch (Exception e) {
923 throw new IllegalStateException("Could not output", e);
924 }
925 XMLOutputter2 xout = new XMLOutputter2();
926 xout.getFormat().setLineSeparator(LineSeparator.NL);
927 return xout.outputString(handler.getDocument().getRootElement().getContent());
928 }
929
930 @Override
931 public String outputCommentAsString(Format format, Comment comment) {
932 SAXHandler handler = new SAXHandler();
933 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
934 handler, handler, handler);
935
936 try {
937 handler.startDocument();
938 handler.startElement("", "root", "root", new AttributesImpl());
939 saxout.outputFragment(comment);
940 handler.endElement("", "root", "root");
941 handler.endDocument();
942 } catch (Exception e) {
943 throw new IllegalStateException("Could not output", e);
944 }
945 XMLOutputter2 xout = new XMLOutputter2();
946 xout.getFormat().setLineSeparator(LineSeparator.NL);
947 return xout.outputString(handler.getDocument().getRootElement().getContent());
948 }
949
950 @Override
951 public String outputPIAsString(Format format, ProcessingInstruction pi) {
952 SAXHandler handler = new SAXHandler();
953 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
954 handler, handler, handler);
955
956 try {
957 handler.startDocument();
958 handler.startElement("", "root", "root", new AttributesImpl());
959 saxout.outputFragment(pi);
960 handler.endElement("", "root", "root");
961 handler.endDocument();
962 } catch (Exception e) {
963 throw new IllegalStateException("Could not output", e);
964 }
965 XMLOutputter2 xout = new XMLOutputter2();
966 xout.getFormat().setLineSeparator(LineSeparator.NL);
967 return xout.outputString(handler.getDocument().getRootElement().getContent());
968 }
969
970 @Override
971 public String outputEntityRefAsString(Format format, EntityRef entity) {
972 SAXHandler handler = new SAXHandler();
973 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
974 handler, handler, handler);
975
976 try {
977 handler.startDocument();
978 handler.startElement("", "root", "root", new AttributesImpl());
979 saxout.outputFragment(entity);
980 handler.endElement("", "root", "root");
981 handler.endDocument();
982 } catch (Exception e) {
983 throw new IllegalStateException("Could not output", e);
984 }
985 XMLOutputter2 xout = new XMLOutputter2();
986 xout.getFormat().setLineSeparator(LineSeparator.NL);
987 return xout.outputString(handler.getDocument().getRootElement().getContent());
988 }
989
990 @Override
991 public String outputElementContentString(Format format, Element element) {
992 SAXHandler handler = new SAXHandler();
993 SAXOutputter saxout = new SAXOutputter(null, format, handler, handler,
994 handler, handler, handler);
995
996 try {
997 saxout.outputFragment(element.getContent());
998 } catch (Exception e) {
999 throw new IllegalStateException("Could not output", e);
1000 }
1001 XMLOutputter2 xout = new XMLOutputter2();
1002 xout.getFormat().setLineSeparator(LineSeparator.NL);
1003 return xout.outputString(handler.getDocument().getRootElement());
1004 }
1005
1006
1007
1008
1009 @Test
1010 @Override
1011 @Ignore
1012 public void testOutputElementExpandEmpty() {
1013 // Can't control expand in SAXOutputter.
1014 }
1015
1016 @Test
1017 @Override
1018 @Ignore
1019 public void testOutputElementMultiAllWhiteExpandEmpty() {
1020 // Can't control expand in SAXOutputter.
1021 }
1022
1023 @Test
1024 @Ignore
1025 @Override
1026 public void testDocTypeSimpleISS() {
1027 //Cannot preserve internal subset in DOCTYPE through the round-trip test.
1028 }
1029
1030 @Test
1031 @Ignore
1032 @Override
1033 public void testDocTypePublicSystemID() {
1034 //Cannot test with a SystemID because it needs to be resolved/referenced
1035 }
1036
1037 @Test
1038 @Ignore
1039 @Override
1040 public void testDocTypePublicSystemIDISS() {
1041 //Cannot test with a SystemID because it needs to be resolved/referenced
1042 //Cannot preserve internal subset in DOCTYPE through the round-trip test.
1043 }
1044
1045 @Test
1046 @Ignore
1047 @Override
1048 public void testDocTypeSystemID() {
1049 //Cannot test with a SystemID because it needs to be resolved/referenced
1050 }
1051
1052 @Test
1053 @Ignore
1054 @Override
1055 public void testDocTypeSystemIDISS() {
1056 //Cannot preserve internal subset in DOCTYPE through the round-trip test.
1057 }
1058
1059 @Test
1060 @Override
1061 @Ignore
1062 public void testDocumentDocType() {
1063 // override because we can't control whitespace outside of the root element
1064 }
1065
1066
1067 @Test
1068 @Override
1069 @Ignore
1070 public void testOutputDocTypeInternalSubset() {
1071 //Cannot preserve internal subset in DOCTYPE through the round-trip test.
1072 }
1073
1074
1075 @Test
1076 @Override
1077 @Ignore
1078 public void testOutputDocTypeSystem() {
1079 //Cannot test with a SystemID because it needs to be resolved/referenced
1080 }
1081
1082 @Test
1083 @Override
1084 @Ignore
1085 public void testOutputDocTypePublic() {
1086 // cannot test with a non-resolved publicID
1087 }
1088
1089 @Test
1090 @Override
1091 @Ignore
1092 public void testOutputDocTypePublicSystem() {
1093 //Cannot test with a SystemID because it needs to be resolved/referenced
1094 }
1095
1096
1097 @Test
1098 @Override
1099 @Ignore
1100 public void testOutputDocumentOmitEncoding() {
1101 // Cannot test for formatting outside of root element
1102 }
1103
1104 @Test
1105 @Override
1106 @Ignore
1107 public void testOutputDocumentOmitDeclaration() {
1108 // Cannot test for formatting outside of root element
1109 }
1110
1111 @Test
1112 public void testNoNamespaceIssue60 () throws JDOMException {
1113 Document doc = new Document();
1114 Namespace ns = Namespace.getNamespace("myurl");
1115 Element root = new Element("root", ns);
1116 Element child = new Element("child", ns);
1117 root.addContent(child);
1118 doc.setRootElement(root);
1119 final String[] count = new String[1];
1120
1121 child.setAttribute("att", "val");
1122
1123 ContentHandler ch = new DefaultHandler2() {
1124 @Override
1125 public void startPrefixMapping(String pfx, String uri)
1126 throws SAXException {
1127 if ("".equals(pfx) && "".equals(uri)) {
1128 fail("Should not be firing xmlns=\"\"");
1129 }
1130 if (!"".equals(pfx)) {
1131 fail("we should not have prefix " + pfx);
1132 }
1133 if (count[0] != null) {
1134 fail("we should not have multiple mappings " + pfx + " -> " + uri);
1135 }
1136 count[0] = uri;
1137 }
1138 };
1139 SAXOutputter saxout = new SAXOutputter(ch);
1140 saxout.output(doc);
1141 assertTrue("myurl".equals(count[0]));
1142 }
1143
1144 }
0 package org.jdom.test.cases.output;
1
2 import static org.jdom.test.util.UnitTestUtil.failException;
3 import static org.jdom.test.util.UnitTestUtil.normalizeAttributes;
4 import static org.junit.Assert.assertEquals;
5 import static org.junit.Assert.assertNotNull;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.fail;
8
9 import java.io.ByteArrayOutputStream;
10 import java.io.CharArrayReader;
11 import java.io.IOException;
12 import java.io.StringReader;
13 import java.io.StringWriter;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 import javax.xml.stream.XMLEventFactory;
18 import javax.xml.stream.XMLEventWriter;
19 import javax.xml.stream.XMLInputFactory;
20 import javax.xml.stream.XMLOutputFactory;
21 import javax.xml.stream.XMLStreamConstants;
22 import javax.xml.stream.XMLStreamException;
23 import javax.xml.stream.XMLStreamReader;
24 import javax.xml.stream.events.XMLEvent;
25 import javax.xml.stream.util.XMLEventConsumer;
26
27 import org.junit.Ignore;
28 import org.junit.Test;
29 import org.xml.sax.SAXException;
30 import org.xml.sax.SAXParseException;
31 import org.xml.sax.ext.DefaultHandler2;
32
33 import org.jdom.Attribute;
34 import org.jdom.AttributeType;
35 import org.jdom.CDATA;
36 import org.jdom.Comment;
37 import org.jdom.Content;
38 import org.jdom.DocType;
39 import org.jdom.Document;
40 import org.jdom.Element;
41 import org.jdom.EntityRef;
42 import org.jdom.IllegalDataException;
43 import org.jdom.JDOMException;
44 import org.jdom.Namespace;
45 import org.jdom.ProcessingInstruction;
46 import org.jdom.Text;
47 import org.jdom.UncheckedJDOMFactory;
48 import org.jdom.input.SAXBuilder;
49 import org.jdom.input.StAXStreamBuilder;
50 import org.jdom.input.sax.SAXHandler;
51 import org.jdom.input.stax.DefaultStAXFilter;
52 import org.jdom.output.Format;
53 import org.jdom.output.Format.TextMode;
54 import org.jdom.output.support.AbstractStAXEventProcessor;
55 import org.jdom.output.support.StAXEventProcessor;
56 import org.jdom.output.SAXOutputter;
57 import org.jdom.output.StAXEventOutputter;
58 import org.jdom.output.XMLOutputter2;
59
60 @SuppressWarnings("javadoc")
61 public final class TestStAXEventOutputter extends AbstractTestOutputter {
62
63 private final static XMLOutputFactory soutfactory = XMLOutputFactory.newInstance();
64 private final static XMLInputFactory sinfactory = XMLInputFactory.newInstance();
65 private final static XMLEventFactory seventfactory = XMLEventFactory.newInstance();
66
67 private static final class OutWrapper {
68 private final StringWriter swriter = new StringWriter();
69
70 private final StAXEventOutputter stax;
71 private final XMLEventWriter xwriter;
72 private int from = 0, to = -1;
73
74 public OutWrapper(Format format) {
75 try {
76 xwriter = soutfactory.createXMLEventWriter(swriter);
77 stax = new StAXEventOutputter(format);
78 } catch (Exception xse) {
79 throw new IllegalStateException("Cannot construct: See Cause", xse);
80 }
81 }
82
83 @Override
84 public String toString() {
85 return to >= 0 ? swriter.getBuffer().substring(from, to) :
86 swriter.getBuffer().substring(from);
87 }
88
89
90
91 public StAXEventOutputter getStax() {
92 return stax;
93 }
94
95 public void close() {
96 try {
97 xwriter.close();
98 } catch (XMLStreamException e) {
99 throw new IllegalStateException("Cannot flush(): See Cause", e);
100 }
101 }
102
103 public XMLEventWriter getStream() {
104 return xwriter;
105 }
106
107 public void setDocumentMarkFrom() {
108 try {
109 xwriter.add(seventfactory.createStartDocument());
110 xwriter.add(seventfactory.createCharacters(""));
111 xwriter.flush();
112 } catch (XMLStreamException e) {
113 throw new IllegalStateException("Cannot flush(): See Cause", e);
114 }
115 from = swriter.getBuffer().length();
116 }
117
118 public void setDocumentMarkTo() {
119 try {
120 xwriter.add(seventfactory.createCharacters(""));
121 xwriter.flush();
122 to = swriter.getBuffer().length();
123 xwriter.add(seventfactory.createEndDocument());
124 } catch (XMLStreamException e) {
125 throw new IllegalStateException("Cannot flush(): See Cause", e);
126 }
127 }
128
129 public void setElementMarkFrom() {
130 try {
131 xwriter.add(seventfactory.createStartDocument());
132 xwriter.add(seventfactory.createStartElement("", "", "root"));
133 xwriter.add(seventfactory.createCharacters(""));
134 xwriter.flush();
135 from = swriter.getBuffer().length();
136 } catch (XMLStreamException e) {
137 throw new IllegalStateException("Cannot flush(): See Cause", e);
138 }
139 }
140
141 public void setElementMarkTo() {
142 try {
143 xwriter.add(seventfactory.createCharacters(""));
144 xwriter.flush();
145 to = swriter.getBuffer().length();
146 xwriter.add(seventfactory.createEndElement("", "", "root"));
147 xwriter.add(seventfactory.createEndDocument());
148 xwriter.flush();
149 xwriter.close();
150 } catch (XMLStreamException e) {
151 throw new IllegalStateException("Cannot flush(): See Cause", e);
152 }
153 }
154
155 }
156
157
158 private static final class EventStore implements XMLEventConsumer {
159 private final ArrayList<XMLEvent> store = new ArrayList<XMLEvent>();
160 private final String encoding;
161
162 EventStore(String enc) {
163 encoding = enc;
164 }
165
166 @Override
167 public void add(XMLEvent event) throws XMLStreamException {
168 store.add(event);
169 }
170
171 @Override
172 public String toString() {
173 ByteArrayOutputStream sw = new ByteArrayOutputStream();
174 try {
175 XMLEventWriter xew = soutfactory.createXMLEventWriter(sw, encoding);
176 for (XMLEvent x : store) {
177 xew.add(x);
178 }
179 xew.flush();
180 xew.close();
181 return new String(sw.toByteArray());
182 } catch (XMLStreamException e) {
183 throw new IllegalStateException("Can't get toString...", e);
184 }
185
186 }
187 }
188
189 public TestStAXEventOutputter() {
190 super(false, false, true, true, false);
191 }
192
193
194 @Override
195 public String outputDocumentAsString(Format format, Document doc) {
196 OutWrapper ow = new OutWrapper(format);
197 try {
198 ow.getStax().output(doc, ow.getStream());
199 } catch (XMLStreamException e) {
200 throw new IllegalStateException(e);
201 }
202 ow.close();
203 return ow.toString();
204 }
205
206
207
208
209 @Override
210 public String outputDocTypeAsString(Format format, DocType doctype) {
211 OutWrapper ow = new OutWrapper(format);
212 try {
213 ow.setDocumentMarkFrom();
214 ow.getStax().output(doctype, ow.getStream());
215 ow.setDocumentMarkTo();
216 } catch (XMLStreamException e) {
217 throw new IllegalStateException(e);
218 }
219 ow.close();
220 return ow.toString();
221 }
222
223 @Override
224 public String outputElementAsString(Format format, Element element) {
225 OutWrapper ow = new OutWrapper(format);
226 try {
227 ow.setDocumentMarkFrom();
228 ow.getStax().output(element, ow.getStream());
229 ow.setDocumentMarkTo();
230 } catch (XMLStreamException e) {
231 throw new IllegalStateException(e);
232 }
233 ow.close();
234 return ow.toString();
235 }
236
237 @Override
238 public String outputListAsString(Format format, List<? extends Content> list) {
239 OutWrapper ow = new OutWrapper(format);
240 try {
241 ow.setElementMarkFrom();
242 ow.getStax().output(list, ow.getStream());
243 ow.setElementMarkTo();
244 } catch (XMLStreamException e) {
245 throw new IllegalStateException(e);
246 }
247 ow.close();
248 return ow.toString();
249 }
250
251 @Override
252 public String outputCDataAsString(Format format, CDATA cdata) {
253 OutWrapper ow = new OutWrapper(format);
254 try {
255 ow.setElementMarkFrom();
256 ow.getStax().output(cdata, ow.getStream());
257 ow.setElementMarkTo();
258 } catch (XMLStreamException e) {
259 throw new IllegalStateException(e);
260 }
261 ow.close();
262 return ow.toString();
263 }
264
265 @Override
266 public String outputTextAsString(Format format, Text text) {
267 OutWrapper ow = new OutWrapper(format);
268 try {
269 ow.setElementMarkFrom();
270 ow.getStax().output(text, ow.getStream());
271 ow.setElementMarkTo();
272 } catch (XMLStreamException e) {
273 throw new IllegalStateException(e);
274 }
275 ow.close();
276 return ow.toString();
277 }
278
279 @Override
280 public String outputCommentAsString(Format format, Comment comment) {
281 OutWrapper ow = new OutWrapper(format);
282 try {
283 ow.setDocumentMarkFrom();
284 ow.getStax().output(comment, ow.getStream());
285 ow.setDocumentMarkTo();
286 } catch (XMLStreamException e) {
287 throw new IllegalStateException(e);
288 }
289 ow.close();
290 return ow.toString();
291 }
292
293 @Override
294 public String outputPIAsString(Format format, ProcessingInstruction pi) {
295 OutWrapper ow = new OutWrapper(format);
296 try {
297 ow.setDocumentMarkFrom();
298 ow.getStax().output(pi, ow.getStream());
299 ow.setDocumentMarkTo();
300 } catch (XMLStreamException e) {
301 throw new IllegalStateException(e);
302 }
303 ow.close();
304 return ow.toString();
305 }
306
307 @Override
308 public String outputEntityRefAsString(Format format, EntityRef entity) {
309 OutWrapper ow = new OutWrapper(format);
310 try {
311 ow.setElementMarkFrom();
312 ow.getStax().output(entity, ow.getStream());
313 ow.setElementMarkTo();
314 } catch (XMLStreamException e) {
315 throw new IllegalStateException(e);
316 }
317 ow.close();
318 return ow.toString();
319 }
320
321 @Override
322 public String outputElementContentString(Format format, Element element) {
323 OutWrapper ow = new OutWrapper(format);
324 try {
325 ow.setElementMarkFrom();
326 ow.getStax().outputElementContent(element, ow.getStream());
327 ow.setElementMarkTo();
328 } catch (XMLStreamException e) {
329 throw new IllegalStateException(e);
330 }
331 ow.close();
332 return ow.toString();
333 }
334
335 @Override
336 public void testOutputDocumentOmitDeclaration() {
337 // skip this test.
338 }
339
340 @Test @Ignore
341 public void test_HighSurrogatePair() throws XMLStreamException, IOException, JDOMException {
342 SAXBuilder builder = new SAXBuilder();
343 builder.setExpandEntities(true);
344 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>&#x10000; &#x10000;</root>"));
345
346 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
347 StAXEventOutputter outputter = new StAXEventOutputter(format);
348 EventStore es = new EventStore("ISO-8859-1");
349 outputter.output(doc, es);
350 String xml = es.toString();
351 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n" +
352 "<root>&#xd800;&#xdc00; &#xd800;&#xdc00;</root>\r\n", xml);
353 }
354
355 @Test @Ignore
356 public void test_HighSurrogatePairDecimal() throws JDOMException, IOException, XMLStreamException {
357 SAXBuilder builder = new SAXBuilder();
358 builder.setExpandEntities(true);
359 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>&#x10000; &#65536;</root>"));
360 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
361 StAXEventOutputter outputter = new StAXEventOutputter(format);
362 EventStore es = new EventStore("ISO-8859-1");
363 outputter.output(doc, es);
364 String xml = es.toString();
365 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n" +
366 "<root>&#xd800;&#xdc00; &#xd800;&#xdc00;</root>\r\n", xml);
367 }
368
369 @Test @Ignore
370 public void test_HighSurrogateAttPair() throws JDOMException, IOException, XMLStreamException {
371 SAXBuilder builder = new SAXBuilder();
372 builder.setExpandEntities(true);
373 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root att=\"&#x10000; &#x10000;\" />"));
374 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
375 StAXEventOutputter outputter = new StAXEventOutputter(format);
376 EventStore es = new EventStore("ISO-8859-1");
377 outputter.output(doc, es);
378 String xml = es.toString();
379 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n" +
380 "<root att=\"&#xd800;&#xdc00; &#xd800;&#xdc00;\"></root>\r\n", xml);
381 }
382
383 @Test @Ignore
384 public void test_HighSurrogateAttPairDecimal() throws JDOMException, IOException, XMLStreamException {
385 SAXBuilder builder = new SAXBuilder();
386 builder.setExpandEntities(true);
387 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root att=\"&#x10000; &#65536;\" />"));
388 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
389 StAXEventOutputter outputter = new StAXEventOutputter(format);
390 EventStore es = new EventStore("ISO-8859-1");
391 outputter.output(doc, es);
392 String xml = es.toString();
393 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n" +
394 "<root att=\"&#xd800;&#xdc00; &#xd800;&#xdc00;\"></root>\r\n", xml);
395 }
396
397 // Construct a raw surrogate pair character and confirm it outputs hex escaped
398 @Test @Ignore
399 public void test_RawSurrogatePair() throws JDOMException, IOException, XMLStreamException {
400 SAXBuilder builder = new SAXBuilder();
401 builder.setExpandEntities(true);
402 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>\uD800\uDC00</root>"));
403 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
404 StAXEventOutputter outputter = new StAXEventOutputter(format);
405 EventStore es = new EventStore("ISO-8859-1");
406 outputter.output(doc, es);
407 String xml = es.toString();
408 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n" +
409 "<root>&#xd800;&#xdc00;</root>\r\n", xml);
410 }
411
412 // Construct a raw surrogate pair character and confirm it outputs hex escaped, when UTF-8 too
413 @Test
414 @Ignore
415 // TODO
416 public void test_RawSurrogatePairUTF8() throws JDOMException, IOException, XMLStreamException {
417 SAXBuilder builder = new SAXBuilder();
418 builder.setExpandEntities(true);
419 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>\uD800\uDC00</root>"));
420 Format format = Format.getCompactFormat().setEncoding("UTF-8");
421 StAXEventOutputter outputter = new StAXEventOutputter(format);
422 EventStore es = new EventStore("UTF-8");
423 outputter.output(doc, es);
424 String xml = es.toString();
425 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
426 "<root>\uD800\uDC00</root>", xml);
427 }
428
429 // Construct illegal XML and check if the parser notices
430 @Test
431 public void test_ErrorSurrogatePair() throws JDOMException, IOException {
432 SAXBuilder builder = new SAXBuilder();
433 builder.setExpandEntities(true);
434 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root></root>"));
435 try {
436 doc.getRootElement().setText("\uD800\uDBFF");
437 fail("Illegal surrogate pair should have thrown an exception");
438 }
439 catch (IllegalDataException e) {
440 // do nothing
441 } catch (Exception e) {
442 fail ("Unexpected exception " + e.getClass());
443 }
444 }
445
446 // Manually construct illegal XML and make sure the outputter notices
447 @Test
448 @Ignore
449 // TODO
450 public void test_ErrorSurrogatePairOutput() throws JDOMException, IOException {
451 SAXBuilder builder = new SAXBuilder();
452 builder.setExpandEntities(true);
453 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root></root>"));
454 Text t = new UncheckedJDOMFactory().text("\uD800\uDBFF");
455 doc.getRootElement().setContent(t);
456 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
457 StAXEventOutputter outputter = new StAXEventOutputter(format);
458 try {
459 EventStore es = new EventStore("ISO-8859-1");
460 outputter.output(doc, es);
461 fail("Illegal surrogate pair output should have thrown an exception");
462 }
463 catch (XMLStreamException e) {
464 // do nothing
465 } catch (Exception e) {
466 fail ("Unexpected exception " + e.getClass());
467 }
468 }
469
470
471 @Test
472 public void testXMLOutputter() {
473 StAXEventOutputter out = new StAXEventOutputter();
474 TestFormat.checkEquals(out.getFormat(), Format.getRawFormat());
475 }
476
477
478 @Test
479 public void testXMLOutputterFormat() {
480 Format mine = Format.getCompactFormat();
481 mine.setEncoding("US-ASCII");
482 StAXEventOutputter out = new StAXEventOutputter(mine);
483 TestFormat.checkEquals(mine, out.getFormat());
484 }
485
486 // @Test
487 // public void testXMLOutputterXMLOutputter() {
488 // Format mine = Format.getCompactFormat();
489 // StAXEventProcessor xoutp = new StAXEventOutputter().getStAXStream();
490 // mine.setEncoding("US-ASCII");
491 // // double-construct it.
492 // StAXEventOutputter out = new StAXEventOutputter();
493 // TestFormat.checkEquals(mine, out.getFormat());
494 // assertTrue(xoutp == out.getXMLOutputProcessor());
495 // }
496
497 @Test
498 public void testXMLOutputterXMLOutputProcessor() {
499 StAXEventProcessor xoutp = new AbstractStAXEventProcessor() {
500 // nothing;
501 };
502 // double-constrcut it.
503 StAXEventOutputter out = new StAXEventOutputter(xoutp);
504 TestFormat.checkEquals(Format.getRawFormat(), out.getFormat());
505 assertTrue(xoutp == out.getStAXStream());
506 }
507
508 @Test
509 public void testFormat() {
510 Format mine = Format.getCompactFormat();
511 mine.setEncoding("US-ASCII");
512 // double-constcut it.
513 StAXEventOutputter out = new StAXEventOutputter();
514 TestFormat.checkEquals(Format.getRawFormat(), out.getFormat());
515 out.setFormat(mine);
516 TestFormat.checkEquals(mine, out.getFormat());
517 }
518
519 @Test
520 public void testXMLOutputProcessor() {
521 StAXEventProcessor xoutp = new AbstractStAXEventProcessor() {
522 // nothing;
523 };
524 // double-constcut it.
525 StAXEventOutputter out = new StAXEventOutputter();
526 StAXEventProcessor xop = out.getStAXStream();
527 out.setStAXEventProcessor(xoutp);
528 assertTrue(xoutp != xop);
529 assertTrue(xoutp == out.getStAXStream());
530 }
531
532 @Test
533 public void testTrimFullWhite() throws XMLStreamException {
534 // See issue #31.
535 // https://github.com/hunterhacker/jdom/issues/31
536 // This tests should pass when issue 31 is resolved.
537 Element root = new Element("root");
538 root.addContent(new Text(" "));
539 root.addContent(new Text("x"));
540 root.addContent(new Text(" "));
541 Format mf = Format.getRawFormat();
542 mf.setTextMode(TextMode.TRIM_FULL_WHITE);
543 StAXEventOutputter xout = new StAXEventOutputter(mf);
544 EventStore es = new EventStore("UTF-8");
545 xout.output(root, es);
546 assertEquals("<root> x </root>", es.toString());
547 }
548
549 @Test
550 public void testClone() {
551 StAXEventOutputter xo = new StAXEventOutputter();
552 assertTrue(xo != xo.clone());
553 }
554
555 @Test
556 public void testToString() {
557 Format fmt = Format.getCompactFormat();
558 fmt.setLineSeparator("\n\t ");
559 StAXEventOutputter out = new StAXEventOutputter(fmt);
560 assertNotNull(out.toString());
561 }
562
563 /*
564 * The following are borrowed from the TestSAXOutputter
565 * The effect is that we compare the StAX string output with the re-parsed
566 * value of the input.
567 */
568
569 private void roundTripDocument(Document doc) {
570 StAXEventOutputter xout = new StAXEventOutputter(Format.getRawFormat());
571 // create a String representation of the input.
572 if (doc.hasRootElement()) {
573 normalizeAttributes(doc.getRootElement());
574 }
575
576 try {
577 EventStore xsw = new EventStore("UTF-8");
578 xout.output(doc, xsw);
579 String expect = xsw.toString();
580
581 // convert the input to a SAX Stream
582
583 StAXStreamBuilder sbuilder = new StAXStreamBuilder();
584
585 char[] chars = expect.toCharArray();
586 CharArrayReader car = new CharArrayReader(chars);
587 XMLStreamReader xsr = sinfactory.createXMLStreamReader(car);
588
589 Document backagain = sbuilder.build(xsr);
590 xsr.close();
591
592 // get a String representation of the round-trip.
593 if (backagain.hasRootElement()) {
594 normalizeAttributes(backagain.getRootElement());
595 }
596 xsw = new EventStore("UTF-8");
597 xout.output(backagain, xsw);
598 String actual = xsw.toString();
599
600 assertEquals(expect, actual);
601 } catch (Exception e) {
602 failException("Failed to round-trip the document with exception: "
603 + e.getMessage(), e);
604 }
605 }
606
607 private void roundTripElement(Element emt) {
608
609 try {
610 StAXEventOutputter xout = new StAXEventOutputter(Format.getRawFormat());
611
612 EventStore xsw = new EventStore("UTF-8");
613 xout.output(emt, xsw);
614 String expect = xsw.toString();
615
616 StAXStreamBuilder sbuilder = new StAXStreamBuilder();
617
618 XMLStreamReader xsr = sinfactory.createXMLStreamReader(new StringReader(expect));
619 assertTrue(xsr.getEventType() == XMLStreamConstants.START_DOCUMENT);
620 assertTrue(xsr.hasNext());
621 xsr.next();
622
623 Element backagain = (Element)sbuilder.fragment(xsr);
624
625 // convert the input to a SAX Stream
626
627 xsw = new EventStore("UTF-8");
628 xout.output(backagain, xsw);
629
630 String actual = xsw.toString();
631 assertEquals(expect, actual);
632 } catch (Exception e) {
633 failException("Failed to round-trip the document with exception: "
634 + e.getMessage(), e);
635 }
636 }
637
638 private void roundTripFragment(List<Content> content) {
639 try {
640 StAXEventOutputter xout = new StAXEventOutputter(Format.getRawFormat());
641
642 EventStore xsw = new EventStore("UTF-8");
643 xout.output(content, xsw);
644 String expect = xsw.toString();
645
646 StAXStreamBuilder sbuilder = new StAXStreamBuilder();
647
648 XMLStreamReader xsr = sinfactory.createXMLStreamReader(new StringReader(expect));
649 // assertTrue(xsr.getEventType() == XMLStreamConstants.START_DOCUMENT);
650 // assertTrue(xsr.hasNext());
651 // xsr.next();
652
653 List<Content> backagain = sbuilder.buildFragments(xsr, new DefaultStAXFilter());
654
655 // convert the input to a SAX Stream
656
657 xsw = new EventStore("UTF-8");
658 xout.output(backagain, xsw);
659
660 String actual = xsw.toString();
661 assertEquals(expect, actual);
662 } catch (Exception e) {
663 failException("Failed to round-trip the document with exception: "
664 + e.getMessage(), e);
665 }
666
667 }
668
669 private void roundTripFragment(Content content) {
670 try {
671 StAXEventOutputter xout = new StAXEventOutputter(Format.getRawFormat());
672
673 EventStore xsw = new EventStore("UTF-8");
674 switch(content.getCType()) {
675 case CDATA :
676 xout.output((CDATA)content, xsw);
677 break;
678 case Text:
679 xout.output((Text)content, xsw);
680 break;
681 case Comment:
682 xout.output((Comment)content, xsw);
683 break;
684 case DocType:
685 xout.output((DocType)content, xsw);
686 break;
687 case Element:
688 xout.output((Element)content, xsw);
689 break;
690 case EntityRef:
691 xout.output((EntityRef)content, xsw);
692 break;
693 case ProcessingInstruction:
694 xout.output((ProcessingInstruction)content, xsw);
695 break;
696 default:
697 throw new IllegalStateException(content.getCType().toString());
698 }
699 String expect = xsw.toString();
700
701 StAXStreamBuilder sbuilder = new StAXStreamBuilder();
702
703 Content backagain = sbuilder.fragment(
704 sinfactory.createXMLStreamReader(new StringReader(expect)));
705
706 // convert the input to a SAX Stream
707
708 xsw = new EventStore("UTF-8");
709 switch(content.getCType()) {
710 case CDATA :
711 xout.output((CDATA)backagain, xsw);
712 break;
713 case Text:
714 xout.output((Text)backagain, xsw);
715 break;
716 case Comment:
717 xout.output((Comment)backagain, xsw);
718 break;
719 case DocType:
720 xout.output((DocType)backagain, xsw);
721 break;
722 case Element:
723 xout.output((Element)backagain, xsw);
724 break;
725 case EntityRef:
726 xout.output((EntityRef)backagain, xsw);
727 break;
728 case ProcessingInstruction:
729 xout.output((ProcessingInstruction)backagain, xsw);
730 break;
731 default:
732 throw new IllegalStateException(backagain.getCType().toString());
733 }
734
735 String actual = xsw.toString();
736 assertEquals(expect, actual);
737 } catch (Exception e) {
738 failException("Failed to round-trip the document with exception: "
739 + e.getMessage(), e);
740 }
741 }
742
743 @Test
744 public void testRTOutputDocumentSimple() {
745 Document doc = new Document(new Element("root"));
746 roundTripDocument(doc);
747 }
748
749 @Test
750 // TODO
751 @Ignore
752 public void testRTOutputDocumentFull() {
753 Document doc = new Document();
754 DocType dt = new DocType("root");
755 dt.setInternalSubset(" ");
756 doc.addContent(dt);
757 doc.addContent(new Comment("This is a document"));
758 doc.addContent(new ProcessingInstruction("jdomtest", ""));
759 Element e = new Element("root");
760 e.addContent(new EntityRef("ref"));
761 doc.addContent(e);
762 roundTripDocument(doc);
763 }
764
765 @Test
766 public void testOutputDocumentRootAttNS() {
767 Document doc = new Document();
768 Element e = new Element("root");
769 e.setAttribute(new Attribute("att", "val", Namespace.getNamespace("ans", "mynamespace")));
770 doc.addContent(e);
771 roundTripDocument(doc);
772 }
773
774 @Test
775 public void testOutputDocumentFullNoLexical() throws JDOMException {
776 Document doc = new Document();
777 doc.addContent(new ProcessingInstruction("jdomtest", ""));
778 Element e = new Element("root");
779 doc.addContent(e);
780 e.addContent(new Text("text"));
781 e.addContent(new EntityRef("ref"));
782
783 // the Lexical handler is what helps track comments,
784 // and identifies CDATA sections.
785 // as a result the output of CDATA structures appears as plain text.
786 // and comments are dropped....
787 e.addContent(new Text("cdata"));
788 String expect = new XMLOutputter2().outputString(doc);
789 e.removeContent(2);
790 e.addContent(new CDATA("cdata"));
791 e.addContent(new Comment("This is a document"));
792
793 SAXHandler handler = new SAXHandler();
794 SAXOutputter saxout = new SAXOutputter(handler, handler, handler, handler);
795 saxout.output(doc);
796
797 Document act = handler.getDocument();
798 String actual = new XMLOutputter2().outputString(act);
799
800 assertEquals(expect, actual);
801
802 }
803
804 @Test
805 public void testOutputDocumentNoErrorHandler() {
806 DefaultHandler2 handler = new DefaultHandler2() {
807 @Override
808 public void error(SAXParseException arg0) throws SAXException {
809 throw new SAXException ("foo!");
810 }
811 };
812
813 SAXOutputter saxout = new SAXOutputter(handler);
814
815 try {
816 saxout.outputFragment(new DocType("rootemt"));
817 fail("SHould have exception!");
818 } catch (JDOMException e) {
819 assertTrue(e.getMessage().indexOf("rootemt") >= 0);
820 }
821
822 saxout.setErrorHandler(handler);
823
824 try {
825 saxout.outputFragment(new DocType("rootemt"));
826 fail("SHould have exception!");
827 } catch (JDOMException e) {
828 assertTrue(e.getMessage().endsWith("foo!"));
829 }
830
831 }
832
833 @Test
834 public void testOutputDocumentAttributes() {
835 Element emt = new Element("root");
836 emt.setAttribute("att", "val");
837 Document doc = new Document(emt);
838 roundTripDocument(doc);
839 }
840
841 @Test
842 public void testOutputDocumentNamespaces() {
843 Element emt = new Element("root", Namespace.getNamespace("ns", "myns"));
844 Namespace ans = Namespace.getNamespace("ans", "attributens");
845 emt.addNamespaceDeclaration(ans);
846 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
847 emt.setAttribute(new Attribute("att", "val", ans));
848 emt.addContent(new Element("child", Namespace.getNamespace("", "childuri")));
849 Document doc = new Document(emt);
850 roundTripDocument(doc);
851 }
852
853 @Test
854 public void testRTOutputList() {
855 List<Content> list = new ArrayList<Content>();
856 list.add(new ProcessingInstruction("jdomtest", ""));
857 list.add(new Comment("comment"));
858 list.add(new Element("root"));
859 roundTripFragment(list);
860 }
861
862 @Test
863 public void testOutputElementAttributes() {
864 Element emt = new Element("root");
865 emt.setAttribute("att", "val");
866 emt.setAttribute(new Attribute("attx", "valx", AttributeType.UNDECLARED));
867 roundTripElement(emt);
868 }
869
870 @Test
871 public void testRTOutputElementNamespaces() {
872 Element emt = new Element("root", Namespace.getNamespace("ns", "myns"));
873 Namespace ans = Namespace.getNamespace("ans", "attributens");
874 emt.addNamespaceDeclaration(ans);
875 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
876 emt.setAttribute(new Attribute("att", "val", ans));
877 emt.addContent(new Element("child", Namespace.getNamespace("", "childns")));
878 roundTripElement(emt);
879 }
880
881 @Test
882 @Ignore
883 public void testOutputFragmentList() {
884 List<Content> list = new ArrayList<Content>();
885 list.add(new ProcessingInstruction("jdomtest", ""));
886 list.add(new Comment("comment"));
887 list.add(new CDATA("foo"));
888 list.add(new Element("root"));
889 list.add(new Text("bar"));
890 roundTripFragment(list);
891 }
892
893 @Test
894 @Ignore
895 public void testOutputFragmentContent() {
896 roundTripFragment(new ProcessingInstruction("jdomtest", ""));
897 roundTripFragment(new Comment("comment"));
898 roundTripFragment(new CDATA("foo"));
899 roundTripFragment(new Element("root"));
900 roundTripFragment(new Text("bar"));
901 }
902
903 @Test
904 public void testOutputNullContent() throws JDOMException {
905 DefaultHandler2 handler = new DefaultHandler2() {
906 @Override
907 public void startDocument() throws SAXException {
908 throw new SAXException("SHould not be reaching this, ever");
909 }
910 };
911 SAXOutputter saxout = new SAXOutputter(handler, handler, handler, handler, handler);
912
913 Document doc = null;
914 Element emt = null;
915 List<Content> list = null;
916 List<Content> empty = new ArrayList<Content>();
917 saxout.output(doc);
918 saxout.output(emt);
919 saxout.output(list);
920 saxout.output(empty);
921 saxout.outputFragment(emt);
922 saxout.outputFragment(list);
923 saxout.outputFragment(empty);
924 }
925
926
927 }
0 package org.jdom.test.cases.output;
1
2 import static org.jdom.test.util.UnitTestUtil.failException;
3 import static org.jdom.test.util.UnitTestUtil.normalizeAttributes;
4 import static org.junit.Assert.assertEquals;
5 import static org.junit.Assert.assertNotNull;
6 import static org.junit.Assert.assertTrue;
7 import static org.junit.Assert.fail;
8
9 import java.io.ByteArrayOutputStream;
10 import java.io.IOException;
11 import java.io.StringReader;
12 import java.io.StringWriter;
13 import java.util.ArrayList;
14 import java.util.List;
15
16 import javax.xml.stream.XMLInputFactory;
17 import javax.xml.stream.XMLOutputFactory;
18 import javax.xml.stream.XMLStreamConstants;
19 import javax.xml.stream.XMLStreamException;
20 import javax.xml.stream.XMLStreamReader;
21 import javax.xml.stream.XMLStreamWriter;
22
23 import org.junit.Ignore;
24 import org.junit.Test;
25 import org.xml.sax.SAXException;
26 import org.xml.sax.ext.DefaultHandler2;
27
28 import org.jdom.Attribute;
29 import org.jdom.AttributeType;
30 import org.jdom.CDATA;
31 import org.jdom.Comment;
32 import org.jdom.Content;
33 import org.jdom.DocType;
34 import org.jdom.Document;
35 import org.jdom.Element;
36 import org.jdom.EntityRef;
37 import org.jdom.IllegalDataException;
38 import org.jdom.JDOMException;
39 import org.jdom.Namespace;
40 import org.jdom.ProcessingInstruction;
41 import org.jdom.Text;
42 import org.jdom.UncheckedJDOMFactory;
43 import org.jdom.input.SAXBuilder;
44 import org.jdom.input.StAXStreamBuilder;
45 import org.jdom.input.stax.DefaultStAXFilter;
46 import org.jdom.output.Format;
47 import org.jdom.output.Format.TextMode;
48 import org.jdom.output.SAXOutputter;
49 import org.jdom.output.StAXStreamOutputter;
50 import org.jdom.output.support.AbstractStAXStreamProcessor;
51 import org.jdom.output.support.StAXStreamProcessor;
52 import org.jdom.test.util.UnitTestUtil;
53
54 @SuppressWarnings("javadoc")
55 public final class TestStAXStreamOutputter extends AbstractTestOutputter {
56
57
58 private static final XMLOutputFactory soutfactory = XMLOutputFactory.newInstance();
59 private static final XMLInputFactory sinfactory = XMLInputFactory.newInstance();
60
61 private static final class OutWrapper {
62 private final StringWriter swriter = new StringWriter();
63 private final StAXStreamOutputter stax;
64 private final XMLStreamWriter xwriter;
65 private int from = 0, to = -1;
66
67 public OutWrapper(Format format) {
68 try {
69 xwriter = soutfactory.createXMLStreamWriter(swriter);
70 stax = new StAXStreamOutputter(format);
71 } catch (Exception xse) {
72 throw new IllegalStateException("Cannot construct: See Cause", xse);
73 }
74 }
75
76 public void setMarkFrom() {
77 try {
78 xwriter.flush();
79 } catch (XMLStreamException e) {
80 throw new IllegalStateException("Cannot flush(): See Cause", e);
81 }
82 from = swriter.getBuffer().length();
83 }
84
85 public void setMarkTo() {
86 try {
87 xwriter.flush();
88 } catch (XMLStreamException e) {
89 throw new IllegalStateException("Cannot flush(): See Cause", e);
90 }
91 to = swriter.getBuffer().length();
92 }
93
94 @Override
95 public String toString() {
96 return to >= 0 ? swriter.getBuffer().substring(from, to) :
97 swriter.getBuffer().substring(from);
98 }
99
100
101
102 public StAXStreamOutputter getStax() {
103 return stax;
104 }
105
106 public void close() {
107 try {
108 xwriter.close();
109 } catch (XMLStreamException e) {
110 throw new IllegalStateException("Cannot flush(): See Cause", e);
111 }
112 }
113
114 public XMLStreamWriter getStream() {
115 return xwriter;
116 }
117
118 }
119
120 public TestStAXStreamOutputter() {
121 super(false, false, false, false, false);
122 }
123
124 @Override
125 public String outputDocumentAsString(Format format, Document doc) {
126 OutWrapper ow = new OutWrapper(format);
127 try {
128 ow.getStax().output(doc, ow.getStream());
129 } catch (XMLStreamException e) {
130 throw new IllegalStateException(e);
131 }
132 ow.close();
133 return ow.toString();
134 }
135
136 @Override
137 public String outputDocTypeAsString(Format format, DocType doctype) {
138 OutWrapper ow = new OutWrapper(format);
139 try {
140 ow.getStream().writeStartDocument();
141 ow.setMarkFrom();
142 ow.getStax().output(doctype, ow.getStream());
143 ow.setMarkTo();
144 ow.getStream().writeEndDocument();
145 } catch (XMLStreamException e) {
146 throw new IllegalStateException(e);
147 }
148 ow.close();
149 return ow.toString();
150 }
151
152 @Override
153 public String outputElementAsString(Format format, Element element) {
154 OutWrapper ow = new OutWrapper(format);
155 try {
156 ow.getStream().writeStartDocument();
157 ow.setMarkFrom();
158 ow.getStax().output(element, ow.getStream());
159 ow.setMarkTo();
160 ow.getStream().writeEndDocument();
161 } catch (XMLStreamException e) {
162 throw new IllegalStateException(e);
163 }
164 ow.close();
165 return ow.toString();
166 }
167
168 @Override
169 public String outputListAsString(Format format, List<? extends Content> list) {
170 OutWrapper ow = new OutWrapper(format);
171 try {
172 ow.getStream().writeStartDocument();
173 ow.getStream().writeStartElement("root");
174 ow.getStream().writeCharacters("");
175 ow.setMarkFrom();
176 ow.getStax().output(list, ow.getStream());
177 ow.setMarkTo();
178 ow.getStream().writeEndElement();
179 ow.getStream().writeEndDocument();
180 } catch (XMLStreamException e) {
181 throw new IllegalStateException(e);
182 }
183 ow.close();
184 return ow.toString();
185 }
186
187 @Override
188 public String outputCDataAsString(Format format, CDATA cdata) {
189 OutWrapper ow = new OutWrapper(format);
190 try {
191 ow.getStream().writeStartDocument();
192 ow.getStream().writeStartElement("root");
193 ow.getStream().writeCharacters("");
194 ow.setMarkFrom();
195 ow.getStax().output(cdata, ow.getStream());
196 ow.setMarkTo();
197 ow.getStream().writeEndElement();
198 ow.getStream().writeEndDocument();
199 } catch (XMLStreamException e) {
200 throw new IllegalStateException(e);
201 }
202 ow.close();
203 return ow.toString();
204 }
205
206 @Override
207 public String outputTextAsString(Format format, Text text) {
208 OutWrapper ow = new OutWrapper(format);
209 try {
210 ow.getStream().writeStartDocument();
211 ow.getStream().writeStartElement("root");
212 ow.getStream().writeCharacters("");
213 ow.setMarkFrom();
214 ow.getStax().output(text, ow.getStream());
215 ow.setMarkTo();
216 ow.getStream().writeEndElement();
217 ow.getStream().writeEndDocument();
218 } catch (XMLStreamException e) {
219 throw new IllegalStateException(e);
220 }
221 ow.close();
222 return ow.toString();
223 }
224
225 @Override
226 public String outputCommentAsString(Format format, Comment comment) {
227 OutWrapper ow = new OutWrapper(format);
228 try {
229 ow.getStream().writeStartDocument();
230 ow.setMarkFrom();
231 ow.getStax().output(comment, ow.getStream());
232 ow.setMarkTo();
233 ow.getStream().writeEndDocument();
234 } catch (XMLStreamException e) {
235 throw new IllegalStateException(e);
236 }
237 ow.close();
238 return ow.toString();
239 }
240
241 @Override
242 public String outputPIAsString(Format format, ProcessingInstruction pi) {
243 OutWrapper ow = new OutWrapper(format);
244 try {
245 ow.getStream().writeStartDocument();
246 ow.setMarkFrom();
247 ow.getStax().output(pi, ow.getStream());
248 ow.setMarkTo();
249 ow.getStream().writeEndDocument();
250 } catch (XMLStreamException e) {
251 throw new IllegalStateException(e);
252 }
253 ow.close();
254 return ow.toString();
255 }
256
257 @Override
258 public String outputEntityRefAsString(Format format, EntityRef entity) {
259 OutWrapper ow = new OutWrapper(format);
260 try {
261 ow.getStream().writeStartDocument();
262 ow.getStream().writeStartElement("root");
263 ow.getStream().writeCharacters("");
264 ow.setMarkFrom();
265 ow.getStax().output(entity, ow.getStream());
266 ow.setMarkTo();
267 ow.getStream().writeEndElement();
268 ow.getStream().writeEndDocument();
269 } catch (XMLStreamException e) {
270 throw new IllegalStateException(e);
271 }
272 ow.close();
273 return ow.toString();
274 }
275
276 @Override
277 public String outputElementContentString(Format format, Element element) {
278 OutWrapper ow = new OutWrapper(format);
279 try {
280 ow.getStream().writeStartDocument();
281 ow.getStream().writeStartElement("root");
282 ow.getStream().writeCharacters("");
283 ow.setMarkFrom();
284 ow.getStax().outputElementContent(element, ow.getStream());
285 ow.setMarkTo();
286 ow.getStream().writeEndElement();
287 ow.getStream().writeEndDocument();
288 } catch (XMLStreamException e) {
289 throw new IllegalStateException(e);
290 }
291 ow.close();
292 return ow.toString();
293 }
294
295 @Test
296 @Override // because omit still adds declaration....
297 public void testOutputDocumentOmitDeclaration() {
298 Document doc = new Document();
299 doc.addContent(new Element("root"));
300 FormatSetup setup = new FormatSetup() {
301 @Override
302 public void setup(Format fmt) {
303 fmt.setOmitDeclaration(true);
304 }
305 };
306 String rtdec = "<?xml version=\"1.0\" ?>\n<root />\n";
307 checkOutput(doc, setup,
308 rtdec,
309 rtdec,
310 rtdec,
311 rtdec,
312 rtdec);
313 }
314
315 @Test @Ignore
316 public void test_HighSurrogatePair() throws XMLStreamException, IOException, JDOMException {
317 SAXBuilder builder = new SAXBuilder();
318 builder.setExpandEntities(true);
319 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>&#x10000; &#x10000;</root>"));
320
321 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
322 StAXStreamOutputter outputter = new StAXStreamOutputter(format);
323 ByteArrayOutputStream sw = new ByteArrayOutputStream();
324 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(sw, "ISO-8859-1");
325 outputter.output(doc, xsw);
326 String xml = sw.toString();
327 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
328 "<root>&#xd800;&#xdc00; &#xd800;&#xdc00;</root>" + format.getLineSeparator(), xml);
329 }
330
331 @Test @Ignore
332 public void test_HighSurrogatePairDecimal() throws JDOMException, IOException, XMLStreamException {
333 SAXBuilder builder = new SAXBuilder();
334 builder.setExpandEntities(true);
335 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>&#x10000; &#65536;</root>"));
336 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
337 StAXStreamOutputter outputter = new StAXStreamOutputter(format);
338 ByteArrayOutputStream baos = new ByteArrayOutputStream();
339 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(baos, "ISO-8859-1");
340 outputter.output(doc, xsw);
341 String xml = baos.toString();
342 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
343 "<root>&#xd800;&#xdc00; &#xd800;&#xdc00;</root>" + format.getLineSeparator(), xml);
344 }
345
346 @Test @Ignore
347 public void test_HighSurrogateAttPair() throws JDOMException, IOException, XMLStreamException {
348 SAXBuilder builder = new SAXBuilder();
349 builder.setExpandEntities(true);
350 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root att=\"&#x10000; &#x10000;\" />"));
351 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
352 StAXStreamOutputter outputter = new StAXStreamOutputter(format);
353 ByteArrayOutputStream baos = new ByteArrayOutputStream();
354 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(baos, "ISO-8859-1");
355 outputter.output(doc, xsw);
356 String xml = baos.toString();
357 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
358 "<root att=\"&#xd800;&#xdc00; &#xd800;&#xdc00;\"/>" + format.getLineSeparator(), xml);
359 }
360
361 @Test @Ignore
362 public void test_HighSurrogateAttPairDecimal() throws JDOMException, IOException, XMLStreamException {
363 SAXBuilder builder = new SAXBuilder();
364 builder.setExpandEntities(true);
365 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root att=\"&#x10000; &#65536;\" />"));
366 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
367 StAXStreamOutputter outputter = new StAXStreamOutputter(format);
368 ByteArrayOutputStream baos = new ByteArrayOutputStream();
369 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(baos, "ISO-8859-1");
370 outputter.output(doc, xsw);
371 String xml = baos.toString();
372 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
373 "<root att=\"&#xd800;&#xdc00; &#xd800;&#xdc00;\"/>" + format.getLineSeparator(), xml);
374 }
375
376 // Construct a raw surrogate pair character and confirm it outputs hex escaped
377 @Test @Ignore
378 public void test_RawSurrogatePair() throws JDOMException, IOException, XMLStreamException {
379 SAXBuilder builder = new SAXBuilder();
380 builder.setExpandEntities(true);
381 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>\uD800\uDC00</root>"));
382 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
383 StAXStreamOutputter outputter = new StAXStreamOutputter(format);
384 ByteArrayOutputStream baos = new ByteArrayOutputStream();
385 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(baos, "ISO-8859-1");
386 outputter.output(doc, xsw);
387 String xml = baos.toString();
388 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
389 "<root>&#xd800;&#xdc00;</root>" + format.getLineSeparator(), xml);
390 }
391
392 // Construct a raw surrogate pair character and confirm it outputs hex escaped, when UTF-8 too
393 @Test
394 public void test_RawSurrogatePairUTF8() throws JDOMException, IOException, XMLStreamException {
395 SAXBuilder builder = new SAXBuilder();
396 builder.setExpandEntities(true);
397 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>\uD800\uDC00</root>"));
398 Format format = Format.getCompactFormat().setEncoding("UTF-8");
399 StAXStreamOutputter outputter = new StAXStreamOutputter(format);
400 StringWriter baos = new StringWriter();
401 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(baos);
402 outputter.output(doc, xsw);
403 String xml = baos.toString();
404 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + format.getLineSeparator() +
405 "<root>\uD800\uDC00</root>" + format.getLineSeparator(), xml);
406 }
407
408 // Construct illegal XML and check if the parser notices
409 @Test
410 public void test_ErrorSurrogatePair() throws JDOMException, IOException {
411 SAXBuilder builder = new SAXBuilder();
412 builder.setExpandEntities(true);
413 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root></root>"));
414 try {
415 doc.getRootElement().setText("\uD800\uDBFF");
416 fail("Illegal surrogate pair should have thrown an exception");
417 }
418 catch (IllegalDataException e) {
419 // do nothing
420 } catch (Exception e) {
421 fail ("Unexpected exception " + e.getClass());
422 }
423 }
424
425 // Manually construct illegal XML and make sure the outputter notices
426 @Test
427 public void test_ErrorSurrogatePairOutput() throws JDOMException, IOException, XMLStreamException {
428 SAXBuilder builder = new SAXBuilder();
429 builder.setExpandEntities(true);
430 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root></root>"));
431 Text t = new UncheckedJDOMFactory().text("\uD800\uDBFF");
432 doc.getRootElement().setContent(t);
433 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
434 StAXStreamOutputter outputter = new StAXStreamOutputter(format);
435 ByteArrayOutputStream baos = new ByteArrayOutputStream();
436 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(baos);
437 try {
438 outputter.output(doc, xsw);
439 fail("Illegal surrogate pair output should have thrown an exception");
440 }
441 catch (XMLStreamException e) {
442 // do nothing
443 } catch (Exception e) {
444 fail ("Unexpected exception " + e.getClass());
445 }
446 }
447
448
449 @Test
450 public void testStAXStreamOutputter() {
451 StAXStreamOutputter out = new StAXStreamOutputter();
452 TestFormat.checkEquals(out.getFormat(), Format.getRawFormat());
453 }
454
455
456 @Test
457 public void testStAXStreamOutputterFormat() {
458 Format mine = Format.getCompactFormat();
459 mine.setEncoding("US-ASCII");
460 StAXStreamOutputter out = new StAXStreamOutputter(mine);
461 TestFormat.checkEquals(mine, out.getFormat());
462 }
463
464 // @Test
465 // public void testXMLOutputterXMLOutputter() {
466 // Format mine = Format.getCompactFormat();
467 // StAXStreamProcessor xoutp = new StAXStreamOutputter().getStAXStream();
468 // mine.setEncoding("US-ASCII");
469 // // double-construct it.
470 // StAXStreamOutputter out = new StAXStreamOutputter();
471 // TestFormat.checkEquals(mine, out.getFormat());
472 // assertTrue(xoutp == out.getXMLOutputProcessor());
473 // }
474
475 @Test
476 public void testStAXStreamOutputterXMLOutputProcessor() {
477 StAXStreamProcessor xoutp = new AbstractStAXStreamProcessor() {
478 // nothing;
479 };
480 // double-constrcut it.
481 StAXStreamOutputter out = new StAXStreamOutputter(xoutp);
482 TestFormat.checkEquals(Format.getRawFormat(), out.getFormat());
483 assertTrue(xoutp == out.getStAXStream());
484 }
485
486 @Test
487 public void testFormat() {
488 Format mine = Format.getCompactFormat();
489 mine.setEncoding("US-ASCII");
490 // double-constcut it.
491 StAXStreamOutputter out = new StAXStreamOutputter();
492 TestFormat.checkEquals(Format.getRawFormat(), out.getFormat());
493 out.setFormat(mine);
494 TestFormat.checkEquals(mine, out.getFormat());
495 }
496
497 @Test
498 public void testStAXStreamOutputProcessor() {
499 StAXStreamProcessor xoutp = new AbstractStAXStreamProcessor() {
500 // nothing;
501 };
502 // double-constcut it.
503 StAXStreamOutputter out = new StAXStreamOutputter();
504 StAXStreamProcessor xop = out.getStAXStream();
505 out.setStAXStreamProcessor(xoutp);
506 assertTrue(xoutp != xop);
507 assertTrue(xoutp == out.getStAXStream());
508 }
509
510 @Test
511 public void testTrimFullWhite() throws XMLStreamException {
512 // See issue #31.
513 // https://github.com/hunterhacker/jdom/issues/31
514 // This tests should pass when issue 31 is resolved.
515 Element root = new Element("root");
516 root.addContent(new Text(" "));
517 root.addContent(new Text("x"));
518 root.addContent(new Text(" "));
519 Format mf = Format.getRawFormat();
520 mf.setTextMode(TextMode.TRIM_FULL_WHITE);
521 StAXStreamOutputter xout = new StAXStreamOutputter(mf);
522 StringWriter sw = new StringWriter();
523 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(sw);
524 xout.output(root, xsw);
525 assertEquals("<root> x </root>", sw.toString());
526 }
527
528 @Test
529 public void testClone() {
530 StAXStreamOutputter xo = new StAXStreamOutputter();
531 assertTrue(xo != xo.clone());
532 }
533
534 @Test
535 public void testToString() {
536 Format fmt = Format.getCompactFormat();
537 fmt.setLineSeparator("\n\t ");
538 StAXStreamOutputter out = new StAXStreamOutputter(fmt);
539 assertNotNull(out.toString());
540 }
541
542 /*
543 * The following are borrowed from the TestSAXOutputter
544 * The effect is that we compare the StAX string output with the re-parsed
545 * value of the input.
546 */
547
548 private void roundTripDocument(Document doc) {
549 roundTripDocument(doc, true);
550 roundTripDocument(doc, false);
551 }
552
553 private void roundTripDocument(Document doc, boolean repairing) {
554 StAXStreamOutputter xout = new StAXStreamOutputter(Format.getRawFormat());
555 // create a String representation of the input.
556 if (doc.hasRootElement()) {
557 normalizeAttributes(doc.getRootElement());
558 }
559
560 try {
561 StringWriter sw = new StringWriter();
562 soutfactory.setProperty("javax.xml.stream.isRepairingNamespaces", repairing);
563 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(sw);
564 xout.output(doc, xsw);
565 xsw.close();
566 Document expect = new SAXBuilder().build(new StringReader(sw.toString()));
567 // convert the input to a SAX Stream
568 UnitTestUtil.compare(doc, expect);
569
570 StAXStreamBuilder sbuilder = new StAXStreamBuilder();
571
572 StringReader car = new StringReader(sw.toString());
573 XMLStreamReader xsr = sinfactory.createXMLStreamReader(car);
574
575 Document backagain = sbuilder.build(xsr);
576 xsr.close();
577
578 UnitTestUtil.compare(expect, backagain);
579
580 } catch (Exception e) {
581 failException("Failed to round-trip the document with exception: "
582 + e.getMessage(), e);
583 }
584 }
585
586 private void roundTripElement(Element emt) {
587
588 try {
589 StAXStreamOutputter xout = new StAXStreamOutputter(Format.getRawFormat());
590
591 StringWriter sw = new StringWriter();
592 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(sw);
593 xout.output(emt, xsw);
594 xsw.close();
595 String expect = sw.toString();
596
597 StAXStreamBuilder sbuilder = new StAXStreamBuilder();
598
599 XMLStreamReader xsr = sinfactory.createXMLStreamReader(new StringReader(expect));
600 assertTrue(xsr.getEventType() == XMLStreamConstants.START_DOCUMENT);
601 assertTrue(xsr.hasNext());
602 xsr.next();
603
604 Element backagain = (Element)sbuilder.fragment(xsr);
605
606 // convert the input to a SAX Stream
607
608 sw.getBuffer().setLength(0);
609 xsw = soutfactory.createXMLStreamWriter(sw);
610 xout.output(backagain, xsw);
611 xsw.close();
612
613 String actual = sw.toString();
614 assertEquals(expect, actual);
615 } catch (Exception e) {
616 failException("Failed to round-trip the document with exception: "
617 + e.getMessage(), e);
618 }
619 }
620
621 private void roundTripFragment(List<Content> content) {
622 try {
623 StAXStreamOutputter xout = new StAXStreamOutputter(Format.getRawFormat());
624
625 StringWriter sw = new StringWriter();
626 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(sw);
627 xout.output(content, xsw);
628 xsw.close();
629 String expect = sw.toString();
630
631 StAXStreamBuilder sbuilder = new StAXStreamBuilder();
632
633 XMLStreamReader xsr = sinfactory.createXMLStreamReader(new StringReader(expect));
634 // assertTrue(xsr.getEventType() == XMLStreamConstants.START_DOCUMENT);
635 // assertTrue(xsr.hasNext());
636 // xsr.next();
637
638 List<Content> backagain = sbuilder.buildFragments(xsr, new DefaultStAXFilter());
639
640 // convert the input to a SAX Stream
641
642 sw.getBuffer().setLength(0);
643 xsw = soutfactory.createXMLStreamWriter(sw);
644 xout.output(backagain, xsw);
645 xsw.close();
646
647 String actual = sw.toString();
648 assertEquals(expect, actual);
649 } catch (Exception e) {
650 failException("Failed to round-trip the document with exception: "
651 + e.getMessage(), e);
652 }
653
654 }
655
656 private void roundTripFragment(Content content) {
657 try {
658 StAXStreamOutputter xout = new StAXStreamOutputter(Format.getRawFormat());
659
660 StringWriter sw = new StringWriter();
661 XMLStreamWriter xsw = soutfactory.createXMLStreamWriter(sw);
662 switch(content.getCType()) {
663 case CDATA :
664 xout.output((CDATA)content, xsw);
665 break;
666 case Text:
667 xout.output((Text)content, xsw);
668 break;
669 case Comment:
670 xout.output((Comment)content, xsw);
671 break;
672 case DocType:
673 xout.output((DocType)content, xsw);
674 break;
675 case Element:
676 xout.output((Element)content, xsw);
677 break;
678 case EntityRef:
679 xout.output((EntityRef)content, xsw);
680 break;
681 case ProcessingInstruction:
682 xout.output((ProcessingInstruction)content, xsw);
683 break;
684 default:
685 throw new IllegalStateException(content.getCType().toString());
686 }
687 xsw.close();
688 String expect = sw.toString();
689
690 StAXStreamBuilder sbuilder = new StAXStreamBuilder();
691
692 Content backagain = sbuilder.fragment(
693 sinfactory.createXMLStreamReader(new StringReader(expect)));
694
695 // convert the input to a SAX Stream
696
697 sw.getBuffer().setLength(0);
698 xsw = soutfactory.createXMLStreamWriter(sw);
699 switch(content.getCType()) {
700 case CDATA :
701 xout.output((CDATA)backagain, xsw);
702 break;
703 case Text:
704 xout.output((Text)backagain, xsw);
705 break;
706 case Comment:
707 xout.output((Comment)backagain, xsw);
708 break;
709 case DocType:
710 xout.output((DocType)backagain, xsw);
711 break;
712 case Element:
713 xout.output((Element)backagain, xsw);
714 break;
715 case EntityRef:
716 xout.output((EntityRef)backagain, xsw);
717 break;
718 case ProcessingInstruction:
719 xout.output((ProcessingInstruction)backagain, xsw);
720 break;
721 default:
722 throw new IllegalStateException(backagain.getCType().toString());
723 }
724 xsw.close();
725
726 String actual = sw.toString();
727 assertEquals(expect, actual);
728 } catch (Exception e) {
729 failException("Failed to round-trip the document with exception: "
730 + e.getMessage(), e);
731 }
732 }
733
734 @Test
735 public void testRTOutputDocumentSimple() {
736 Document doc = new Document(new Element("root"));
737 roundTripDocument(doc);
738 }
739
740 @Test
741 public void testRTOutputDocumentDefaultNS() {
742 Element root = new Element("root", "http://jdom/noprefix");
743 Document doc = new Document(root);
744 roundTripDocument(doc);
745 }
746
747 @Test
748 @Ignore
749 // TODO
750 public void testRTOutputDocumentFull() {
751 Document doc = new Document();
752 DocType dt = new DocType("root");
753 dt.setInternalSubset(" ");
754 doc.addContent(dt);
755 doc.addContent(new Comment("This is a document"));
756 doc.addContent(new ProcessingInstruction("jdomtest", ""));
757 Element e = new Element("root");
758 e.addContent(new EntityRef("ref"));
759 doc.addContent(e);
760 roundTripDocument(doc);
761 }
762
763 @Test
764 public void testOutputDocumentRootAttNS() {
765 Document doc = new Document();
766 Element e = new Element("root");
767 e.setAttribute(new Attribute("att", "val", Namespace.getNamespace("ans", "mynamespace")));
768 doc.addContent(e);
769 roundTripDocument(doc);
770 }
771
772 @Test
773 public void testOutputDocumentAttributes() {
774 Element emt = new Element("root");
775 emt.setAttribute("att", "val");
776 Document doc = new Document(emt);
777 roundTripDocument(doc);
778 }
779
780 @Test
781 public void testOutputDocumentNamespaces() {
782 Element emt = new Element("root", Namespace.getNamespace("ns", "myns"));
783 Namespace ans = Namespace.getNamespace("ans", "attributens");
784 emt.addNamespaceDeclaration(ans);
785 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
786 emt.setAttribute(new Attribute("att", "val", ans));
787 emt.addContent(new Element("child", Namespace.getNamespace("", "childuri")));
788 Document doc = new Document(emt);
789 roundTripDocument(doc);
790 }
791
792 @Test
793 public void testRTOutputList() {
794 List<Content> list = new ArrayList<Content>();
795 list.add(new ProcessingInstruction("jdomtest", ""));
796 list.add(new Comment("comment"));
797 list.add(new Element("root"));
798 roundTripFragment(list);
799 }
800
801 @Test
802 public void testOutputElementAttributes() {
803 Element emt = new Element("root");
804 emt.setAttribute("att", "val");
805 emt.setAttribute(new Attribute("attx", "valx", AttributeType.UNDECLARED));
806 roundTripElement(emt);
807 }
808
809 @Test
810 public void testRTOutputElementNamespaces() {
811 Element emt = new Element("root", Namespace.getNamespace("ns", "myns"));
812 Namespace ans = Namespace.getNamespace("ans", "attributens");
813 emt.addNamespaceDeclaration(ans);
814 emt.addNamespaceDeclaration(Namespace.getNamespace("two", "two"));
815 emt.setAttribute(new Attribute("att", "val", ans));
816 emt.addContent(new Element("child", Namespace.getNamespace("", "childns")));
817 roundTripElement(emt);
818 }
819
820 @Test
821 @Ignore
822 // TODO
823 public void testOutputFragmentList() {
824 List<Content> list = new ArrayList<Content>();
825 list.add(new ProcessingInstruction("jdomtest", ""));
826 list.add(new Comment("comment"));
827 list.add(new CDATA("foo"));
828 list.add(new Element("root"));
829 list.add(new Text("bar"));
830 roundTripFragment(list);
831 }
832
833 @Test
834 @Ignore
835 // TODO
836 public void testOutputFragmentContent() {
837 roundTripFragment(new ProcessingInstruction("jdomtest", ""));
838 roundTripFragment(new Comment("comment"));
839 roundTripFragment(new CDATA("foo"));
840 roundTripFragment(new Element("root"));
841 roundTripFragment(new Text("bar"));
842 }
843
844 @Test
845 public void testOutputNullContent() throws JDOMException {
846 DefaultHandler2 handler = new DefaultHandler2() {
847 @Override
848 public void startDocument() throws SAXException {
849 throw new SAXException("SHould not be reaching this, ever");
850 }
851 };
852 SAXOutputter saxout = new SAXOutputter(handler, handler, handler, handler, handler);
853
854 Document doc = null;
855 Element emt = null;
856 List<Content> list = null;
857 List<Content> empty = new ArrayList<Content>();
858 saxout.output(doc);
859 saxout.output(emt);
860 saxout.output(list);
861 saxout.output(empty);
862 saxout.outputFragment(emt);
863 saxout.outputFragment(list);
864 saxout.outputFragment(empty);
865 }
866
867
868 }
0 package org.jdom.test.cases.output;
1
2 import static org.junit.Assert.fail;
3
4 import java.io.IOException;
5 import java.io.Writer;
6
7 import org.jdom.IllegalDataException;
8 import org.jdom.Text;
9 import org.jdom.output.Format;
10 import org.jdom.output.support.AbstractXMLOutputProcessor;
11 import org.jdom.output.support.FormatStack;
12
13 import org.junit.Test;
14
15 /**
16 *
17 * @author Rolf Lear
18 *
19 */
20 @SuppressWarnings("javadoc")
21 public class TestXMLOutputProcessor extends AbstractXMLOutputProcessor {
22
23 private static final String formatChar(char ch) {
24 return String.format(" char '%s' (0x%04x)", "" + ch, (int)ch);
25 }
26
27 private static final class CheckWriter extends Writer {
28 private final char[] expect;
29 private int cursor = 0;
30 private CheckWriter(String expect) {
31 this.expect = expect.toCharArray();
32 }
33
34 private final String formatLast() {
35 if (cursor < 10) {
36 return "\"" + new String(expect, 0, cursor) + "\"";
37 }
38 return "\"...{x" + (cursor - 10) + "}" + new String(expect, cursor - 10, 10) + "\"";
39 }
40
41 private void checkChar(char ch) {
42 if (cursor >= expect.length) {
43 fail("We have additional characters. Not expecting " +
44 formatChar(ch) + " after " + formatLast());
45 }
46 if (ch != expect[cursor]) {
47 fail("Expecting " + formatChar(expect[cursor]) + " not " +
48 formatChar(ch) + " after " + formatLast());
49 }
50 cursor++;
51 }
52
53 @Override
54 public void write(char[] cbuf, int off, int len) {
55 for (int i = 0; i < len; i++) {
56 checkChar(cbuf[off + i]);
57 }
58
59 }
60 @Override
61 public void write(int c) {
62 checkChar((char)c);
63 }
64
65 @Override
66 public void close() {
67 flush();
68 }
69
70 @Override
71 public void flush() {
72 // this is called after a complete output.
73 if (cursor < expect.length) {
74 fail ("Expected additional characters after " + formatLast());
75 }
76 }
77
78 }
79
80 private final Format RAW;
81 private final FormatStack fsraw;
82
83 public TestXMLOutputProcessor() {
84 RAW = Format.getRawFormat();
85 RAW.setEncoding("US-ASCII");
86 fsraw = new FormatStack(RAW);
87 }
88
89
90 @Test
91 public void testAttributeEscapedEntitiesFilter() throws IOException {
92 CheckWriter cw = new CheckWriter(" &quot; &#x153; ' &amp; &lt; &gt; &#xD; &#xA; &#x9; &#x10000; ");
93 attributeEscapedEntitiesFilter(cw, fsraw, " \" \u0153 ' & < > \r \n \t \uD800\uDC00 ");
94 cw.close();
95 }
96
97 @Test
98 public void testAttributeEscapedEntitiesFilterASCII() throws IOException {
99 CheckWriter cw = new CheckWriter(" &quot; ' &amp; &lt; &gt; &#xD; &#xA; &#x9; &#x10000; ");
100 attributeEscapedEntitiesFilter(cw, fsraw, " \" ' & < > \r \n \t \uD800\uDC00 ");
101 cw.close();
102 }
103
104 @Test
105 public void testAttributeEscapedEntitiesFilterErrorMid() {
106 CheckWriter cw = new CheckWriter(" &quot; ' &amp; &lt; &gt; &#xD; &#xA; &#x9; &#x10000; ");
107 try {
108 attributeEscapedEntitiesFilter(cw, fsraw, " \" ' & < > \r \n \t \uD800 \uDC00 ");
109 fail("Should have missed the low surrogate...");
110 } catch (IllegalDataException ide) {
111 //good
112 } catch (Exception e) {
113 e.printStackTrace();
114 fail("Expected IllegalDataException but got " + e.getClass());
115 }
116 }
117
118 @Test
119 public void testAttributeEscapedEntitiesFilterErrorEnd() {
120 CheckWriter cw = new CheckWriter(" &quot; ' &amp; &lt; &gt; &#xD; &#xA; &#x9; &#x10000; ");
121 try {
122 attributeEscapedEntitiesFilter(cw, fsraw, " \" ' & < > \r \n \t \uD800");
123 fail("Should have missed the low surrogate...");
124 } catch (IllegalDataException ide) {
125 //good
126 } catch (Exception e) {
127 e.printStackTrace();
128 fail("Expected IllegalDataException but got " + e.getClass());
129 }
130 }
131
132 @Test
133 public void testAttributeEscapedEntitiesFilterNoEscape() throws IOException {
134 CheckWriter cw = new CheckWriter(" \" ' & < > \r \n \t \uD800\uDC00 ");
135 FormatStack tmps = new FormatStack(RAW);
136 tmps.setEscapeOutput(false);
137 attributeEscapedEntitiesFilter(cw, tmps, " \" ' & < > \r \n \t \uD800\uDC00 ");
138 cw.close();
139 }
140
141 @Test
142 public void testTextRawWriterString() throws IOException {
143 CheckWriter cw = new CheckWriter(" \" ' & < > \r \n \t \uD800\uDC00 ");
144 textRaw(cw, " \" ' & < > \r \n \t \uD800\uDC00 ");
145 cw.close();
146 }
147
148 @Test
149 public void testTextRawWriterChar() throws IOException {
150 CheckWriter cw = new CheckWriter(" ");
151 textRaw(cw, ' ');
152 cw.close();
153 }
154
155 @Test
156 public void testTextEntityRef() throws IOException {
157 CheckWriter cw = new CheckWriter("&er;");
158 textEntityRef(cw, "er");
159 cw.close();
160 }
161
162 @Test
163 public void testTextCDATARaw() throws IOException {
164 CheckWriter cw = new CheckWriter("<![CDATA[ \" ' & < > \r \n \t \uD800\uDC00 ]]>");
165 textCDATA(cw, " \" ' & < > \r \n \t \uD800\uDC00 ");
166 cw.close();
167 }
168
169 @Test
170 public void testTextCDATARawEmpty() throws IOException {
171 CheckWriter cw = new CheckWriter("<![CDATA[]]>");
172 textCDATA(cw, "");
173 cw.close();
174 }
175
176 @Test
177 public void testTextEscapedEntitiesFilter() throws IOException {
178 CheckWriter cw = new CheckWriter(" \" &#x153; ' &amp; &lt; &gt; &#xD; \r\n \t &#x10000; ");
179 String data = " \" \u0153 ' & < > \r \n \t \uD800\uDC00 ";
180 printText(cw, fsraw, new Text(data));
181 cw.close();
182 }
183
184 @Test
185 public void testTextEscapedEntitiesFilterErrorMid() {
186 CheckWriter cw = new CheckWriter(" \" ' &amp; &lt; &gt; &#xD; \r\n \t &#x10000; ");
187 // the HighSurrogate is broken here....
188 try {
189 String data = " \" ' & < > \r \n \t \uD800 \uDC00 ";
190 printText(cw, fsraw, new Text(data));
191 fail("Should have missed the low surrogate...");
192 } catch (IllegalDataException ide) {
193 //good
194 } catch (Exception e) {
195 e.printStackTrace();
196 fail("Expected IllegalDataException but got " + e.getClass());
197 }
198 }
199
200 @Test
201 public void testTextEscapedEntitiesFilterErrorEnd() {
202 CheckWriter cw = new CheckWriter(" \" ' &amp; &lt; &gt; &#xD; \r\n \t &#x10000; ");
203 // the HighSurrogate is broken here....
204 try {
205 String data = " \" ' & < > \r \n \t \uD800";
206 printText(cw, fsraw, new Text(data));
207 fail("Should have missed the low surrogate...");
208 } catch (IllegalDataException ide) {
209 //good
210 } catch (Exception e) {
211 e.printStackTrace();
212 fail("Expected IllegalDataException but got " + e.getClass());
213 }
214 }
215
216 @Test
217 public void testTextEscapedEntitiesFilterNoEscape() throws IOException {
218 CheckWriter cw = new CheckWriter(" \" ' & < > \r \n \t \uD800\uDC00 ");
219 String data = " \" ' & < > \r \n \t \uD800\uDC00 ";
220 FormatStack tmps = new FormatStack(RAW);
221 tmps.setEscapeOutput(false);
222 printText(cw, tmps, new Text(data));
223 cw.close();
224 }
225
226 @Test
227 public void testTextEscapeRaw() throws IOException {
228 CheckWriter cw = new CheckWriter(" \" ' &amp; &lt; &gt; &#xD; \r\n \t &#x10000; ");
229 String s = " \" ' & < > \r \n \t \uD800\uDC00 ";
230 printText(cw, fsraw, new Text(s));
231 cw.close();
232 }
233
234 @Test
235 public void testTextEscapeRawEmpty() throws IOException {
236 CheckWriter cw = new CheckWriter("");
237 printText(cw, fsraw, new Text(""));
238 cw.close();
239 }
240
241
242 // @Test
243 // public void testProcessWriterFormatDocument() {
244 //
245 // fail("Not yet implemented");
246 // }
247 //
248 // @Test
249 // public void testProcessWriterFormatDocType() {
250 // fail("Not yet implemented");
251 // }
252 //
253 // @Test
254 // public void testProcessWriterFormatElement() {
255 // fail("Not yet implemented");
256 // }
257 //
258 // @Test
259 // public void testProcessWriterFormatListOfQextendsContent() {
260 // fail("Not yet implemented");
261 // }
262 //
263 // @Test
264 // public void testProcessWriterFormatCDATA() {
265 // fail("Not yet implemented");
266 // }
267 //
268 // @Test
269 // public void testProcessWriterFormatText() {
270 // fail("Not yet implemented");
271 // }
272 //
273 // @Test
274 // public void testProcessWriterFormatComment() {
275 // fail("Not yet implemented");
276 // }
277 //
278 // @Test
279 // public void testProcessWriterFormatProcessingInstruction() {
280 // fail("Not yet implemented");
281 // }
282 //
283 // @Test
284 // public void testProcessWriterFormatEntityRef() {
285 // fail("Not yet implemented");
286 // }
287 //
288 // @Test
289 // public void testWriteWriterString() {
290 // fail("Not yet implemented");
291 // }
292 //
293 // @Test
294 // public void testWriteWriterChar() {
295 // fail("Not yet implemented");
296 // }
297 //
298 // @Test
299 // public void testPrintDocument() {
300 // fail("Not yet implemented");
301 // }
302 //
303 // @Test
304 // public void testPrintDeclaration() {
305 // fail("Not yet implemented");
306 // }
307 //
308 // @Test
309 // public void testPrintDocType() {
310 // fail("Not yet implemented");
311 // }
312 //
313 // @Test
314 // public void testPrintProcessingInstruction() {
315 // fail("Not yet implemented");
316 // }
317 //
318 // @Test
319 // public void testPrintComment() {
320 // fail("Not yet implemented");
321 // }
322 //
323 // @Test
324 // public void testPrintEntityRef() {
325 // fail("Not yet implemented");
326 // }
327 //
328 // @Test
329 // public void testPrintCDATA() {
330 // fail("Not yet implemented");
331 // }
332 //
333 // @Test
334 // public void testPrintText() {
335 // fail("Not yet implemented");
336 // }
337 //
338 // @Test
339 // public void testPrintElement() {
340 // fail("Not yet implemented");
341 // }
342 //
343 // @Test
344 // public void testPrintContent() {
345 // fail("Not yet implemented");
346 // }
347 //
348 // @Test
349 // public void testPrintTextConsecutive() {
350 // fail("Not yet implemented");
351 // }
352 //
353 // @Test
354 // public void testHelperContentDispatcher() {
355 // fail("Not yet implemented");
356 // }
357 //
358 // @Test
359 // public void testHelperTextType() {
360 // fail("Not yet implemented");
361 // }
362 //
363 // @Test
364 // public void testHelperRawTextType() {
365 // fail("Not yet implemented");
366 // }
367 //
368 // @Test
369 // public void testPrintNamespace() {
370 // fail("Not yet implemented");
371 // }
372 //
373 // @Test
374 // public void testPrintAttribute() {
375 // fail("Not yet implemented");
376 // }
377 //
378 // @Test
379 // public void testIsAllWhitespace() {
380 // fail("Not yet implemented");
381 // }
382 //
383 //
384 //
385
386 }
0 package org.jdom.test.cases.output;
1
2 /* Please run replic.pl on me ! */
3 /**
4 * Please put a description of your test here.
5 *
6 * @author unascribed
7 * @version 0.1
8 */
9
10 import org.jdom.*;
11 import org.jdom.input.SAXBuilder;
12 import org.jdom.output.Format;
13 import org.jdom.output.Format.TextMode;
14 import org.jdom.output.LineSeparator;
15 import org.jdom.output.XMLOutputter;
16 import org.jdom.output.support.AbstractXMLOutputProcessor;
17 import org.jdom.output.support.XMLOutputProcessor;
18 import org.junit.Ignore;
19 import org.junit.Test;
20 import org.junit.runner.JUnitCore;
21
22 import javax.xml.transform.Result;
23 import java.io.*;
24 import java.lang.reflect.Method;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import static org.junit.Assert.*;
30
31 @SuppressWarnings("javadoc")
32 public final class TestXMLOutputter extends AbstractTestOutputter {
33
34 /**
35 * The main method runs all the tests in the text ui
36 */
37 public static void main (String args[])
38 {
39 JUnitCore.runClasses(TestXMLOutputter.class);
40 }
41
42 public TestXMLOutputter() {
43 super(true, true, false, false, false);
44 }
45
46 private XMLOutputter getOutputter(Format format) {
47 return new XMLOutputter(format);
48 }
49
50 @Override
51 public String outputDocumentAsString(Format format, Document doc) {
52 return getOutputter(format).outputString(doc);
53 }
54
55 @Override
56 public String outputDocTypeAsString(Format format, DocType doctype) {
57 return getOutputter(format).outputString(doctype);
58 }
59
60 @Override
61 public String outputElementAsString(Format format, Element element) {
62 return getOutputter(format).outputString(element);
63 }
64
65 @Override
66 public String outputListAsString(Format format, List<? extends Content> list) {
67 return getOutputter(format).outputString(list);
68 }
69
70 @Override
71 public String outputCDataAsString(Format format, CDATA cdata) {
72 return getOutputter(format).outputString(cdata);
73 }
74
75 @Override
76 public String outputTextAsString(Format format, Text text) {
77 return getOutputter(format).outputString(text);
78 }
79
80 @Override
81 public String outputCommentAsString(Format format, Comment comment) {
82 return getOutputter(format).outputString(comment);
83 }
84
85 @Override
86 public String outputPIAsString(Format format, ProcessingInstruction pi) {
87 return getOutputter(format).outputString(pi);
88 }
89
90 @Override
91 public String outputEntityRefAsString(Format format, EntityRef entity) {
92 return getOutputter(format).outputString(entity);
93 }
94
95 @Override
96 public String outputElementContentString(Format format, Element element) {
97 StringWriter out = new StringWriter();
98 try {
99 getOutputter(format).outputElementContent(element, out); // output() flushes
100 } catch (IOException e) {
101 // swallow - will never happen.
102 }
103 return out.toString();
104 }
105
106 @Test @Ignore
107 @Override
108 public void testTextWhitespace() {
109 }
110
111 @Test @Ignore
112 @Override
113 public void testCDATAEmpty() {
114 }
115
116 @Test @Ignore
117 @Override
118 public void testCDATAWhitespace() {
119 }
120
121 @Test @Ignore
122 @Override
123 public void testMultiText() {
124 }
125
126 @Test @Ignore
127 @Override
128 public void testDocumentSimple() {
129 }
130
131 @Test @Ignore
132 @Override
133 public void testDocumentDocType() {
134 }
135
136 @Test @Ignore
137 @Override
138 public void testDocumentComment() {
139 }
140
141 @Test @Ignore
142 @Override
143 public void testOutputElementAttributeNotSpecifiedA() {
144 }
145
146 @Test @Ignore
147 @Override
148 public void testOutputElementAttributeNotSpecifiedB() {
149 }
150
151 @Test @Ignore
152 @Override
153 public void testOutputElementPreserveSpaceComplex() {
154 }
155
156 @Test @Ignore
157 @Override
158 public void testOutputElementMultiText() {
159 }
160
161 @Test @Ignore
162 @Override
163 public void testOutputElementMultiMostWhiteExpandEmpty() {
164 }
165
166 @Test @Ignore
167 @Override
168 public void testOutputElementMixedMultiCDATA() {
169 }
170
171 @Test @Ignore
172 @Override
173 public void testOutputElementMixedMultiEntityRef() {
174 }
175
176 @Test @Ignore
177 @Override
178 public void testOutputElementMixedMultiText() {
179 }
180
181 @Test @Ignore
182 @Override
183 public void testOutputElementMixedMultiZeroText() {
184 }
185
186 @Test @Ignore
187 @Override
188 public void testOutputElementInterleavedEmptyText() {
189 }
190
191 @Test @Ignore
192 @Override
193 public void testOutputElementMultiEntityLeftRight() {
194 }
195
196 @Test @Ignore
197 @Override
198 public void testOutputElementMultiTrimLeftRight() {
199 }
200
201 @Test @Ignore
202 @Override
203 public void testOutputElementMultiCDATALeftRight() {
204 }
205
206 @Test @Ignore
207 @Override
208 public void testOutputElementNamespaces() {
209 }
210
211 @Test @Ignore
212 @Override
213 public void testOutputDocumentSimple() {
214 }
215
216 @Test @Ignore
217 @Override
218 public void testOutputDocumentOmitEncoding() {
219 }
220
221 @Test @Ignore
222 @Override
223 public void testOutputDocumentOmitDeclaration() {
224 }
225
226 @Test @Ignore
227 @Override
228 public void testOutputDocumentFull() {
229 }
230
231 @Test @Ignore
232 @Override
233 public void testDeepNesting() {
234 }
235
236 @Test @Ignore
237 @Override
238 public void testOutputEscapedMixedMultiText() {
239 }
240
241
242 @Test
243 public void test_HighSurrogatePair() throws JDOMException, IOException {
244 SAXBuilder builder = new SAXBuilder();
245 builder.setExpandEntities(true);
246 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>&#x10000; &#x10000;</root>"));
247 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
248 XMLOutputter outputter = new XMLOutputter(format);
249 StringWriter sw = new StringWriter();
250 outputter.output(doc, sw);
251 String xml = sw.toString();
252 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
253 "<root>&#x10000; &#x10000;</root>" + format.getLineSeparator(), xml);
254 }
255
256 @Test
257 public void test_HighSurrogatePairDecimal() throws JDOMException, IOException {
258 SAXBuilder builder = new SAXBuilder();
259 builder.setExpandEntities(true);
260 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>&#x10000; &#65536;</root>"));
261 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
262 XMLOutputter outputter = new XMLOutputter(format);
263 ByteArrayOutputStream baos = new ByteArrayOutputStream();
264 outputter.output(doc, baos);
265 String xml = baos.toString();
266 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
267 "<root>&#x10000; &#x10000;</root>" + format.getLineSeparator(), xml);
268 }
269
270 @Test
271 public void test_HighSurrogateAttPair() throws JDOMException, IOException {
272 SAXBuilder builder = new SAXBuilder();
273 builder.setExpandEntities(true);
274 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root att=\"&#x10000; &#x10000;\" />"));
275 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
276 XMLOutputter outputter = new XMLOutputter(format);
277 ByteArrayOutputStream baos = new ByteArrayOutputStream();
278 outputter.output(doc, baos);
279 String xml = baos.toString();
280 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
281 "<root att=\"&#x10000; &#x10000;\" />" + format.getLineSeparator(), xml);
282 }
283
284 @Test
285 public void test_HighSurrogateAttPairDecimal() throws JDOMException, IOException {
286 SAXBuilder builder = new SAXBuilder();
287 builder.setExpandEntities(true);
288 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root att=\"&#x10000; &#65536;\" />"));
289 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
290 XMLOutputter outputter = new XMLOutputter(format);
291 ByteArrayOutputStream baos = new ByteArrayOutputStream();
292 outputter.output(doc, baos);
293 String xml = baos.toString();
294 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
295 "<root att=\"&#x10000; &#x10000;\" />" + format.getLineSeparator(), xml);
296 }
297
298 // Construct a raw surrogate pair character and confirm it outputs hex escaped
299 @Test
300 public void test_RawSurrogatePair() throws JDOMException, IOException {
301 SAXBuilder builder = new SAXBuilder();
302 builder.setExpandEntities(true);
303 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>\uD800\uDC00</root>"));
304 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
305 XMLOutputter outputter = new XMLOutputter(format);
306 ByteArrayOutputStream baos = new ByteArrayOutputStream();
307 outputter.output(doc, baos);
308 String xml = baos.toString();
309 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
310 "<root>&#x10000;</root>" + format.getLineSeparator(), xml);
311 }
312
313 // Construct a raw surrogate pair character and confirm it outputs hex escaped, when UTF-8 too
314 @Test
315 public void test_RawSurrogatePairUTF8() throws JDOMException, IOException {
316 SAXBuilder builder = new SAXBuilder();
317 builder.setExpandEntities(true);
318 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>\uD800\uDC00</root>"));
319 Format format = Format.getCompactFormat().setEncoding("UTF-8");
320 XMLOutputter outputter = new XMLOutputter(format);
321 ByteArrayOutputStream baos = new ByteArrayOutputStream();
322 outputter.output(doc, baos);
323 String xml = baos.toString();
324 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + format.getLineSeparator() +
325 "<root>&#x10000;</root>" + format.getLineSeparator(), xml);
326 }
327
328 // Construct illegal XML and check if the parser notices
329 @Test
330 public void test_ErrorSurrogatePair() throws JDOMException, IOException {
331 SAXBuilder builder = new SAXBuilder();
332 builder.setExpandEntities(true);
333 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root></root>"));
334 try {
335 doc.getRootElement().setText("\uD800\uDBFF");
336 fail("Illegal surrogate pair should have thrown an exception");
337 }
338 catch (IllegalDataException e) {
339 // do nothing
340 } catch (Exception e) {
341 fail ("Unexpected exception " + e.getClass());
342 }
343 }
344
345 // Manually construct illegal XML and make sure the outputter notices
346 @Test
347 public void test_ErrorSurrogatePairOutput() throws JDOMException, IOException {
348 SAXBuilder builder = new SAXBuilder();
349 builder.setExpandEntities(true);
350 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root></root>"));
351 Text t = new UncheckedJDOMFactory().text("\uD800\uDBFF");
352 doc.getRootElement().setContent(t);
353 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
354 XMLOutputter outputter = new XMLOutputter(format);
355 ByteArrayOutputStream baos = new ByteArrayOutputStream();
356 try {
357 outputter.output(doc, baos);
358 fail("Illegal surrogate pair output should have thrown an exception");
359 }
360 catch (IllegalDataException e) {
361 // do nothing
362 } catch (Exception e) {
363 fail ("Unexpected exception " + e.getClass());
364 }
365 }
366
367
368 @Test
369 public void testXMLOutputter() {
370 XMLOutputter out = new XMLOutputter();
371 TestFormat.checkEquals(out.getFormat(), Format.getRawFormat());
372 }
373
374
375 @Test
376 public void testXMLOutputterFormat() {
377 Format mine = Format.getCompactFormat();
378 mine.setEncoding("US-ASCII");
379 XMLOutputter out = new XMLOutputter(mine);
380 TestFormat.checkEquals(mine, out.getFormat());
381 }
382
383 @Test
384 public void testFormat() {
385 Format mine = Format.getCompactFormat();
386 mine.setEncoding("US-ASCII");
387 // double-constcut it.
388 XMLOutputter out = new XMLOutputter();
389 TestFormat.checkEquals(Format.getRawFormat(), out.getFormat());
390 out.setFormat(mine);
391 TestFormat.checkEquals(mine, out.getFormat());
392 }
393
394 @Test
395 public void testNoLineSeparator() {
396 XMLOutputter out = new XMLOutputter(Format.getRawFormat().setLineSeparator(LineSeparator.NONE));
397 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root />",
398 out.outputString(new Document(new Element("root"))));
399 }
400
401 @Test
402 public void testEscapeAttributeEntities() {
403 Map<String,String> totest = new LinkedHashMap<String,String>();
404
405 totest.put("\"", "&quot;");
406 totest.put("&", "&amp;");
407 totest.put("<", "&lt;");
408 totest.put(">", "&gt;");
409 totest.put("\t", "&#x9;");
410 totest.put("\r", "&#xD;");
411 totest.put("\n", "&#xA;");
412 totest.put("\nz\n\n", "&#xA;z&#xA;&#xA;");
413
414 totest.put("'", "'");
415
416 totest.put("Frodo's Journey", "Frodo's Journey");
417
418
419 XMLOutputter out = new XMLOutputter();
420
421 for (Map.Entry<String,String> me : totest.entrySet()) {
422 if (!me.getValue().equals(out.escapeAttributeEntities(me.getKey()))) {
423 assertEquals("Failed attempt to escape '" + me.getKey() + "'",
424 me.getValue(), out.escapeAttributeEntities(me.getKey()));
425 }
426 }
427 }
428
429 @Test
430 public void testEscapeElementEntities() {
431 Map<String,String> totest = new LinkedHashMap<String,String>();
432
433 totest.put("\"", "\"");
434 totest.put("&", "&amp;");
435 totest.put("<", "&lt;");
436 totest.put(">", "&gt;");
437 totest.put("> >>", "&gt; &gt;&gt;");
438 totest.put("\t", "\t");
439 totest.put("\r", "&#xD;");
440 totest.put("\n", "\r\n");
441
442 totest.put("'", "'");
443
444 totest.put("Frodo's Journey", "Frodo's Journey");
445
446
447 XMLOutputter out = new XMLOutputter();
448
449 for (Map.Entry<String,String> me : totest.entrySet()) {
450 if (!me.getValue().equals(out.escapeElementEntities(me.getKey()))) {
451 assertEquals("Failed attempt to escape '" + me.getKey() + "'",
452 me.getValue(), out.escapeElementEntities(me.getKey()));
453 }
454 }
455 }
456
457
458
459 @Test
460 public void testClone() {
461 XMLOutputter xo = new XMLOutputter();
462 assertTrue(xo != xo.clone());
463 }
464
465 @Test
466 public void testToString() {
467 Format fmt = Format.getCompactFormat();
468 fmt.setLineSeparator("\n\t ");
469 XMLOutputter out = new XMLOutputter(fmt);
470 assertNotNull(out.toString());
471 }
472
473 /**
474 * The following method will run the output data through each of the three base
475 * formatters, raw, compact, and pretty. It will also run each of those
476 * formatters as the outputString(content), output(content, OutputStream)
477 * and output(content, Writer).
478 *
479 * The expectation is that the results of the three output forms (String,
480 * OutputStream, and Writer) will be identical, and that it will match
481 * the expected value for the appropriate formatter.
482 *
483 * @param content The content to output
484 * @param methodprefix What the methods are called
485 * @param clazz The class used as the parameter for the methods.
486 * @param setup A callback mechanism to modify the formatters
487 * @param raw What we expect the content to look like with the RAW format
488 * @param compact What we expect the content to look like with the COMPACT format
489 * @param pretty What we expect the content to look like with the PRETTY format
490 * @param trimfw What we expect the content to look like with the TRIM_FULL_WHITE format
491 */
492 @Override
493 protected void checkOutput(Object content, String methodprefix, Class<?> clazz,
494 FormatSetup setup, String raw, String compact, String pretty, String tso, String trimfw) {
495
496 super.checkOutput(content, methodprefix, clazz, setup, raw, compact, pretty, tso, trimfw);
497
498 Method mstring = getMethod(methodprefix + "String", clazz);
499 Method mstream = getMethod(methodprefix, clazz, OutputStream.class);
500 Method mwriter = getMethod(methodprefix, clazz, Writer.class);
501
502 String[] descn = new String[] {"Raw", "Compact", "Pretty", "TrimFullWhite"};
503 Format ftrimfw = Format.getPrettyFormat();
504 ftrimfw.setTextMode(TextMode.TRIM_FULL_WHITE);
505 Format[] formats = new Format[] {
506 getFormat(setup, Format.getRawFormat()),
507 getFormat(setup, Format.getCompactFormat()),
508 getFormat(setup, Format.getPrettyFormat()),
509 getFormat(setup, ftrimfw)};
510 String[] result = new String[] {expect(raw), expect(compact), expect(pretty), expect(trimfw)};
511
512 for (int i = 0; i < 4; i++) {
513 XMLOutputter out = new XMLOutputter(formats[i]);
514 ByteArrayOutputStream baos = new ByteArrayOutputStream(result[i].length() * 2);
515 CharArrayWriter caw = new CharArrayWriter(result[i].length() + 2);
516 try {
517 if (mstring != null) {
518 String rstring = (String) mstring.invoke(out, content);
519 assertEquals("outputString Format " + descn[i], result[i], rstring);
520 }
521 if (mstream != null) {
522 mstream.invoke(out, content, baos);
523 String rstream = new String(baos.toByteArray());
524 assertEquals("output OutputStream Format " + descn[i], result[i], rstream);
525 }
526 if (mwriter != null) {
527 mwriter.invoke(out, content, caw);
528 String rwriter = String.valueOf(caw.toCharArray());
529 assertEquals("output Writer Format " + descn[i], result[i], rwriter);
530 }
531
532 } catch (Exception e) {
533 e.printStackTrace();
534 fail("Failed to process " + descn[i] + " on content " + clazz + ": " + e.getMessage());
535 }
536 }
537 }
538
539 private Method getMethod(String name, Class<?>...classes) {
540 try {
541 return XMLOutputter.class.getMethod(name, classes);
542 } catch (Exception e) {
543 // ignore.
544 System.out.println("Can't find " + name + " on " + this.getClass().getName() + ": " + e.getMessage());
545 }
546 return null;
547 }
548
549
550 }
0 package org.jdom.test.cases.output;
1
2 /* Please run replic.pl on me ! */
3 /**
4 * Please put a description of your test here.
5 *
6 * @author unascribed
7 * @version 0.1
8 */
9 import static org.junit.Assert.assertEquals;
10 import static org.junit.Assert.assertNotNull;
11 import static org.junit.Assert.assertTrue;
12 import static org.junit.Assert.fail;
13
14 import java.io.ByteArrayOutputStream;
15 import java.io.CharArrayWriter;
16 import java.io.IOException;
17 import java.io.OutputStream;
18 import java.io.StringReader;
19 import java.io.StringWriter;
20 import java.io.Writer;
21 import java.lang.reflect.Method;
22 import java.util.LinkedHashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import javax.xml.transform.Result;
27
28 import org.junit.Test;
29 import org.junit.runner.JUnitCore;
30
31 import org.jdom.CDATA;
32 import org.jdom.Comment;
33 import org.jdom.Content;
34 import org.jdom.DocType;
35 import org.jdom.Document;
36 import org.jdom.Element;
37 import org.jdom.EntityRef;
38 import org.jdom.IllegalDataException;
39 import org.jdom.JDOMException;
40 import org.jdom.ProcessingInstruction;
41 import org.jdom.Text;
42 import org.jdom.UncheckedJDOMFactory;
43 import org.jdom.input.SAXBuilder;
44 import org.jdom.output.Format;
45 import org.jdom.output.Format.TextMode;
46 import org.jdom.output.support.AbstractXMLOutputProcessor;
47 import org.jdom.output.support.XMLOutputProcessor;
48 import org.jdom.output.XMLOutputter2;
49
50 @SuppressWarnings("javadoc")
51 public final class TestXMLOutputter2 extends AbstractTestOutputter {
52
53 /**
54 * The main method runs all the tests in the text ui
55 */
56 public static void main (String args[])
57 {
58 JUnitCore.runClasses(TestXMLOutputter2.class);
59 }
60
61 public TestXMLOutputter2() {
62 super(true, true, false, false, false);
63 }
64
65 private XMLOutputter2 getOutputter(Format format) {
66 return new XMLOutputter2(format);
67 }
68
69 @Override
70 public String outputDocumentAsString(Format format, Document doc) {
71 return getOutputter(format).outputString(doc);
72 }
73
74 @Override
75 public String outputDocTypeAsString(Format format, DocType doctype) {
76 return getOutputter(format).outputString(doctype);
77 }
78
79 @Override
80 public String outputElementAsString(Format format, Element element) {
81 return getOutputter(format).outputString(element);
82 }
83
84 @Override
85 public String outputListAsString(Format format, List<? extends Content> list) {
86 return getOutputter(format).outputString(list);
87 }
88
89 @Override
90 public String outputCDataAsString(Format format, CDATA cdata) {
91 return getOutputter(format).outputString(cdata);
92 }
93
94 @Override
95 public String outputTextAsString(Format format, Text text) {
96 return getOutputter(format).outputString(text);
97 }
98
99 @Override
100 public String outputCommentAsString(Format format, Comment comment) {
101 return getOutputter(format).outputString(comment);
102 }
103
104 @Override
105 public String outputPIAsString(Format format, ProcessingInstruction pi) {
106 return getOutputter(format).outputString(pi);
107 }
108
109 @Override
110 public String outputEntityRefAsString(Format format, EntityRef entity) {
111 return getOutputter(format).outputString(entity);
112 }
113
114 @Override
115 public String outputElementContentString(Format format, Element element) {
116 return getOutputter(format).outputElementContentString(element);
117 }
118
119
120
121
122 @Test
123 public void test_HighSurrogatePair() throws JDOMException, IOException {
124 SAXBuilder builder = new SAXBuilder();
125 builder.setExpandEntities(true);
126 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>&#x10000; &#x10000;</root>"));
127 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
128 XMLOutputter2 outputter = new XMLOutputter2(format);
129 StringWriter sw = new StringWriter();
130 outputter.output(doc, sw);
131 String xml = sw.toString();
132 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
133 "<root>&#x10000; &#x10000;</root>" + format.getLineSeparator(), xml);
134 }
135
136 @Test
137 public void test_HighSurrogatePairDecimal() throws JDOMException, IOException {
138 SAXBuilder builder = new SAXBuilder();
139 builder.setExpandEntities(true);
140 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>&#x10000; &#65536;</root>"));
141 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
142 XMLOutputter2 outputter = new XMLOutputter2(format);
143 ByteArrayOutputStream baos = new ByteArrayOutputStream();
144 outputter.output(doc, baos);
145 String xml = baos.toString();
146 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
147 "<root>&#x10000; &#x10000;</root>" + format.getLineSeparator(), xml);
148 }
149
150 @Test
151 public void test_HighSurrogateAttPair() throws JDOMException, IOException {
152 SAXBuilder builder = new SAXBuilder();
153 builder.setExpandEntities(true);
154 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root att=\"&#x10000; &#x10000;\" />"));
155 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
156 XMLOutputter2 outputter = new XMLOutputter2(format);
157 ByteArrayOutputStream baos = new ByteArrayOutputStream();
158 outputter.output(doc, baos);
159 String xml = baos.toString();
160 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
161 "<root att=\"&#x10000; &#x10000;\" />" + format.getLineSeparator(), xml);
162 }
163
164 @Test
165 public void test_HighSurrogateAttPairDecimal() throws JDOMException, IOException {
166 SAXBuilder builder = new SAXBuilder();
167 builder.setExpandEntities(true);
168 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root att=\"&#x10000; &#65536;\" />"));
169 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
170 XMLOutputter2 outputter = new XMLOutputter2(format);
171 ByteArrayOutputStream baos = new ByteArrayOutputStream();
172 outputter.output(doc, baos);
173 String xml = baos.toString();
174 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
175 "<root att=\"&#x10000; &#x10000;\" />" + format.getLineSeparator(), xml);
176 }
177
178 // Construct a raw surrogate pair character and confirm it outputs hex escaped
179 @Test
180 public void test_RawSurrogatePair() throws JDOMException, IOException {
181 SAXBuilder builder = new SAXBuilder();
182 builder.setExpandEntities(true);
183 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>\uD800\uDC00</root>"));
184 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
185 XMLOutputter2 outputter = new XMLOutputter2(format);
186 ByteArrayOutputStream baos = new ByteArrayOutputStream();
187 outputter.output(doc, baos);
188 String xml = baos.toString();
189 assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" + format.getLineSeparator() +
190 "<root>&#x10000;</root>" + format.getLineSeparator(), xml);
191 }
192
193 // Construct a raw surrogate pair character and confirm it outputs hex escaped, when UTF-8 too
194 @Test
195 public void test_RawSurrogatePairUTF8() throws JDOMException, IOException {
196 SAXBuilder builder = new SAXBuilder();
197 builder.setExpandEntities(true);
198 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root>\uD800\uDC00</root>"));
199 Format format = Format.getCompactFormat().setEncoding("UTF-8");
200 XMLOutputter2 outputter = new XMLOutputter2(format);
201 ByteArrayOutputStream baos = new ByteArrayOutputStream();
202 outputter.output(doc, baos);
203 String xml = baos.toString();
204 assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + format.getLineSeparator() +
205 "<root>&#x10000;</root>" + format.getLineSeparator(), xml);
206 }
207
208 // Construct illegal XML and check if the parser notices
209 @Test
210 public void test_ErrorSurrogatePair() throws JDOMException, IOException {
211 SAXBuilder builder = new SAXBuilder();
212 builder.setExpandEntities(true);
213 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root></root>"));
214 try {
215 doc.getRootElement().setText("\uD800\uDBFF");
216 fail("Illegal surrogate pair should have thrown an exception");
217 }
218 catch (IllegalDataException e) {
219 // do nothing
220 } catch (Exception e) {
221 fail ("Unexpected exception " + e.getClass());
222 }
223 }
224
225 // Manually construct illegal XML and make sure the outputter notices
226 @Test
227 public void test_ErrorSurrogatePairOutput() throws JDOMException, IOException {
228 SAXBuilder builder = new SAXBuilder();
229 builder.setExpandEntities(true);
230 Document doc = builder.build(new StringReader("<?xml version=\"1.0\"?><root></root>"));
231 Text t = new UncheckedJDOMFactory().text("\uD800\uDBFF");
232 doc.getRootElement().setContent(t);
233 Format format = Format.getCompactFormat().setEncoding("ISO-8859-1");
234 XMLOutputter2 outputter = new XMLOutputter2(format);
235 ByteArrayOutputStream baos = new ByteArrayOutputStream();
236 try {
237 outputter.output(doc, baos);
238 fail("Illegal surrogate pair output should have thrown an exception");
239 }
240 catch (IllegalDataException e) {
241 // do nothing
242 } catch (Exception e) {
243 fail ("Unexpected exception " + e.getClass());
244 }
245 }
246
247
248 @Test
249 public void testXMLOutputter() {
250 XMLOutputter2 out = new XMLOutputter2();
251 TestFormat.checkEquals(out.getFormat(), Format.getRawFormat());
252 }
253
254
255 @Test
256 public void testXMLOutputterFormat() {
257 Format mine = Format.getCompactFormat();
258 mine.setEncoding("US-ASCII");
259 XMLOutputter2 out = new XMLOutputter2(mine);
260 TestFormat.checkEquals(mine, out.getFormat());
261 }
262
263 @Test
264 public void testXMLOutputterXMLOutputter() {
265 Format mine = Format.getCompactFormat();
266 XMLOutputProcessor xoutp = new XMLOutputter2().getXMLOutputProcessor();
267 mine.setEncoding("US-ASCII");
268 // double-constcut it.
269 XMLOutputter2 out = new XMLOutputter2(new XMLOutputter2(mine));
270 TestFormat.checkEquals(mine, out.getFormat());
271 assertTrue(xoutp == out.getXMLOutputProcessor());
272 }
273
274 @Test
275 public void testXMLOutputterXMLOutputProcessor() {
276 XMLOutputProcessor xoutp = new AbstractXMLOutputProcessor() {
277 // nothing;
278 };
279 // double-constrcut it.
280 XMLOutputter2 out = new XMLOutputter2(xoutp);
281 TestFormat.checkEquals(Format.getRawFormat(), out.getFormat());
282 assertTrue(xoutp == out.getXMLOutputProcessor());
283 }
284
285 @Test
286 public void testFormat() {
287 Format mine = Format.getCompactFormat();
288 mine.setEncoding("US-ASCII");
289 // double-constcut it.
290 XMLOutputter2 out = new XMLOutputter2();
291 TestFormat.checkEquals(Format.getRawFormat(), out.getFormat());
292 out.setFormat(mine);
293 TestFormat.checkEquals(mine, out.getFormat());
294 }
295
296 @Test
297 public void testXMLOutputProcessor() {
298 XMLOutputProcessor xoutp = new AbstractXMLOutputProcessor() {
299 // nothing;
300 };
301 // double-constcut it.
302 XMLOutputter2 out = new XMLOutputter2();
303 XMLOutputProcessor xop = out.getXMLOutputProcessor();
304 out.setXMLOutputProcessor(xoutp);
305 assertTrue(xoutp != xop);
306 assertTrue(xoutp == out.getXMLOutputProcessor());
307 }
308
309 @Test
310 public void testEscapeAttributeEntities() {
311 Map<String,String> totest = new LinkedHashMap<String,String>();
312
313 totest.put("\"", "&quot;");
314 totest.put("&", "&amp;");
315 totest.put("<", "&lt;");
316 totest.put(">", "&gt;");
317 totest.put("\t", "&#x9;");
318 totest.put("\r", "&#xD;");
319 totest.put("\n", "&#xA;");
320 totest.put("\nz\n\n", "&#xA;z&#xA;&#xA;");
321
322 totest.put("'", "'");
323
324 totest.put("Frodo's Journey", "Frodo's Journey");
325
326
327 XMLOutputter2 out = new XMLOutputter2();
328
329 for (Map.Entry<String,String> me : totest.entrySet()) {
330 if (!me.getValue().equals(out.escapeAttributeEntities(me.getKey()))) {
331 assertEquals("Failed attempt to escape '" + me.getKey() + "'",
332 me.getValue(), out.escapeAttributeEntities(me.getKey()));
333 }
334 }
335 }
336
337 @Test
338 public void testEscapeElementEntities() {
339 Map<String,String> totest = new LinkedHashMap<String,String>();
340
341 totest.put("\"", "\"");
342 totest.put("&", "&amp;");
343 totest.put("<", "&lt;");
344 totest.put(">", "&gt;");
345 totest.put("> >>", "&gt; &gt;&gt;");
346 totest.put("\t", "\t");
347 totest.put("\r", "&#xD;");
348 totest.put("\n", "\r\n");
349
350 totest.put("'", "'");
351
352 totest.put("Frodo's Journey", "Frodo's Journey");
353
354
355 XMLOutputter2 out = new XMLOutputter2();
356
357 for (Map.Entry<String,String> me : totest.entrySet()) {
358 if (!me.getValue().equals(out.escapeElementEntities(me.getKey()))) {
359 assertEquals("Failed attempt to escape '" + me.getKey() + "'",
360 me.getValue(), out.escapeElementEntities(me.getKey()));
361 }
362 }
363 }
364
365
366
367 @Test
368 public void testTrimFullWhite() {
369 // See issue #31.
370 // https://github.com/hunterhacker/jdom/issues/31
371 // This tests should pass when issue 31 is resolved.
372 Element root = new Element("root");
373 root.addContent(new Text(" "));
374 root.addContent(new Text("x"));
375 root.addContent(new Text(" "));
376 Format mf = Format.getRawFormat();
377 mf.setTextMode(TextMode.TRIM_FULL_WHITE);
378 XMLOutputter2 xout = new XMLOutputter2(mf);
379 String output = xout.outputString(root);
380 assertEquals("<root> x </root>", output);
381 }
382
383
384 @Test
385 public void testOutputElementIgnoreTrAXEscapingPIs() {
386 Element root = new Element("root");
387 root.addContent(new Text("&"));
388 root.addContent(new ProcessingInstruction(Result.PI_DISABLE_OUTPUT_ESCAPING, ""));
389 root.addContent(new Text(" && "));
390 root.addContent(new ProcessingInstruction(Result.PI_ENABLE_OUTPUT_ESCAPING, ""));
391 root.addContent(new Text("&"));
392 String expect = "<root>&amp; && &amp;</root>";
393 String excompact = "<root>&amp;&&&amp;</root>";
394 String expretty = "<root>\n &amp;\n &&\n &amp;\n</root>";
395 String extfw = "<root>\n &amp;\n && \n &amp;\n</root>";
396 checkOutput(root,
397 expect,
398 excompact,
399 expretty,
400 expretty,
401 extfw);
402 }
403
404
405 @Test
406 public void testClone() {
407 XMLOutputter2 xo = new XMLOutputter2();
408 assertTrue(xo != xo.clone());
409 }
410
411 @Test
412 public void testToString() {
413 Format fmt = Format.getCompactFormat();
414 fmt.setLineSeparator("\n\t ");
415 XMLOutputter2 out = new XMLOutputter2(fmt);
416 assertNotNull(out.toString());
417 }
418
419 @Test
420 public void testCRNLEscaping() {
421 Document doc = new Document();
422 Element root = new Element("root");
423 Element child1 = new Element("child1");
424 Element child2 = new Element("child2");
425 Text stuff = new Text("foo");
426 root.addContent(child1);
427 root.addContent(stuff);
428 root.addContent(child2);
429 doc.setRootElement(root);
430 XMLOutputter2 xout = new XMLOutputter2(Format.getPrettyFormat());
431 String actual = xout.outputString(doc);
432 String expect = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
433 + "<root>\r\n"
434 + " <child1 />\r\n"
435 + " foo\r\n"
436 + " <child2 />\r\n"
437 + "</root>\r\n";
438 assertEquals(expect, actual);
439 }
440
441 /**
442 * The following method will run the output data through each of the three base
443 * formatters, raw, compact, and pretty. It will also run each of those
444 * formatters as the outputString(content), output(content, OutputStream)
445 * and output(content, Writer).
446 *
447 * The expectation is that the results of the three output forms (String,
448 * OutputStream, and Writer) will be identical, and that it will match
449 * the expected value for the appropriate formatter.
450 *
451 * @param content The content to output
452 * @param methodprefix What the methods are called
453 * @param clazz The class used as the parameter for the methods.
454 * @param setup A callback mechanism to modify the formatters
455 * @param raw What we expect the content to look like with the RAW format
456 * @param compact What we expect the content to look like with the COMPACT format
457 * @param pretty What we expect the content to look like with the PRETTY format
458 * @param trimfw What we expect the content to look like with the TRIM_FULL_WHITE format
459 */
460 @Override
461 protected void checkOutput(Object content, String methodprefix, Class<?> clazz,
462 FormatSetup setup, String raw, String compact, String pretty, String tso, String trimfw) {
463
464 super.checkOutput(content, methodprefix, clazz, setup, raw, compact, pretty, tso, trimfw);
465
466 Method mstring = getMethod(methodprefix + "String", clazz);
467 Method mstream = getMethod(methodprefix, clazz, OutputStream.class);
468 Method mwriter = getMethod(methodprefix, clazz, Writer.class);
469
470 String[] descn = new String[] {"Raw", "Compact", "Pretty", "TrimFullWhite"};
471 Format ftrimfw = Format.getPrettyFormat();
472 ftrimfw.setTextMode(TextMode.TRIM_FULL_WHITE);
473 Format[] formats = new Format[] {
474 getFormat(setup, Format.getRawFormat()),
475 getFormat(setup, Format.getCompactFormat()),
476 getFormat(setup, Format.getPrettyFormat()),
477 getFormat(setup, ftrimfw)};
478 String[] result = new String[] {expect(raw), expect(compact), expect(pretty), expect(trimfw)};
479
480 for (int i = 0; i < 4; i++) {
481 XMLOutputter2 out = new XMLOutputter2(formats[i]);
482 ByteArrayOutputStream baos = new ByteArrayOutputStream(result[i].length() * 2);
483 CharArrayWriter caw = new CharArrayWriter(result[i].length() + 2);
484 try {
485 if (mstring != null) {
486 String rstring = (String) mstring.invoke(out, content);
487 assertEquals("outputString Format " + descn[i], result[i], rstring);
488 }
489 if (mstream != null) {
490 mstream.invoke(out, content, baos);
491 String rstream = new String(baos.toByteArray());
492 assertEquals("output OutputStream Format " + descn[i], result[i], rstream);
493 }
494 if (mwriter != null) {
495 mwriter.invoke(out, content, caw);
496 String rwriter = String.valueOf(caw.toCharArray());
497 assertEquals("output Writer Format " + descn[i], result[i], rwriter);
498 }
499
500 } catch (Exception e) {
501 e.printStackTrace();
502 fail("Failed to process " + descn[i] + " on content " + clazz + ": " + e.getMessage());
503 }
504 }
505 }
506
507 private Method getMethod(String name, Class<?>...classes) {
508 try {
509 return XMLOutputter2.class.getMethod(name, classes);
510 } catch (Exception e) {
511 // ignore.
512 System.out.println("Can't find " + name + " on " + this.getClass().getName() + ": " + e.getMessage());
513 }
514 return null;
515 }
516
517
518 }
0 package org.jdom.test.cases.serialize;
1
2 import org.jdom.Attribute;
3
4 @SuppressWarnings("javadoc")
5 public class SAttribute extends Attribute {
6
7 private static final long serialVersionUID = 1L;
8
9 }
0 package org.jdom.test.cases.serialize;
1
2 import org.jdom.CDATA;
3
4 @SuppressWarnings("javadoc")
5 public class SCDATA extends CDATA {
6
7 private static final long serialVersionUID = 1L;
8
9 }
0 package org.jdom.test.cases.serialize;
1
2 import org.jdom.Comment;
3
4 @SuppressWarnings("javadoc")
5 public class SComment extends Comment {
6
7 private static final long serialVersionUID = 1L;
8
9 }
0 package org.jdom.test.cases.serialize;
1
2 import org.jdom.DocType;
3
4 @SuppressWarnings("javadoc")
5 public class SDocType extends DocType {
6
7 private static final long serialVersionUID = 1L;
8
9 }
0 package org.jdom.test.cases.serialize;
1
2 import org.jdom.Element;
3
4 @SuppressWarnings("javadoc")
5 public class SElement extends Element {
6
7 private static final long serialVersionUID = 1L;
8
9 }
0 package org.jdom.test.cases.serialize;
1
2 import org.jdom.EntityRef;
3
4 @SuppressWarnings("javadoc")
5 public class SEntityRef extends EntityRef {
6
7 private static final long serialVersionUID = 1L;
8
9 }
0 package org.jdom.test.cases.serialize;
1
2 import org.jdom.filter2.AbstractFilter;
3
4 @SuppressWarnings("javadoc")
5 public class SFilter extends AbstractFilter<Integer> {
6
7 private static final long serialVersionUID = 1L;
8
9 @Override
10 public Integer filter(Object content) {
11 if (content instanceof Integer) {
12 return (Integer)content;
13 }
14 return null;
15 }
16
17 }
0 package org.jdom.test.cases.serialize;
1
2 import org.jdom.ProcessingInstruction;
3
4 @SuppressWarnings("javadoc")
5 public class SProcessingInstruction extends ProcessingInstruction {
6
7 private static final long serialVersionUID = 1L;
8
9 }
0 package org.jdom.test.cases.serialize;
1
2 import org.jdom.Text;
3
4 @SuppressWarnings("javadoc")
5 public class SText extends Text {
6
7 private static final long serialVersionUID = 1L;
8
9 }
0 package org.jdom.test.cases.serialize;
1
2 import static org.jdom.test.util.UnitTestUtil.deSerialize;
3
4 import org.junit.Test;
5
6 @SuppressWarnings("javadoc")
7 public class TestSubclassSerializables {
8
9 @Test
10 public void testFilter() {
11 deSerialize(new SFilter());
12 }
13
14 @Test
15 public void testAttribute() {
16 deSerialize(new SAttribute());
17 }
18
19 @Test
20 public void testCDATA() {
21 deSerialize(new SComment());
22 }
23
24 @Test
25 public void testComment() {
26 deSerialize(new SComment());
27 }
28
29 @Test
30 public void testDocType() {
31 deSerialize(new SDocType());
32 }
33
34 @Test
35 public void testElement() {
36 deSerialize(new SElement());
37 }
38
39 @Test
40 public void testEntityRef() {
41 deSerialize(new SEntityRef());
42 }
43
44 @Test
45 public void testProcessingInstruction() {
46 deSerialize(new SProcessingInstruction());
47 }
48
49 @Test
50 public void testText() {
51 deSerialize(new SText());
52 }
53
54 }
0 <!ELEMENT doc (#PCDATA)>
1 <!ENTITY minus "&#x2212;" >
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!DOCTYPE doc PUBLIC "-//JDOM//DTD MINUS 1.0//EN" "./TestIssue008.dtd">
2 <doc>&minus;</doc>
0 package org.jdom.test.cases.special;
1
2 import static org.junit.Assert.*;
3
4 import java.io.IOException;
5 import java.net.URL;
6
7 import org.jdom.Document;
8 import org.jdom.JDOMException;
9 import org.jdom.input.SAXBuilder;
10 import org.jdom.output.Format;
11 import org.jdom.output.XMLOutputter2;
12 import org.jdom.test.util.FidoFetch;
13
14 import org.junit.Test;
15
16 @SuppressWarnings("javadoc")
17 public class TestIssue008ExpandEntity {
18
19 private final void roundTrip(boolean expand, boolean validating, String encoding, String expect) {
20 String docloc = "/" + this.getClass().getPackage().getName().replaceAll("\\.", "/") + "/TestIssue008.xml";
21 URL docurl = FidoFetch.getFido().getURL(docloc);
22
23 if (docurl == null) {
24 throw new IllegalStateException("Unable to get resource " + docloc);
25 }
26
27 @SuppressWarnings("deprecation")
28 SAXBuilder builder = new SAXBuilder(validating);
29 //builder.setValidation(validating);
30 builder.setExpandEntities(expand);
31 Document doc = null;
32 try {
33 doc = builder.build(docurl);
34 } catch (JDOMException e) {
35 e.printStackTrace();
36 } catch (IOException e) {
37 e.printStackTrace();
38 }
39 if (doc == null) {
40 fail("Unable to parse document, see output.");
41 }
42
43 Format fmt = Format.getCompactFormat();
44 if (encoding != null) {
45 fmt.setEncoding(encoding);
46 }
47 XMLOutputter2 xout = new XMLOutputter2(fmt);
48
49 String actual = xout.outputString(doc.getRootElement());
50 assertEquals(expect, actual);
51
52 }
53
54 @Test
55 public void testFalse() {
56 roundTrip(false, false, null, "<doc>&minus;</doc>");
57 }
58
59 @Test
60 public void testFalseUSASCII() {
61 roundTrip(false, false, "US-ASCII", "<doc>&minus;</doc>");
62 }
63
64 @Test
65 public void testFalseUTF8() {
66 roundTrip(false, false, "UTF-8", "<doc>&minus;</doc>");
67 }
68
69 @Test
70 public void testTrueUSASCII() {
71 roundTrip(true, false, "US-ASCII", "<doc>&#x2212;</doc>");
72 }
73
74 @Test
75 public void testTrueUTF8() {
76 roundTrip(true, false, "UTF-8", "<doc>\u2212</doc>");
77 }
78
79 @Test
80 public void testTrue() {
81 roundTrip(true, false, null, "<doc>\u2212</doc>");
82 }
83
84
85
86 @Test
87 public void testValidFalse() {
88 roundTrip(false, true, null, "<doc>&minus;</doc>");
89 }
90
91 @Test
92 public void testValidFalseUSASCII() {
93 roundTrip(false, true, "US-ASCII", "<doc>&minus;</doc>");
94 }
95
96 @Test
97 public void testValidFalseUTF8() {
98 roundTrip(false, true, "UTF-8", "<doc>&minus;</doc>");
99 }
100
101 @Test
102 public void testValidTrueUSASCII() {
103 roundTrip(true, true, "US-ASCII", "<doc>&#x2212;</doc>");
104 }
105
106 @Test
107 public void testValidTrueUTF8() {
108 roundTrip(true, true, "UTF-8", "<doc>\u2212</doc>");
109 }
110
111 @Test
112 public void testValidTrue() {
113 roundTrip(true, true, null, "<doc>\u2212</doc>");
114 }
115
116
117 }
0 package org.jdom.test.cases.transform;
1
2 import static org.junit.Assert.*;
3
4 import java.util.ArrayList;
5
6 import org.jdom.Content;
7 import org.jdom.Document;
8 import org.jdom.Element;
9 import org.jdom.JDOMFactory;
10 import org.jdom.ProcessingInstruction;
11 import org.jdom.Text;
12 import org.jdom.UncheckedJDOMFactory;
13 import org.jdom.transform.JDOMResult;
14 import org.junit.Test;
15 import org.xml.sax.ContentHandler;
16 import org.xml.sax.ext.DefaultHandler2;
17 import org.xml.sax.ext.LexicalHandler;
18
19 @SuppressWarnings("javadoc")
20 public class TestJDOMResult {
21
22 /* *************************************************
23 * These tests cover only a small part of JDOMResult.
24 * The more complex code relates to accepting the
25 * events fired during transformation. Those calls
26 * are tested in TestJDOMTransform which puts 'real'
27 * transformations through JDOMResult.
28 * *************************************************/
29
30 @Test
31 public void testJDOMResult() {
32 JDOMResult result = new JDOMResult();
33 assertNotNull(result.getHandler());
34 assertTrue(result.getHandler() == result.getLexicalHandler());
35 }
36
37 @Test
38 public void testSetHandlerContentHandler() {
39 JDOMResult result = new JDOMResult();
40 ContentHandler handler = result.getHandler();
41 assertNotNull(handler);
42 ContentHandler toset = new DefaultHandler2();
43
44 // we do not allow others to change the handler on the JDOMResult
45 // so this should do nothing.
46 result.setHandler(toset);
47
48 assertTrue(handler == result.getHandler());
49 }
50
51 @Test
52 public void testSetLexicalHandlerLexicalHandler() {
53 JDOMResult result = new JDOMResult();
54 LexicalHandler handler = result.getLexicalHandler();
55 assertNotNull(handler);
56 LexicalHandler toset = new DefaultHandler2();
57
58 // we do not allow others to change the handler on the JDOMResult
59 // so this should do nothing.
60 result.setLexicalHandler(toset);
61
62 assertTrue(handler == result.getLexicalHandler());
63 }
64
65 @Test
66 public void testGetSetFactory() {
67 JDOMResult result = new JDOMResult();
68 JDOMFactory faca = result.getFactory();
69 assertTrue(faca == null);
70 JDOMFactory facb = new UncheckedJDOMFactory();
71 result.setFactory(facb);
72 assertTrue(facb == result.getFactory());
73 result.setFactory(null);
74 assertTrue(null == result.getFactory());
75 }
76
77 @Test
78 public void testDocumentResult() {
79 // in this context, the 'source' provides us with a document.
80 // the expectation is that getDocument() will work to retrieve the result
81 // but, getNodes will only work if called first... subsequent calls
82 // return an empty list.
83 JDOMResult result = new JDOMResult();
84 assertNull(result.getDocument());
85 assertTrue(result.getResult().isEmpty());
86
87 // OK, we expect things now.
88 Element root = new Element("root");
89 Document doc = new Document(root);
90 result.setDocument(doc);
91 // test a few times. Should not change.
92 assertTrue(doc == result.getDocument());
93 assertTrue(doc == result.getDocument());
94 assertTrue(doc == result.getDocument());
95 // after a call to getDocument, getResult should be empty.
96 assertTrue(result.getResult().isEmpty());
97 // messing with the getDocument side of things should not mess with the
98 // document tree.
99 assertTrue(root.getParent() == doc);
100
101 // OK, reset the result.
102 result.setDocument(doc);
103 // should be something there this time
104 assertTrue(result.getResult().size() == 1);
105 // but, now it is cached too. we can get the result...
106 assertTrue(root == result.getResult().get(0));
107 // using getResult() returns detached content, so....
108 assertFalse(doc.hasRootElement());
109 assertTrue(null == root.getParent());
110 // further, a successful getResult() call invalidates the getDocument()
111 // so that will now be null.
112 assertNull(result.getDocument());
113 }
114
115 @Test
116 public void testNodesResult() {
117 // In this context, the 'source' provides us with a list of Nodes.
118 // In theory, these nodes should all be legal Element content.
119 JDOMResult result = new JDOMResult();
120 assertNull(result.getDocument());
121 assertTrue(result.getResult().isEmpty());
122
123 // OK, we expect things now.
124 Element child = new Element("child");
125 Text text = new Text("text");
126 ArrayList<Content> nodes = new ArrayList<Content>(2);
127 nodes.add(child);
128 nodes.add(text);
129
130 result.setResult(nodes);
131
132 // test a few times. Should not change.
133 assertTrue(nodes == result.getResult());
134 assertTrue(!nodes.isEmpty());
135 assertTrue(nodes == result.getResult());
136 assertTrue(nodes == result.getResult());
137
138 // A call to getDocument should be null after a call to getResult().
139 assertTrue(null == result.getDocument());
140
141 // after a null call to getDocument, getResult should be unchanged.
142 assertTrue(nodes == result.getResult());
143
144 // OK, reset the result.
145 result.setResult(nodes);
146 // should still be nothing there... because Text is not valid Document content
147 assertNull(result.getDocument());
148 // but, the results are there still.
149 assertTrue(result.getResult().size() == 2);
150
151 // So, make the content valid for a Document.
152 nodes.remove(1); // get rid of text.
153 // insert a PI in front of the element.
154 nodes.add(0, new ProcessingInstruction("jdomtest", ""));
155
156 assertTrue(child.getParent() == null);
157
158 // This time we expect a document result.
159 result.setResult(nodes);
160 Document doc = result.getDocument();
161 assertNotNull(doc);
162 assertTrue (doc == child.getParent());
163
164 }
165
166
167
168 }
0 package org.jdom.test.cases.transform;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertNull;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.fail;
6
7 import java.io.ByteArrayInputStream;
8 import java.io.CharArrayReader;
9 import java.io.IOException;
10 import java.io.Reader;
11 import java.io.StringWriter;
12 import java.lang.reflect.InvocationHandler;
13 import java.lang.reflect.Method;
14 import java.lang.reflect.Proxy;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.concurrent.atomic.AtomicReference;
19
20 import org.jdom.Content;
21 import org.jdom.Document;
22 import org.jdom.Element;
23 import org.jdom.output.SAXOutputter;
24 import org.jdom.output.XMLOutputter2;
25 import org.jdom.transform.JDOMSource;
26 import org.junit.Test;
27 import org.xml.sax.Attributes;
28 import org.xml.sax.InputSource;
29 import org.xml.sax.SAXException;
30 import org.xml.sax.SAXNotSupportedException;
31 import org.xml.sax.XMLReader;
32 import org.xml.sax.ext.DefaultHandler2;
33 import org.xml.sax.helpers.XMLFilterImpl;
34
35 @SuppressWarnings("javadoc")
36 public class TestJDOMSource {
37
38 @Test
39 public void testJDOMSourceDocument() {
40 Document doc = new Document(new Element("root"));
41 doc.setBaseURI("baseURI");
42 JDOMSource source = new JDOMSource(doc);
43 assertTrue(source.getDocument() == doc);
44 // TODO Should the InputSource's SystemID be set?
45 //assertEquals("baseURI", source.getInputSource().getSystemId());
46 }
47
48 @Test
49 public void testJDOMSourceList() {
50 List<Element> nodes = new ArrayList<Element>();
51 nodes.add(new Element("nodea"));
52 nodes.add(new Element("nodeb"));
53 JDOMSource source = new JDOMSource(nodes);
54 assertTrue(nodes == source.getNodes());
55 }
56
57 @Test
58 public void testJDOMSourceElement() {
59 Element emt = new Element("emt");
60 JDOMSource source = new JDOMSource(emt);
61 assertTrue(emt == source.getNodes().get(0));
62 }
63
64 @Test
65 public void testJDOMSourceDocumentEntityResolver() {
66 DefaultHandler2 handler = new DefaultHandler2();
67 Document doc = new Document(new Element("root"));
68 JDOMSource source = new JDOMSource(doc, handler);
69 assertTrue(doc == source.getDocument());
70 assertTrue(handler == source.getXMLReader().getEntityResolver());
71 }
72
73 @Test
74 public void testGetSetDocument() {
75 Element emt = new Element("emt");
76 Document doc = new Document(new Element("root"));
77 JDOMSource source = new JDOMSource(emt);
78 assertTrue(null == source.getDocument());
79 assertTrue(emt == source.getNodes().get(0));
80 source.setDocument(doc);
81 assertTrue(doc == source.getDocument());
82 assertTrue(null == source.getNodes());
83 }
84
85 @Test
86 public void testGetSetNodes() {
87 Element emt = new Element("emt");
88 Document doc = new Document(new Element("root"));
89 JDOMSource source = new JDOMSource(doc);
90 assertTrue(doc == source.getDocument());
91 assertTrue(null == source.getNodes());
92 source.setNodes(Collections.singletonList(emt));
93 assertTrue(null == source.getDocument());
94 assertTrue(emt == source.getNodes().get(0));
95 }
96
97 @Test
98 public void testGetSetInputSourceInputSource() {
99 Document doc = new Document(new Element("root"));
100 JDOMSource source = new JDOMSource(doc);
101 InputSource insrc = new InputSource("url");
102 try {
103 source.setInputSource(insrc);
104 fail("Should not be able to change the InputSource");
105 } catch (UnsupportedOperationException uoe) {
106 // good
107 } catch (Exception e) {
108 fail("Expected exception UnsupportedOperationException, but got " + e.getClass());
109 }
110 }
111
112 @Test
113 public void testGetSetXMLReaderXMLReader() {
114 Document doc = new Document(new Element("root"));
115 JDOMSource source = new JDOMSource(doc);
116 try {
117 XMLReader f = (XMLReader)Proxy.newProxyInstance(null,
118 new Class<?>[]{XMLReader.class}, new InvocationHandler() {
119 @Override
120 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
121 if (String.class == method.getReturnType()) {
122 return "XMLFilter Proxy";
123 }
124 return null;
125 }
126 });
127 source.setXMLReader(f);
128 fail("Should not be able to change the XMLReader");
129 } catch (UnsupportedOperationException uoe) {
130 // good
131 } catch (Exception e) {
132 e.printStackTrace();
133 fail("Expected exception UnsupportedOperationException, but got " + e.getClass());
134 }
135
136 // but, you can add a Filter.
137 XMLReader pnt = new XMLFilterImpl();
138 XMLReader filter = new XMLFilterImpl(pnt);
139 source.setXMLReader(filter);
140 XMLReader r = source.getXMLReader();
141 assertTrue(filter == r);
142 }
143
144 @Test
145 public void testInputSourceSetters() {
146 JDOMSource source = new JDOMSource(new Document(new Element("root")));
147 InputSource isrc = source.getInputSource();
148 try {
149 isrc.setCharacterStream(new CharArrayReader(new char[0]));
150 fail("should not be able to set the CharacterStream");
151 } catch (UnsupportedOperationException uoe) {
152 // good
153 } catch (Exception e) {
154 fail ("Expected Unsupported operation exception, not " + e.getClass());
155 }
156 try {
157 isrc.setByteStream(new ByteArrayInputStream(new byte[0]));
158 fail("should not be able to set the ByteStream");
159 } catch (UnsupportedOperationException uoe) {
160 // good
161 } catch (Exception e) {
162 fail ("Expected Unsupported operation exception, not " + e.getClass());
163 }
164 }
165
166 @Test
167 public void testInputSourceByteStream() {
168 JDOMSource source = new JDOMSource(new Document(new Element("root")));
169 assertNull(source.getInputSource().getByteStream());
170 }
171
172 @Test
173 public void testInputSourceDocCharacterStream() throws IOException {
174 JDOMSource source = new JDOMSource(new Document(new Element("root")));
175 Document doc = source.getDocument();
176 String expect = new XMLOutputter2().outputString(doc);
177 Reader r = source.getInputSource().getCharacterStream();
178 StringWriter sw = new StringWriter();
179 char[] buffer = new char[512];
180 int len = 0;
181 while ((len = r.read(buffer)) >= 0) {
182 sw.write(buffer, 0, len);
183 }
184 r.close();
185 String actual = sw.toString();
186 assertEquals(expect, actual);
187 }
188
189 @Test
190 public void testInputSourceListCharacterStream() throws IOException {
191 JDOMSource source = new JDOMSource(new Element("root"));
192 Element emt = (Element)source.getNodes().get(0);
193 String expect = new XMLOutputter2().outputString(emt);
194 Reader r = source.getInputSource().getCharacterStream();
195 StringWriter sw = new StringWriter();
196 char[] buffer = new char[512];
197 int len = 0;
198 while ((len = r.read(buffer)) >= 0) {
199 sw.write(buffer, 0, len);
200 }
201 r.close();
202 String actual = sw.toString();
203 assertEquals(expect, actual);
204 }
205
206 @Test
207 public void testInputSourceNullCharacterStream() {
208 JDOMSource source = new JDOMSource((Document)null);
209 Reader r = source.getInputSource().getCharacterStream();
210 assertNull(r);
211 }
212
213 @Test
214 public void testXMLReaderParse() {
215 JDOMSource source = new JDOMSource(new Document(new Element("root")));
216 XMLReader reader = source.getXMLReader();
217 try {
218 reader.parse(new InputSource("someurl"));
219 fail ("Should not be able to read a non-JDOM input source.");
220 } catch (SAXNotSupportedException sne) {
221 // good;
222 } catch (Exception e) {
223 e.printStackTrace();
224 fail ("Expecting a SAXNotSupportedExcetpion, but got " + e.getClass());
225 }
226
227 }
228
229 @Test
230 public void testXMLReaderParseSystemID() {
231 JDOMSource source = new JDOMSource(new Document(new Element("root")));
232 XMLReader reader = source.getXMLReader();
233 try {
234 reader.parse("systemID");
235 fail ("Should not be able to read a SystemID.");
236 } catch (SAXNotSupportedException sne) {
237 // good;
238 } catch (Exception e) {
239 e.printStackTrace();
240 fail ("Expecting a SAXNotSupportedExcetpion, but got " + e.getClass());
241 }
242 }
243
244 @Test
245 public void testXMLReaderParseOtherInputSource() {
246 JDOMSource source = new JDOMSource(new Document(new Element("root")));
247 XMLReader reader = source.getXMLReader();
248 try {
249 reader.parse(new InputSource("someurl"));
250 fail ("Should not be able to read a non-JDOM input source.");
251 } catch (SAXNotSupportedException sne) {
252 // good;
253 } catch (Exception e) {
254 e.printStackTrace();
255 fail ("Expecting a SAXNotSupportedExcetpion, but got " + e.getClass());
256 }
257 }
258
259 @Test
260 public void testXMLReaderParseJDOMDocumentInputSource() throws SAXException, IOException {
261 JDOMSource sourcea = new JDOMSource(new Document(new Element("root")));
262 JDOMSource sourceb = new JDOMSource(new Document(new Element("fubar")));
263 XMLReader reader = sourcea.getXMLReader();
264 assertTrue(reader instanceof SAXOutputter);
265 SAXOutputter readeroutputter = (SAXOutputter)reader;
266 final AtomicReference<String> emtname = new AtomicReference<String>(null);
267
268 DefaultHandler2 handler = new DefaultHandler2() {
269 @Override
270 public void startElement(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {
271 emtname.set(arg1);
272 }
273 };
274
275 readeroutputter.setContentHandler(handler);
276
277 reader.parse(sourceb.getInputSource());
278
279 assertEquals("fubar", emtname.get());
280
281 }
282
283 @Test
284 public void testXMLReaderParseJDOMElementInputSource() throws SAXException, IOException {
285 JDOMSource sourcea = new JDOMSource(new Element("root"));
286 JDOMSource sourceb = new JDOMSource(new Element("fubar"));
287 XMLReader reader = sourcea.getXMLReader();
288 assertTrue(reader instanceof SAXOutputter);
289 SAXOutputter readeroutputter = (SAXOutputter)reader;
290 final AtomicReference<String> emtname = new AtomicReference<String>(null);
291
292 DefaultHandler2 handler = new DefaultHandler2() {
293 @Override
294 public void startElement(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {
295 emtname.set(arg1);
296 }
297 };
298
299 readeroutputter.setContentHandler(handler);
300
301 reader.parse(sourceb.getInputSource());
302
303 assertEquals("fubar", emtname.get());
304
305 }
306
307 @Test
308 public void testXMLReaderParseGarbageInputSource() {
309
310 JDOMSource sourcea = new JDOMSource(new Element("root"));
311 List<Double> junk = Collections.singletonList(Double.valueOf(123.4));
312 // Jump through hoops to defeat Generics.
313 @SuppressWarnings("cast")
314 List<?> tmpa = (List<?>)junk;
315 @SuppressWarnings("unchecked")
316 List<Content> tmpb = (List<Content>)tmpa;
317 JDOMSource sourceb = new JDOMSource(tmpb);
318 XMLReader reader = sourcea.getXMLReader();
319 assertTrue(reader instanceof SAXOutputter);
320 SAXOutputter readeroutputter = (SAXOutputter)reader;
321
322 DefaultHandler2 handler = new DefaultHandler2();
323
324 readeroutputter.setContentHandler(handler);
325
326 try {
327 reader.parse(sourceb.getInputSource());
328 fail ("Should not be able to parse garbage data 123.4");
329 } catch (ClassCastException se) {
330 // good!
331 } catch (Exception e) {
332 e.printStackTrace();
333 fail("Expecting SAXException, but got " + e.getClass());
334 }
335
336 }
337 }
0 package org.jdom.test.cases.transform;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.fail;
4
5 import java.io.StringReader;
6 import java.io.StringWriter;
7
8 import javax.xml.transform.Transformer;
9 import javax.xml.transform.TransformerException;
10 import javax.xml.transform.TransformerFactory;
11 import javax.xml.transform.stream.StreamResult;
12 import javax.xml.transform.stream.StreamSource;
13
14 import org.jdom.Attribute;
15 import org.jdom.CDATA;
16 import org.jdom.Comment;
17 import org.jdom.DocType;
18 import org.jdom.Document;
19 import org.jdom.Element;
20 import org.jdom.Namespace;
21 import org.jdom.ProcessingInstruction;
22 import org.jdom.Text;
23 import org.jdom.output.XMLOutputter2;
24 import org.jdom.transform.JDOMResult;
25 import org.jdom.transform.JDOMSource;
26 import org.junit.Ignore;
27 import org.junit.Test;
28
29 @SuppressWarnings("javadoc")
30 public class TestJDOMTransform {
31
32 private static final void checkTransform(Document doc) {
33 XMLOutputter2 out = new XMLOutputter2();
34 String expect = out.outputString(doc);
35
36 try {
37
38 Transformer t = TransformerFactory.newInstance().newTransformer();
39 StringWriter sw = new StringWriter();
40 t.transform(new JDOMSource(doc), new StreamResult(sw));
41 JDOMResult res = new JDOMResult();
42 String intermediate = sw.toString() + "\n\n\n\n ";
43 t.transform(new StreamSource(new StringReader(intermediate)), res);
44 Document redone = res.getDocument();
45 String actual = out.outputString(redone);
46 assertEquals(expect, actual);
47 } catch (TransformerException te) {
48 te.printStackTrace();
49 fail (te.getMessage());
50 }
51 }
52
53 @Test
54 public void testRootAttNS() {
55 Document doc = new Document();
56 Element e = new Element("root");
57 e.setAttribute(new Attribute("att", "val", Namespace.getNamespace("ans", "mynamespace")));
58 doc.addContent(e);
59 checkTransform(doc);
60 }
61
62
63 @Test
64 public void testSimpleDocument() {
65 checkTransform(new Document(new Element("root")));
66 }
67
68 @Test
69 @Ignore //TODO DocType does not survive transform. Can it be tested?
70 public void testDocumentDocType() {
71 DocType dt = new DocType("root");
72 checkTransform(new Document(new Element("root"), dt));
73 }
74
75 @Test
76 public void testComplexDocument() {
77 // throw a lot of junk at the process... testing it all.
78 Document doc = new Document();
79 doc.addContent(new Comment("This is a document"));
80 doc.addContent(new ProcessingInstruction("jdomtest", ""));
81 Element root = new Element("root");
82 // messes up the ordering of things ... root.setAttribute(new Attribute("att", "val"));
83 root.setAttribute(new Attribute("att", "val", Namespace.getNamespace("ans", "attns")));
84 root.addContent(new Text(" "));
85 root.addContent(new Element("child", Namespace.getNamespace("nopfx")));
86 root.addContent(new CDATA(" cdata "));
87 root.addContent(new Comment("comment"));
88 Element otherchild = new Element("child", Namespace.getNamespace("cns", "childns"));
89 otherchild.addNamespaceDeclaration(Namespace.getNamespace("abc","oddns"));
90 Element grandchild = new Element("leaf", Namespace.getNamespace("abc", "oddns"));
91 // EntityRef will not survive transform
92 // grandchild.addContent(new EntityRef("myref", "systemID"));
93 otherchild.addContent(grandchild);
94 root.addContent(otherchild);
95 doc.addContent(root);
96 checkTransform(doc);
97
98 }
99
100 }
0 package org.jdom.test.cases.transform;
1
2 import static org.junit.Assert.*;
3
4 import org.jdom.transform.XSLTransformException;
5 import org.junit.Test;
6
7 @SuppressWarnings("javadoc")
8 public class TestXSLTransformExceptn {
9
10 @Test
11 public void testXSLTransformException() {
12 XSLTransformException e = new XSLTransformException();
13 assertNull(e.getCause());
14 assertEquals("Error occurred in JDOM application.", e.getMessage());
15 }
16
17 @Test
18 public void testXSLTransformExceptionString() {
19 XSLTransformException e = new XSLTransformException("msg");
20 assertNull(e.getCause());
21 assertEquals("msg", e.getMessage());
22 }
23
24 @Test
25 public void testXSLTransformExceptionStringException() {
26 RuntimeException re = new RuntimeException("abc");
27 XSLTransformException e = new XSLTransformException("msg", re);
28 assertTrue(re == e.getCause());
29 assertEquals("msg", e.getMessage());
30 }
31
32 }
0 package org.jdom.test.cases.transform;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertNull;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.fail;
6
7 import java.io.ByteArrayInputStream;
8 import java.io.File;
9 import java.io.FileWriter;
10 import java.io.IOException;
11 import java.io.StringReader;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15
16 import org.jdom.Content;
17 import org.jdom.DefaultJDOMFactory;
18 import org.jdom.Document;
19 import org.jdom.Element;
20 import org.jdom.JDOMException;
21 import org.jdom.JDOMFactory;
22 import org.jdom.Namespace;
23 import org.jdom.input.SAXBuilder;
24 import org.jdom.output.XMLOutputter2;
25 import org.jdom.transform.XSLTransformException;
26 import org.jdom.transform.XSLTransformer;
27 import org.junit.Ignore;
28 import org.junit.Test;
29
30 @SuppressWarnings("javadoc")
31 public class TestXSLTransformer {
32
33 private static final String xslpassthrough =
34 "<?xml version=\"1.0\"?>\n" +
35 "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" +
36 " <xsl:output encoding=\"UTF-8\" />\n" +
37 " <xsl:template match=\"*\">\n" +
38 " <xsl:copy-of select=\".\" />\n" +
39 " </xsl:template>\n" +
40 "</xsl:stylesheet>\n";
41
42 private interface SetupTransform {
43 XSLTransformer buildTransformer() throws XSLTransformException;
44 }
45
46 private void checkDocs(Document docexpect, Document docactual) {
47 XMLOutputter2 out = new XMLOutputter2();
48 String expect = out.outputString(docexpect);
49 String actual = out.outputString(docactual);
50 assertEquals(expect, actual);
51 }
52
53 private void checkDocs(Document docexpect, boolean addroot, List<Content> content) {
54 List<Content> toadd = content;
55 if (addroot) {
56 Element root = new Element(docexpect.getRootElement().getName());
57 root.addContent(content);
58 toadd = Collections.singletonList((Content)root);
59 }
60 Document actdoc = new Document(toadd);
61 checkDocs(docexpect, actdoc);
62 }
63
64 private void checkTransform(Document doc, Document content, SetupTransform setup) {
65 try {
66 XSLTransformer trans = setup == null
67 ? new XSLTransformer(new StringReader(xslpassthrough))
68 : setup.buildTransformer();
69 Document out = trans.transform(content);
70 checkDocs(doc, out);
71 } catch (Exception e) {
72 e.printStackTrace();
73 fail("Unexpected excepion: " + e.getMessage());
74 }
75 }
76
77 private void checkTransform(Document doc, List<Content> content, boolean atroot, SetupTransform setup) {
78 try {
79 XSLTransformer trans = setup == null
80 ? new XSLTransformer(new StringReader(xslpassthrough))
81 : setup.buildTransformer();
82 List<Content> out = trans.transform(content);
83 checkDocs(doc, atroot, out);
84 } catch (Exception e) {
85 e.printStackTrace();
86 fail("Unexpected excepion: " + e.getMessage());
87 }
88 }
89
90 @Test
91 public void testXSLTransformerInputStream() {
92 Document doc = new Document(new Element("root"));
93 checkTransform(doc, doc, new SetupTransform() {
94 @Override
95 public XSLTransformer buildTransformer() throws XSLTransformException {
96 return new XSLTransformer(new ByteArrayInputStream(xslpassthrough.getBytes()));
97 }
98 });
99 }
100
101 @Test
102 public void testXSLTransformerReader() {
103 Document doc = new Document(new Element("root"));
104 checkTransform(doc, doc, new SetupTransform() {
105 @Override
106 public XSLTransformer buildTransformer() throws XSLTransformException {
107 return new XSLTransformer(new StringReader(xslpassthrough));
108 }
109 });
110 }
111
112 @Test
113 public void testXSLTransformerString() throws IOException {
114 File tmpf = File.createTempFile("jdomxsltest", ".xml");
115 try {
116 tmpf.deleteOnExit();
117 FileWriter fw = new FileWriter(tmpf);
118 fw.write(xslpassthrough);
119 fw.flush();
120 fw.close();
121 final String url = tmpf.toURI().toURL().toExternalForm();
122 Document doc = new Document(new Element("root"));
123 checkTransform(doc, doc, new SetupTransform() {
124 @Override
125 public XSLTransformer buildTransformer() throws XSLTransformException {
126 return new XSLTransformer(url);
127 }
128 });
129 } finally {
130 tmpf.delete();
131 }
132 }
133
134 @Test
135 public void testXSLTransformerFile() throws IOException {
136 final File tmpf = File.createTempFile("jdomxsltest", ".xml");
137 try {
138 tmpf.deleteOnExit();
139 FileWriter fw = new FileWriter(tmpf);
140 fw.write(xslpassthrough);
141 fw.flush();
142 fw.close();
143 Document doc = new Document(new Element("root"));
144 checkTransform(doc, doc, new SetupTransform() {
145 @Override
146 public XSLTransformer buildTransformer() throws XSLTransformException {
147 return new XSLTransformer(tmpf);
148 }
149 });
150 } finally {
151 tmpf.delete();
152 }
153 }
154
155 @Test
156 public void testXSLTransformerDocument() throws JDOMException, IOException {
157 SAXBuilder builder = new SAXBuilder();
158 final Document xsldoc = builder.build(new StringReader(xslpassthrough));
159 Document doc = new Document(new Element("root"));
160 checkTransform(doc, doc, new SetupTransform() {
161 @Override
162 public XSLTransformer buildTransformer() throws XSLTransformException {
163 return new XSLTransformer(xsldoc);
164 }
165 });
166 }
167
168 @Test
169 public void testTransformList() throws JDOMException, IOException {
170 SAXBuilder builder = new SAXBuilder();
171 final Document xsldoc = builder.build(new StringReader(xslpassthrough));
172 Document doc = new Document(new Element("root"));
173 List<Content> content = new ArrayList<Content>();
174 content.add(new Element("root"));
175 checkTransform(doc, content, false, new SetupTransform() {
176 @Override
177 public XSLTransformer buildTransformer() throws XSLTransformException {
178 return new XSLTransformer(xsldoc);
179 }
180 });
181 }
182
183 @Test
184 @Ignore
185 public void testTransformDocumentEntityResolver() {
186 fail("Not yet implemented");
187 }
188
189 @Test
190 public void testGetSetFactory() throws JDOMException, IOException {
191 final JDOMFactory fac = new DefaultJDOMFactory() {
192 @Override
193 public Element element(final int line, final int col, String name, String prefix, String uri) {
194 return super.element(line, col, "xx" + name, prefix, uri);
195 }
196 @Override
197 public Element element(final int line, final int col, String name, String uri) {
198 return super.element(line, col, "xx" + name, uri);
199 }
200 @Override
201 public Element element(final int line, final int col, String name) {
202 return super.element(line, col, "xx" + name);
203 }
204 @Override
205 public Element element(final int line, final int col, String name, Namespace namespace) {
206 return super.element(line, col, "xx" + name, namespace);
207 }
208 };
209
210 SAXBuilder builder = new SAXBuilder();
211 final Document xsldoc = builder.build(new StringReader(xslpassthrough));
212 final XSLTransformer trans = new XSLTransformer(xsldoc);
213 assertNull(trans.getFactory());
214 trans.setFactory(fac);
215 assertTrue(trans.getFactory() == fac);
216
217 Document doc = new Document(new Element("root"));
218 Document expect = new Document(new Element("xxroot"));
219 checkTransform(expect, doc, new SetupTransform() {
220 @Override
221 public XSLTransformer buildTransformer() throws XSLTransformException {
222 return trans;
223 }
224 });
225
226
227 }
228
229 }
0 package org.jdom.test.cases.util;
1
2 import static org.junit.Assert.*;
3
4 import java.util.Arrays;
5
6 import org.junit.Test;
7
8 import org.jdom.internal.ArrayCopy;
9 import org.jdom.test.util.UnitTestUtil;
10
11 @SuppressWarnings("javadoc")
12 public class TestArrayCopy {
13
14 // UnitTests/compile is done from Java6 .... so
15 // we can compare with Arrays.copyOf()
16
17 @Test
18 public void testCopyOfEArrayInt() {
19 final String[] val = {"a", "b", "c", "d"};
20 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 3), Arrays.copyOf(val, 3)));
21 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 0), Arrays.copyOf(val, 0)));
22 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 5), Arrays.copyOf(val, 5)));
23 }
24
25 @Test
26 public void testCopyOfRange() {
27 final String[] val = {"a", "b", "c", "d"};
28 assertTrue(Arrays.equals(ArrayCopy.copyOfRange(val, 1, 2), Arrays.copyOfRange(val, 1, 2)));
29 assertTrue(Arrays.equals(ArrayCopy.copyOfRange(val, 1, 5), Arrays.copyOfRange(val, 1, 5)));
30 try {
31 ArrayCopy.copyOfRange(val, 3, 2);
32 UnitTestUtil.failNoException(IllegalArgumentException.class);
33 } catch (Exception e) {
34 UnitTestUtil.checkException(IllegalArgumentException.class, e);
35 }
36 }
37
38 @Test
39 public void testCopyOfCharArrayInt() {
40 final char[] val = {'a', 'b', 'c', 'd'};
41 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 3), Arrays.copyOf(val, 3)));
42 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 0), Arrays.copyOf(val, 0)));
43 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 5), Arrays.copyOf(val, 5)));
44 }
45
46 @Test
47 public void testCopyOfIntArrayInt() {
48 final int[] val = {1, 2, 3, 4};
49 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 3), Arrays.copyOf(val, 3)));
50 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 0), Arrays.copyOf(val, 0)));
51 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 5), Arrays.copyOf(val, 5)));
52 }
53
54 @Test
55 public void testCopyOfBooleanArrayInt() {
56 final boolean[] val = {true, false, true, false};
57 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 3), Arrays.copyOf(val, 3)));
58 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 0), Arrays.copyOf(val, 0)));
59 assertTrue(Arrays.equals(ArrayCopy.copyOf(val, 5), Arrays.copyOf(val, 5)));
60 }
61
62 }
0 package org.jdom.test.cases.util;
1
2 import static org.junit.Assert.*;
3
4 import java.util.Arrays;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.NoSuchElementException;
8
9 import org.jdom.Element;
10 import org.jdom.Namespace;
11 import org.jdom.util.NamespaceStack;
12
13 import org.junit.Test;
14
15 @SuppressWarnings("javadoc")
16 public class TestNamespaceStack {
17
18 // We do a little cheat in this test class.
19 // NamespaceStack is supposed to make the concept of the
20 // Content.getNamespacesInScope() type methods more efficient.
21 // so, we simply cheat by comparing the one against the other.
22 // We have confidence in the Content.getNamespaces* methods because they are
23 // tested elsewhere.
24
25 private static final void checkIterable(Iterable<Namespace> abl, Namespace...values) {
26 int cnt = 0;
27 for (Namespace ns : abl) {
28 if (cnt >= values.length) {
29 fail("Unexpected extra Namespace: " + ns);
30 }
31 if (ns != values[cnt]) {
32 fail("We expected Namespace " + values[cnt] + " but instead we got " + ns);
33 }
34 cnt++;
35 }
36 if (cnt <values.length) {
37 fail("We expected an additional " + (values.length - cnt) + " Namespaces, starting with " + values[cnt]);
38 }
39 Iterator<Namespace> it = abl.iterator();
40 while (--cnt >= 0) {
41 it.next();
42 }
43
44 assertFalse(it.hasNext());
45
46 try {
47 it.remove();
48 fail("Should not be able to remove content from this iterator.");
49 } catch (UnsupportedOperationException uoe) {
50 // good.
51 } catch (Exception e) {
52 e.printStackTrace();
53 fail("expected UnsupportedOperationException but got :" + e.getClass());
54 }
55
56 try {
57 it.next();
58 fail("Should not be able to iterate beyond the iterator.");
59 } catch (NoSuchElementException nsee) {
60 // good.
61 } catch (Exception e) {
62 e.printStackTrace();
63 fail("expected NoSuchElementException but got :" + e.getClass());
64 }
65 }
66
67 private static final void reverse(Namespace[] data) {
68 Namespace tmp = null;
69 int left = 0, right = data.length - 1;
70 while (left < right) {
71 tmp = data[left];
72 data[left] = data[right];
73 data[right] = tmp;
74 left++;
75 right--;
76 }
77 }
78
79 private static final void checkIterators(NamespaceStack stack,
80 List<Namespace> lscope, List<Namespace> lintro) {
81
82 Namespace[] scope = lscope.toArray(new Namespace[0]);
83 checkIterable(stack, scope);
84 Namespace[] intro = lintro.toArray(new Namespace[0]);
85 checkIterable(stack.addedForward(), intro);
86 reverse(intro);
87 checkIterable(stack.addedReverse(), intro);
88 }
89
90 private void exercise(Element emt, NamespaceStack stack) {
91 List<Namespace> scope = emt.getNamespacesInScope();
92 List<Namespace> intro = emt.getNamespacesIntroduced();
93
94 for (Namespace ns : intro) {
95 assertFalse(stack.isInScope(ns));
96 }
97
98 stack.push(emt);
99
100 for (Namespace ns : intro) {
101 assertTrue(stack.isInScope(ns));
102 }
103
104
105 checkIterators(stack, scope, intro);
106
107
108 for (Element e : emt.getChildren()) {
109 exercise(e, stack);
110 }
111
112 checkIterators(stack, scope, intro);
113 stack.pop();
114 }
115
116 @Test
117 public void testEmptyStack() {
118 Namespace[] scopea = new Namespace[] {Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE};
119 List<Namespace> scopel = Arrays.asList(scopea);
120
121 NamespaceStack stack = new NamespaceStack();
122
123 checkIterators(stack, scopel, scopel);
124
125 try {
126 stack.pop();
127 fail("Should not be able to over-pop the stack.");
128 } catch (IllegalStateException ise) {
129 // good.
130 } catch (Exception e) {
131 e.printStackTrace();
132 fail("Expected IllegalStateException but got " + e.getClass());
133 }
134
135 }
136
137 @Test
138 public void testSimpleEment() {
139 Element root = new Element("root");
140 exercise(root, new NamespaceStack());
141 }
142
143 @Test
144 public void testTwentyDeepEment() {
145 Element root = new Element("root");
146 int cnt = 20;
147 Element e = root;
148 while (--cnt >= 0) {
149 Element c = new Element("kid", Namespace.getNamespace("Level:" + cnt));
150 e.addContent(c);
151 e = c;
152 }
153 exercise(root, new NamespaceStack());
154 }
155
156 @Test
157 public void testChangeMainNoOthers() {
158 Element root = new Element("root", Namespace.getNamespace("rooturl"));
159 // child is in a different namespace but with same "" prefix.
160 Element child = new Element("child", Namespace.getNamespace("childurl"));
161 // leaf is in the NO_NAMESPACE namespace (also prefix "");
162 Element leaf = new Element("leaf");
163
164 root.addContent(child);
165 child.addContent(leaf);
166 exercise(root, new NamespaceStack());
167 }
168
169 @Test
170 public void testChangeMainWithOthers() {
171 Namespace nsa = Namespace.getNamespace("pfxa", "nsurla");
172 Namespace nsb = Namespace.getNamespace("pfxb", "nsurlb");
173 Namespace nsc = Namespace.getNamespace("pfxc", "nsurlc");
174 Namespace nsd = Namespace.getNamespace("pfxd", "nsurld");
175
176 Element root = new Element("root", Namespace.getNamespace("rooturl"));
177 // child is in a different namespace but with same "" prefix.
178 Element child = new Element("child", Namespace.getNamespace("childurl"));
179 // leaf is in the NO_NAMESPACE namespace (also prefix "");
180 Element leaf = new Element("leaf");
181
182 root.addNamespaceDeclaration(nsa);
183 root.addNamespaceDeclaration(nsb);
184 root.addNamespaceDeclaration(nsc);
185 root.addNamespaceDeclaration(nsd);
186
187 child.addNamespaceDeclaration(nsa);
188 child.addNamespaceDeclaration(nsb);
189 child.addNamespaceDeclaration(nsc);
190 child.addNamespaceDeclaration(nsd);
191
192 // On the leaf we try the varaint of adding the namespace
193 // via the attributes.
194 leaf.setAttribute("att", "val", nsa);
195 leaf.setAttribute("att", "val", nsb);
196 leaf.setAttribute("att", "val", nsc);
197 leaf.setAttribute("att", "val", nsd);
198
199 root.addContent(child);
200 child.addContent(leaf);
201 exercise(root, new NamespaceStack());
202 }
203
204 @Test
205 public void testChangeAltNoOthers() {
206 // note, they all have same prefix.
207 Namespace nsa = Namespace.getNamespace("pfxa", "nsurla");
208 Namespace nsb = Namespace.getNamespace("pfxa", "nsurlb");
209 Namespace nsc = Namespace.getNamespace("pfxa", "nsurlc");
210
211 Element root = new Element("root");
212 Element child = new Element("child");
213 Element leaf = new Element("leaf");
214
215 root.addNamespaceDeclaration(nsa);
216
217 child.addNamespaceDeclaration(nsb);
218
219 // On the leaf we try the varaint of adding the namespace
220 // via the attributes.
221 leaf.setAttribute("att", "val", nsc);
222
223 root.addContent(child);
224 child.addContent(leaf);
225 exercise(root, new NamespaceStack());
226 }
227
228 @Test
229 public void testChangeAltWithOthers() {
230 // note, they all have same prefix.
231 Namespace nsa = Namespace.getNamespace("pfxa", "nsurla");
232 Namespace nsb = Namespace.getNamespace("pfxa", "nsurlb");
233 Namespace nsc = Namespace.getNamespace("pfxa", "nsurlc");
234 Namespace alta = Namespace.getNamespace("alta", "nsalturla");
235 Namespace altb = Namespace.getNamespace("altb", "nsalturlb");
236
237 Element root = new Element("root");
238 Element child = new Element("child");
239 Element leaf = new Element("leaf");
240
241 root.addNamespaceDeclaration(nsa);
242 root.addNamespaceDeclaration(alta);
243 root.addNamespaceDeclaration(altb);
244
245 child.addNamespaceDeclaration(nsb);
246 child.addNamespaceDeclaration(alta);
247 child.addNamespaceDeclaration(altb);
248
249 // On the leaf we try the varaint of adding the namespace
250 // via the attributes.
251 leaf.setAttribute("att", "val", nsc);
252 leaf.addNamespaceDeclaration(alta);
253 leaf.addNamespaceDeclaration(altb);
254
255 root.addContent(child);
256 child.addContent(leaf);
257 exercise(root, new NamespaceStack());
258 }
259
260
261 @Test
262 public void testSwapMainAlt() {
263 // note, they all have same prefix.
264 Namespace nsa = Namespace.getNamespace("pfxa", "nsurla");
265 Namespace nsb = Namespace.getNamespace("pfxb", "nsurlb");
266
267 // Note how they have the same namespaces, just swap between
268 // Element and Attribute.
269 Element root = new Element("root", nsa);
270 root.setAttribute("att", "val", nsb);
271
272 Element child = new Element("child", nsb);
273 child.setAttribute("att", "val", nsa);
274
275 root.addContent(child);
276
277 exercise(root, new NamespaceStack());
278 }
279
280 @Test
281 public void testAttributeSpecialCases() {
282 // note, they all have same prefix.
283 Namespace nsa = Namespace.getNamespace("pfxa", "nsurla");
284 Namespace nsb = Namespace.getNamespace("pfxb", "nsurlb");
285
286 // Note how they have the same namespaces, just swap between
287 // Element and Attribute.
288 Element root = new Element("root", nsa);
289 // attribute has same Namespace as element
290 root.setAttribute("att", "val", nsa);
291
292 Element child = new Element("child", nsb);
293 // Attribute has no namespace.
294 child.setAttribute("att", "val");
295
296 root.addContent(child);
297
298 exercise(root, new NamespaceStack());
299 }
300
301 @Test
302 public void testAdditionalSpecialCases() {
303 // note, they all have same prefix.
304 Namespace nsa = Namespace.getNamespace("pfxa", "nsurla");
305
306 // Note how they have the same namespaces, just swap between
307 // Element and Attribute.
308 Element root = new Element("root", nsa);
309 // additional has same Namespace as element
310 root.addNamespaceDeclaration(nsa);
311
312 exercise(root, new NamespaceStack());
313 }
314
315 @Test
316 public void testSeededConstructor() {
317 Namespace x = Namespace.getNamespace("X");
318 Namespace y = Namespace.getNamespace("y", "Y");
319 Namespace[] nsa = new Namespace[] {
320 x, Namespace.XML_NAMESPACE
321 };
322 NamespaceStack nstack = new NamespaceStack(nsa);
323 checkIterable(nstack, nsa);
324 checkIterable(nstack.addedForward(), nsa);
325 Element emt = new Element("root", y);
326 emt.addNamespaceDeclaration(Namespace.NO_NAMESPACE);
327 nstack.push(emt);
328 checkIterable(nstack, y, Namespace.NO_NAMESPACE, Namespace.XML_NAMESPACE);
329 checkIterable(nstack.addedForward(), y, Namespace.NO_NAMESPACE);
330 }
331 }
0 package org.jdom.test.cases.util;
1
2 import static org.jdom.test.util.UnitTestUtil.checkException;
3 import static org.jdom.test.util.UnitTestUtil.failNoException;
4 import static org.junit.Assert.assertTrue;
5
6 import java.util.List;
7
8 import org.junit.Test;
9
10 import org.jdom.Namespace;
11 import org.jdom.internal.ReflectionConstructor;
12
13 @SuppressWarnings("javadoc")
14 public class TestReflectionConstructor {
15
16 @Test
17 public void testConstruct() {
18 List<?> al = ReflectionConstructor.construct("java.util.ArrayList", List.class);
19 assertTrue(al.isEmpty());
20 }
21
22 @Test
23 public void testConstructNoSuchClass() {
24 try {
25 ReflectionConstructor.construct("java.util.Junk", List.class);
26 failNoException(IllegalArgumentException.class);
27 } catch (Exception e) {
28 checkException(IllegalArgumentException.class, e);
29 }
30 }
31
32 @Test
33 public void testConstructDefaultConstructor() {
34 try {
35 ReflectionConstructor.construct("java.util.Integer", Integer.class);
36 failNoException(IllegalArgumentException.class);
37 } catch (Exception e) {
38 checkException(IllegalArgumentException.class, e);
39 }
40 }
41
42 @Test
43 public void testConstructNoaccessConstructor() {
44 try {
45 ReflectionConstructor.construct("org.jdom.Namespace", Namespace.class);
46 failNoException(IllegalArgumentException.class);
47 } catch (Exception e) {
48 checkException(IllegalArgumentException.class, e);
49 }
50 }
51
52 @Test
53 public void testConstructClassCastConstructor() {
54 try {
55 ReflectionConstructor.construct("java.lang.String", Namespace.class);
56 failNoException(ClassCastException.class);
57 } catch (Exception e) {
58 checkException(ClassCastException.class, e);
59 }
60 }
61 }
0 package org.jdom.test.cases.xpath;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.fail;
6
7 import java.util.Collection;
8 import java.util.Collections;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Map;
12
13 import org.jdom.Attribute;
14 import org.jdom.Comment;
15 import org.jdom.Document;
16 import org.jdom.Element;
17 import org.jdom.JDOMException;
18 import org.jdom.Namespace;
19 import org.jdom.ProcessingInstruction;
20 import org.jdom.Text;
21 import org.jdom.test.util.UnitTestUtil;
22 import org.jdom.xpath.XPath;
23
24 import org.junit.Ignore;
25 import org.junit.Test;
26
27 /**
28 *
29 * @author Rolf Lear
30 * @deprecated replaced by XPathExpression
31 */
32 @SuppressWarnings({"javadoc"})
33 @Deprecated
34 public abstract class AbstractTestXPath {
35
36 private final Document doc = new Document();
37
38 private final Comment doccomment = new Comment("doc comment");
39 private final ProcessingInstruction docpi = new ProcessingInstruction("jdomtest", "doc");
40
41 private final Element main = new Element("main");
42 private final Attribute mainatt = new Attribute("atta", "vala");
43 private final Comment maincomment = new Comment("main comment");
44 private final ProcessingInstruction mainpi = new ProcessingInstruction("jdomtest", "pi data");
45 private final Text maintext1 = new Text(" space1 ");
46 private final Element child1emt = new Element("child");
47 private final Text child1text = new Text("child1text");
48 private final Text maintext2 = new Text(" space2 ");
49 private final Element child2emt = new Element("child");
50
51 private final Namespace child3nsa = Namespace.getNamespace("c3nsa", "jdom:c3nsa");
52 private final Namespace child3nsb = Namespace.getNamespace("c3nsb", "jdom:c3nsb");
53 private final Element child3emt = new Element("child", child3nsa);
54 private final Attribute child3attint = new Attribute("intatt", "-123", child3nsb);
55 private final Attribute child3attdoub = new Attribute("doubatt", "-123.45", child3nsb);
56 private final Text child3txt = new Text("c3text");
57
58 private final String mainvalue = " space1 child1text space2 c3text";
59
60 public AbstractTestXPath() {
61 doc.addContent(doccomment);
62 doc.addContent(docpi);
63 doc.addContent(main);
64 main.setAttribute(mainatt);
65 main.addContent(maincomment);
66 main.addContent(mainpi);
67 main.addContent(maintext1);
68 child1emt.addContent(child1text);
69 main.addContent(child1emt);
70 main.addContent(maintext2);
71 main.addContent(child2emt);
72 child3emt.setAttribute(child3attint);
73 child3emt.setAttribute(child3attdoub);
74 child3emt.addContent(child3txt);
75 main.addContent(child3emt);
76 }
77
78 /**
79 * Create an instance of an XPath.
80 * Override this method to create the type of XPath instance we want to test.
81 * The method should add the supplied Namspace keys, and set the given variables
82 * on the XPath.
83 * @param path
84 * @param variables
85 * @param namespaces
86 * @return
87 * @throws JDOMException
88 */
89 abstract XPath buildPath(String path) throws JDOMException;
90
91 private XPath setupXPath(String path, Map<String, Object> variables, Namespace... namespaces) {
92
93 XPath xpath = null;
94
95 try {
96 xpath = buildPath(path);
97
98 assertTrue(xpath != null);
99
100 assertFalse(xpath.equals(null));
101 assertFalse(xpath.equals(new Object()));
102 UnitTestUtil.checkEquals(xpath, xpath);
103
104 assertEquals("getXPath()", path, xpath.getXPath());
105
106
107 if (variables != null) {
108 for (Map.Entry<String, Object> me : variables.entrySet()) {
109 xpath.setVariable(me.getKey(), me.getValue());
110 }
111 }
112 for (Namespace n : namespaces) {
113 xpath.addNamespace(n);
114 }
115 } catch (JDOMException jde) {
116 jde.printStackTrace();
117 fail("Unable to create XPath " + path);
118 }
119 return xpath;
120
121 }
122
123 /**
124 * A mechanism for exercising the XPath system.
125 * @param xpath The xpath to run.
126 * @param context The context on which to run the XPath
127 * @param string What we expect the 'xpath' string value of the result to be (or null to skip test).
128 * @param number What we expect the xpath to resolve the result to be as an xpath 'Number' (or null to skip test);
129 * @param expect The nodes we expect from the XPath selectNodes query
130 */
131 private static void checkXPath(XPath xpath, Object context, String value, Number number, Object...expect) {
132 try {
133
134 // Check the selectNodes operation.
135 List<?> result = xpath.selectNodes(context);
136 if (result == null) {
137 fail ("Got a null result from selectNodes()");
138 }
139 String sze = result.size() == expect.length ? "" :
140 (" Also Different Sizes: expect=" + expect.length + " actual=" + result.size());
141 int pos = 0;
142 for (Object o : result) {
143 if (pos >= expect.length) {
144 fail ("Results contained additional content at position " +
145 pos + " for xpath '" + xpath + "': " + o + sze);
146 }
147 if (o != expect[pos]) {
148 assertEquals("Failed result at position " + pos +
149 " for xpath '" + xpath + "'." + sze, expect[pos], o);
150 }
151 pos++;
152 }
153 if (pos < expect.length) {
154 fail ("Results are missing " + (expect.length - pos) +
155 " content at position " + pos + " for xpath '" + xpath +
156 "'. First missing content is: " + expect[pos] + sze);
157 }
158
159 // Check the selectSingleNode operation.
160 Object o = xpath.selectSingleNode(context);
161 if (expect.length == 0 && o != null) {
162 fail("Expected XPath.selectSingleNode() to return nothing, " +
163 "but it returned " + o + sze);
164 }
165 if (expect.length > 0 && o == null) {
166 fail("XPath.selectSingleNode() returned nothing, but it should " +
167 "have returned " + expect[0] + sze);
168 }
169 if (expect.length > 0 && o != expect[0]) {
170 assertEquals("XPath.selectSingleNode() was expected to return " +
171 expect[0] + "' but instead it returned '" + o + "'" + sze,
172 expect[0], o);
173 }
174
175 // Check the getValue() operation
176 String gotstring = xpath.valueOf(context);
177 if (value != null) {
178 assertEquals("Checking valueOf()", value, gotstring);
179 }
180
181 // check numberValue()
182 if (number == null) {
183 // we do the check, ignore the result, including exceptions.
184 try {
185 xpath.numberValueOf(context);
186 // Great too!
187 } catch (JDOMException jde) {
188 // OK, ignore it....
189 } catch (Exception e) {
190 e.printStackTrace();
191 fail ("Expecting a value or JDOMException from numberValueOf(), but got " + e.getClass());
192 }
193 } else {
194 Number gotval = xpath.numberValueOf(context);
195 if (!number.equals(gotval)) {
196 assertEquals("Numbers fail to compare!", number, gotval);
197 }
198 }
199
200 // if (expect.length == 0 && o != null) {
201 // fail("Expected XPath.selectSingleNode() to return nothing, " +
202 // "but it returned " + o);
203 // }
204 // if (expect.length > 0 && o == null) {
205 // fail("XPath.selectSingleNode() returned nothing, but it should " +
206 // "have returned " + expect[0]);
207 // }
208 // if (expect.length > 0 && o != expect[0]) {
209 // fail("XPath.selectSingleNode() was expected to return " +
210 // expect[0] + "' but instead it returned '" + o + "'");
211 // }
212
213 } catch (JDOMException e) {
214 e.printStackTrace();
215 fail("Could not process XPath '" + xpath +
216 "'. Failed with: " + e.getClass() +
217 ": " + e.getMessage());
218 }
219 }
220
221 private void checkXPath(String xpath, Object context, String value, Object...expect) {
222 checkXPath(setupXPath(xpath, null), context, value, null, expect);
223 }
224
225 private void checkComplexXPath(String xpath, Object context, Map<String, Object> variables,
226 Collection<Namespace> namespaces, String value, Number number, Object...expect) {
227 Namespace[] nsa = namespaces == null ? new Namespace[0] : namespaces.toArray(new Namespace[0]);
228 checkXPath(setupXPath(xpath, variables, nsa), context, value, number, expect);
229 }
230
231 // @Test
232 // public void testSerialization() {
233 // XPath xpath = setupXPath("//main", null);
234 // XPath xser = UnitTestUtil.deSerialize(xpath);
235 // assertTrue(xpath != xser);
236 // // TODO JaxenXPath has useless equals(). See issue #43
237 // // Additionally, all XPath deserialization is done on the default
238 // // factory... will never be equals() if the factory used to create
239 // // the xpath is different.
240 // // UnitTestUtil.checkEquals(xpath, xser);
241 // assertEquals(xpath.toString(), xser.toString());
242 // }
243
244 @Test
245 public void testSelectDocumentDoc() {
246 checkXPath("/", doc, mainvalue, doc);
247 }
248
249 @Test
250 public void testSelectDocumentMain() {
251 checkXPath("/", main, mainvalue, doc);
252 }
253
254 @Test
255 public void testSelectDocumentAttr() {
256 checkXPath("/", child3attint, mainvalue, doc);
257 }
258
259 @Test
260 public void testSelectDocumentPI() {
261 checkXPath("/", mainpi, mainvalue, doc);
262 }
263
264 @Test
265 public void testSelectDocumentText() {
266 checkXPath("/", child1text, mainvalue, doc);
267 }
268
269 @Test
270 public void testSelectMainByName() {
271 checkXPath("main", doc, mainvalue, main);
272 }
273
274 @Test
275 public void testSelectMainFromDoc() {
276 checkXPath("//main", doc, mainvalue, main);
277 }
278
279 @Test
280 public void testAncestorsFromRoot() {
281 checkXPath("ancestor::node()", doc, "");
282 }
283
284 @Test
285 public void testAncestorsFromMain() {
286 checkXPath("ancestor::node()", main, mainvalue, doc);
287 }
288
289 @Test
290 public void testAncestorsFromChild() {
291 checkXPath("ancestor::node()", child1emt, mainvalue, doc, main);
292 }
293
294 @Test
295 public void testAncestorOrSelfFromRoot() {
296 checkXPath("ancestor-or-self::node()", doc, mainvalue, doc);
297 }
298
299 @Test
300 public void testAncestorOrSelfFromMain() {
301 checkXPath("ancestor-or-self::node()", main, mainvalue, doc, main);
302 }
303
304 @Test
305 public void testAncestorOrSelfFromMainAttribute() {
306 checkXPath("ancestor-or-self::node()", mainatt, mainvalue, doc, main, mainatt);
307 }
308
309 @Test
310 public void testAncestorOrSelfFromNamespace() {
311 checkXPath("ancestor-or-self::node()", child3nsa, null, child3nsa);
312 }
313
314 @Test
315 public void testAncestorOrSelfFromChild() {
316 checkXPath("ancestor-or-self::node()", child1emt, mainvalue, doc, main, child1emt);
317 }
318
319
320 /* *************************************
321 * Boolean/Double/String tests.
322 * ************************************* */
323
324 @Test
325 public void getXPathDouble() {
326 checkXPath("count( //* )", doc, null, Double.valueOf(4));
327 }
328
329 @Test
330 public void getXPathString() {
331 checkXPath("string( . )", child1emt, null, child1text.getText());
332 }
333
334 @Test
335 public void getXPathBoolean() {
336 checkXPath("count (//*) > 1", child1emt, null, Boolean.TRUE);
337 }
338
339 /* *************************************
340 * Element tests.
341 * ************************************* */
342
343 @Test
344 public void getXPathElementName() {
345 checkXPath("//*[name() = 'main']", doc, null, main);
346 }
347
348 @Test
349 public void getXPathElementText() {
350 checkXPath("//*[string() = 'child1text']", doc, null, child1emt);
351 }
352
353
354 /* *************************************
355 * Processing Instruction tests.
356 * ************************************* */
357
358 @Test
359 public void getXPathProcessingInstructionAll() {
360 checkXPath("//processing-instruction()", doc, null, docpi, mainpi);
361 }
362
363 @Test
364 public void getXPathProcessingInstructionByTarget() {
365 checkXPath("//processing-instruction()[name() = 'jdomtest']", doc, null, docpi, mainpi);
366 }
367
368 @Test
369 public void getXPathProcessingInstructionByData() {
370 checkXPath("//processing-instruction()[string() = 'doc']", doc, null, docpi);
371 }
372
373 /* *************************************
374 * Attribute tests.
375 * ************************************* */
376
377 @Test
378 @Ignore
379 public void getXPathAttributeAll() {
380 checkXPath("//@*", doc, null, mainatt, child3attint, child3attdoub);
381 }
382
383 @Test
384 public void getXPathAttributeByName() {
385 checkXPath("//@*[name() = 'atta']", doc, null, mainatt);
386 }
387
388 @Test
389 public void getXPathAttributeByValue() {
390 checkXPath("//@*[string() = '-123']", doc, null, child3attint);
391 }
392
393 /* *************************************
394 * XPath Variable tests.
395 * ************************************* */
396
397 @Test
398 public void testSetVariable() {
399 HashMap<String,Object> hm = new HashMap<String, Object>();
400 String attval = mainatt.getValue();
401 hm.put("valvar", attval);
402 checkComplexXPath("//@*[string() = $valvar]", doc, hm, null, attval, null, mainatt);
403 }
404
405 /* *************************************
406 * XPath namespace tests.
407 * ************************************* */
408 @Test
409 public void testAttributeNamespaceAsNumberToo() {
410 checkComplexXPath("//@c3nsb:intatt", child3emt, null, null,
411 "-123", Double.valueOf(-123), child3attint);
412 checkComplexXPath("//@c3nsb:doubatt", child3emt, null, null,
413 "-123.45", Double.valueOf(-123.45), child3attdoub);
414 }
415
416 @Test
417 public void testAddNamespaceNamespace() {
418 checkComplexXPath("//c3nsa:child", doc, null, Collections.singleton(child3nsa),
419 child3emt.getValue(), null, child3emt);
420 }
421
422 @Test
423 @Ignore
424 public void testGetALLNamespaces() {
425 //Namespace.NO_NAMESPACE is declared earlier in documentOrder.
426 // so it comes first.
427 checkXPath("//c3nsa:child/namespace::*", child3emt, "jdom:c3nsa",
428 child3nsa, Namespace.NO_NAMESPACE, child3nsb, Namespace.XML_NAMESPACE);
429 }
430
431 @Test
432 @Ignore
433 // This fails the Jaxen Builder because the returned attributes are not in document order.
434 public void testAttributesNamespace() {
435 checkComplexXPath("//@*[namespace-uri() = 'jdom:c3nsb']", doc, null, null,
436 "-123", Double.valueOf(-123), child3emt.getAttributes().toArray());
437 }
438
439 @Test
440 public void testXPathDefaultNamespacesFromElement() {
441 // the significance here is that the c3nsb namespace should already be
442 // available because it is in scope on the 'context' element.
443 // so, there should be no need to re-declare it for the xpath.
444 checkComplexXPath("//@c3nsb:*[string() = '-123']", child3emt, null, null,
445 "-123", Double.valueOf(-123), child3attint);
446 }
447
448 @Test
449 public void testXPathDefaultNamespacesFromAttribute() {
450 // the significance here is that the c3nsb namespace should already be
451 // available because it is in scope on the 'context' element.
452 // so, there should be no need to re-declare it for the xpath.
453 checkComplexXPath("//@c3nsb:*[string() = '-123']", child3attdoub, null, null,
454 "-123", Double.valueOf(-123), child3attint);
455 }
456
457 @Test
458 public void testXPathDefaultNamespacesFromText() {
459 // the significance here is that the c3nsb namespace should already be
460 // available because it is in scope on the 'context' element.
461 // so, there should be no need to re-declare it for the xpath.
462 checkComplexXPath("//@c3nsb:*[string() = '-123']", child3txt, null, null,
463 "-123", Double.valueOf(-123), child3attint);
464 }
465
466 /* *******************************
467 * Axis TestCases
468 * ******************************* */
469
470 @Test
471 public void testXPathAncestor() {
472 checkXPath("ancestor::*", child3txt, null, main, child3emt);
473 }
474
475 @Test
476 public void testXPathAncestorOrSelf() {
477 checkXPath("ancestor-or-self::*", child3txt, null, main, child3emt);
478 }
479
480 @Test
481 public void testXPathAncestorNodes() {
482 checkXPath("ancestor::node()", child3txt, null, doc, main, child3emt);
483 }
484
485 @Test
486 public void testXPathAncestorOrSelfNodes() {
487 checkXPath("ancestor-or-self::node()", child3txt, null, doc, main, child3emt, child3txt);
488 }
489
490 @Test
491 public void testXPathAncestorOrSelfNodesFromAtt() {
492 checkXPath("ancestor-or-self::node()", child3attint, null, doc, main, child3emt, child3attint);
493 }
494
495 @Test
496 public void testXPathAttributes() {
497 checkXPath("attribute::*", child3emt, null, child3attint, child3attdoub);
498 }
499
500 @Test
501 public void testXPathChild() {
502 checkXPath("child::*", main, null, child1emt, child2emt, child3emt);
503 }
504
505 @Test
506 public void testXPathDescendant() {
507 checkXPath("descendant::*", doc, null, main, child1emt, child2emt, child3emt);
508 }
509
510 @Test
511 public void testXPathDescendantNode() {
512 checkXPath("descendant::node()", doc, null, doccomment, docpi, main,
513 maincomment, mainpi, maintext1, child1emt, child1text,
514 maintext2, child2emt, child3emt, child3txt);
515 }
516
517 @Test
518 public void testXPathDescendantOrSelf() {
519 checkXPath("descendant-or-self::*", doc, null, main, child1emt, child2emt, child3emt);
520 }
521
522 @Test
523 public void testXPathFollowing() {
524 checkXPath("following::*", child2emt, null, child3emt);
525 }
526
527 @Test
528 public void testXPathFollowingNode() {
529 checkXPath("following::node()", child2emt, null, child3emt, child3txt);
530 }
531
532 @Test
533 public void testXPathFollowingSibling() {
534 checkXPath("following-sibling::*", child1emt, null, child2emt, child3emt);
535 }
536
537 @Test
538 public void testXPathFollowingSiblingNode() {
539 checkXPath("following-sibling::node()", child1emt, null, maintext2, child2emt, child3emt);
540 }
541
542 @Test
543 public void testXPathNamespaces() {
544 checkXPath("namespace::*", child3emt, null, child3nsa, Namespace.NO_NAMESPACE, child3nsb, Namespace.XML_NAMESPACE);
545 }
546
547 @Test
548 public void testXPathNamespacesForText() {
549 checkXPath("namespace::*", maintext1, null);
550 }
551
552
553 @Test
554 public void testXPathParent() {
555 checkXPath("parent::*", child3emt, null, main);
556 }
557
558 @Test
559 public void testXPathParentNode() {
560 checkXPath("parent::node()", child3emt, null, main);
561 }
562
563 @Test
564 public void testXPathPreceding() {
565 checkXPath("preceding::*", child2emt, null, child1emt);
566 }
567
568 @Test
569 public void testXPathPrecedingNode() {
570 checkXPath("preceding::node()", child2emt, null, doccomment, docpi,
571 maincomment, mainpi, maintext1, child1emt, child1text, maintext2);
572 }
573
574 @Test
575 public void testXPathPrecedingSibling() {
576 checkXPath("preceding-sibling::*", child3emt, null, child1emt, child2emt);
577 }
578
579 @Test
580 public void testXPathPrecedingSiblingNode() {
581 checkXPath("preceding-sibling::node()", child3emt, null, maincomment,
582 mainpi, maintext1, child1emt, maintext2, child2emt);
583 }
584
585 @Test
586 public void testXPathSelf() {
587 checkXPath("self::*", child3emt, null, child3emt);
588 }
589
590
591
592
593 /* *******************************
594 * Negative TestCases
595 * ******************************* */
596
597 @Test
598 public void testNegativeBrokenPath() {
599 try {
600 XPath.newInstance("//badaxis::dummy");
601 fail("Expected a JDOMException");
602 } catch (JDOMException jde) {
603 // good
604 } catch (Exception e) {
605 e.printStackTrace();
606 fail("Expected a JDOMException but got " + e.getClass());
607 }
608
609 }
610
611 @Test
612 public void testNegativeBrokenExpression() {
613 final String path = "//node()[string() = $novar]";
614 XPath xp = null;
615 try {
616 xp = XPath.newInstance(path);
617 } catch (Exception e) {
618 e.printStackTrace();
619 fail("Not expecting an exception!");
620 }
621 assertEquals(xp.getXPath(), path);
622 try {
623 // we have not declared a value for $novar, so, expect a failure.
624 xp.selectSingleNode(doc);
625 fail("Expected a JDOMException");
626 } catch (JDOMException jde) {
627 //System.out.println(jde.getMessage());
628 // good
629 } catch (Exception e) {
630 e.printStackTrace();
631 fail("Expected a JDOMException but got " + e.getClass());
632 }
633
634 try {
635 // we have not declared a value for $novar, so, expect a failure.
636 xp.selectNodes(doc);
637 fail("Expected a JDOMException");
638 } catch (JDOMException jde) {
639 //System.out.println(jde.getMessage());
640 // good
641 } catch (Exception e) {
642 e.printStackTrace();
643 fail("Expected a JDOMException but got " + e.getClass());
644 }
645
646 try {
647 // we have not declared a value for $novar, so, expect a failure.
648 xp.valueOf(doc);
649 fail("Expected a JDOMException");
650 } catch (JDOMException jde) {
651 //System.out.println(jde.getMessage());
652 // good
653 } catch (Exception e) {
654 e.printStackTrace();
655 fail("Expected a JDOMException but got " + e.getClass());
656 }
657
658 try {
659 // we have not declared a value for $novar, so, expect a failure.
660 xp.numberValueOf(doc);
661 fail("Expected a JDOMException");
662 } catch (JDOMException jde) {
663 //System.out.println(jde.getMessage());
664 // good
665 } catch (Exception e) {
666 e.printStackTrace();
667 fail("Expected a JDOMException but got " + e.getClass());
668 }
669
670 }
671
672 }
0 /*--
1
2 Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions, and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions, and the disclaimer that follows
14 these conditions in the documentation and/or other materials
15 provided with the distribution.
16
17 3. The name "JDOM" must not be used to endorse or promote products
18 derived from this software without prior written permission. For
19 written permission, please contact <request_AT_jdom_DOT_org>.
20
21 4. Products derived from this software may not be called "JDOM", nor
22 may "JDOM" appear in their name, without prior written permission
23 from the JDOM Project Management <request_AT_jdom_DOT_org>.
24
25 In addition, we request (but do not require) that you include in the
26 end-user documentation provided with the redistribution and/or in the
27 software itself an acknowledgement equivalent to the following:
28 "This product includes software developed by the
29 JDOM Project (http://www.jdom.org/)."
30 Alternatively, the acknowledgment may be graphical using the logos
31 available at http://www.jdom.org/images/logos.
32
33 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
37 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 SUCH DAMAGE.
45
46 This software consists of voluntary contributions made by many
47 individuals on behalf of the JDOM Project and was originally
48 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
49 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
50 on the JDOM Project, please see <http://www.jdom.org/>.
51
52 */
53
54 package org.jdom.test.cases.xpath;
55
56 import static org.jdom.test.util.UnitTestUtil.checkException;
57 import static org.jdom.test.util.UnitTestUtil.failNoException;
58 import static org.junit.Assert.assertEquals;
59 import static org.junit.Assert.assertFalse;
60 import static org.junit.Assert.assertTrue;
61 import static org.junit.Assert.fail;
62
63 import java.util.ArrayList;
64 import java.util.Collection;
65 import java.util.Collections;
66 import java.util.HashMap;
67 import java.util.HashSet;
68 import java.util.Iterator;
69 import java.util.List;
70 import java.util.Map;
71
72 import org.junit.Test;
73
74 import org.jdom.Attribute;
75 import org.jdom.CDATA;
76 import org.jdom.Comment;
77 import org.jdom.Document;
78 import org.jdom.Element;
79 import org.jdom.EntityRef;
80 import org.jdom.JDOMException;
81 import org.jdom.Namespace;
82 import org.jdom.NamespaceAware;
83 import org.jdom.ProcessingInstruction;
84 import org.jdom.Text;
85 import org.jdom.filter2.Filter;
86 import org.jdom.filter2.Filters;
87 import org.jdom.test.util.UnitTestUtil;
88 import org.jdom.xpath.XPathBuilder;
89 import org.jdom.xpath.XPathDiagnostic;
90 import org.jdom.xpath.XPathExpression;
91 import org.jdom.xpath.XPathFactory;
92
93 @SuppressWarnings({"javadoc"})
94 public abstract class AbstractTestXPathCompiled {
95
96 protected final Document doc = new Document();
97
98 protected final Comment doccomment = new Comment("doc comment");
99 protected final ProcessingInstruction docpi = new ProcessingInstruction("jdomtest", "doc");
100
101 protected final Element main = new Element("main");
102 protected final Attribute mainatt = new Attribute("atta", "vala");
103 protected final Comment maincomment = new Comment("main comment");
104 protected final ProcessingInstruction mainpi = new ProcessingInstruction("jdomtest", "pi data");
105 protected final Text maintext1 = new Text(" space1 ");
106 protected final Element child1emt = new Element("child");
107 protected final Text child1text = new Text("child1text");
108 protected final Text maintext2 = new Text(" space2 ");
109 protected final Element child2emt = new Element("child");
110
111 protected final Namespace child3nsa = Namespace.getNamespace("c3nsa", "jdom:c3nsa");
112 protected final Namespace child3nsb = Namespace.getNamespace("c3nsb", "jdom:c3nsb");
113 protected final Element child3emt = new Element("child", child3nsa);
114 protected final Attribute child3attint = new Attribute("intatt", "-123", child3nsb);
115 protected final Attribute child3attdoub = new Attribute("doubatt", "-123.45", child3nsb);
116 protected final Text child3txt = new Text("c3text");
117
118 protected final String mainvalue = " space1 child1text space2 c3text";
119 protected final boolean teststring;
120
121 public AbstractTestXPathCompiled(boolean teststring) {
122 this.teststring = teststring;
123 doc.addContent(doccomment);
124 doc.addContent(docpi);
125 doc.addContent(main);
126 main.setAttribute(mainatt);
127 main.addContent(maincomment);
128 main.addContent(mainpi);
129 main.addContent(maintext1);
130 child1emt.addContent(child1text);
131 main.addContent(child1emt);
132 main.addContent(maintext2);
133 main.addContent(child2emt);
134 child3emt.setAttribute(child3attint);
135 child3emt.setAttribute(child3attdoub);
136 child3emt.addContent(child3txt);
137 main.addContent(child3emt);
138 }
139
140 /**
141 * Create an instance of an XPath.
142 * Override this method to create the type of XPath instance we want to test.
143 * The method should add the supplied Namspace keys, and set the given variables
144 * on the XPath.
145 * @param path
146 * @param variables
147 * @param namespaces
148 * @return
149 * @throws JDOMException
150 */
151 abstract XPathFactory getFactory();
152
153 protected <T> XPathExpression<T> setupXPath(Filter<T> filter, String path, Map<String, Object> variables, Object context, Namespace... namespaces) {
154
155 XPathBuilder<T> xpath = new XPathBuilder<T>(path, filter);
156
157 assertFalse(xpath.equals(null));
158 assertFalse(xpath.equals(new Object()));
159 UnitTestUtil.checkEquals(xpath, xpath);
160
161 assertEquals("getXPath()", path, xpath.getExpression());
162
163
164 if (variables != null) {
165 for (Map.Entry<String, Object> me : variables.entrySet()) {
166 xpath.setVariable(me.getKey(), me.getValue());
167 }
168 }
169 if (context instanceof NamespaceAware) {
170 xpath.setNamespaces(((NamespaceAware)context).getNamespacesInScope());
171 }
172 for (Namespace n : namespaces) {
173 xpath.setNamespace(n);
174 }
175
176 return xpath.compileWith(getFactory());
177
178 }
179
180 private static final void checkDiagnostic(XPathExpression<?> xpc, Object context, List<?> result, XPathDiagnostic<?> diag) {
181 assertTrue(xpc == diag.getXPathExpression());
182 assertTrue(context == diag.getContext());
183
184 assertTrue(null != diag.toString());
185
186 assertFalse(diag.isFirstOnly());
187
188 final List<?> dresult = diag.getResult();
189 final List<?> draw = diag.getRawResults();
190 final List<?> dfilt = diag.getFilteredResults();
191
192 assertTrue(dresult.size() == result.size());
193
194 for (int i = 0; i < result.size(); i++) {
195 assertEquals(dresult.get(i), result.get(i));
196 }
197 assertTrue(dresult.size() + dfilt.size() == draw.size());
198
199 int r = 0;
200 int f = 0;
201 for (int i = 0; i < draw.size(); i++) {
202 if (r < dresult.size() && dresult.get(r) == draw.get(i)) {
203 r++;
204 } else if (f < dfilt.size() && dfilt.get(f)== draw.get(i)) {
205 f++;
206 } else {
207 fail (draw.get(i) + " is neither a result nor a filtered (or is in the wrong place)");
208 }
209 }
210
211 }
212
213 /**
214 * A mechanism for exercising the XPath system.
215 * @param xpath The xpath to run.
216 * @param context The context on which to run the XPath
217 * @param string What we expect the 'xpath' string value of the result to be (or null to skip test).
218 * @param number What we expect the xpath to resolve the result to be as an xpath 'Number' (or null to skip test);
219 * @param expect The nodes we expect from the XPath selectNodes query
220 */
221 protected static void checkXPath(XPathExpression<?> xpath, Object context, Object...expect) {
222
223 // Check the selectNodes operation.
224 List<?> result = xpath.evaluate(context);
225 if (result == null) {
226 fail ("Got a null result from selectNodes()");
227 }
228 checkDiagnostic(xpath, context, result, xpath.diagnose(context, false));
229
230 boolean allns = true;
231 boolean allatts = true;
232 for (Object o : expect) {
233 if (!(o instanceof Namespace)) {
234 allns = false;
235 if (!allatts) {
236 break;
237 }
238 }
239 if (!(o instanceof Attribute)) {
240 allatts = false;
241 if (!allns) {
242 break;
243 }
244 }
245 }
246
247 if (allns && expect.length > 0) {
248 // we expect only Namespace results.
249 // we use different rules....
250 // for a start, we don't check on order.
251 // also, if we expect the NO_NAMESPACE, we don't complain if it is
252 // not returned.
253 int expectsize = expect.length;
254 for (Object nso : expect) {
255 Namespace ns = (Namespace)nso;
256 if (ns == Namespace.NO_NAMESPACE) {
257 boolean gotit = false;
258 for (Object o : result) {
259 if (o == ns) {
260 // got it...
261 gotit = true;
262 break;
263 }
264 }
265 if (!gotit) {
266 expectsize--;
267 }
268 } else {
269 boolean gotit = false;
270 for (Object o : result) {
271 if (o == ns) {
272 gotit = true;
273 break;
274 }
275 }
276 if (!gotit) {
277 fail("Expected to have item " + ns + " returned, but it was not");
278 }
279 }
280 }
281 if (expectsize != result.size()) {
282 fail ("We expected " + expectsize + " Namespace results. We got " + result.size());
283 }
284 return;
285 }
286
287 if (allatts && expect.length > 0) {
288 // we expect only Attribute results.
289 // we use different rules....
290 // for a start, we don't check on order.
291 // this really suxks, because it is only to satisfy a bug in Jaxen.
292 int expectsize = expect.length;
293 for (Object atto : expect) {
294 Attribute att = (Attribute)atto;
295 boolean gotit = false;
296 for (Object o : result) {
297 if (o == att) {
298 gotit = true;
299 break;
300 }
301 }
302 if (!gotit) {
303 fail("Expected to have item " + att + " returned, but it was not. Instead we got " + result.toString());
304 }
305 }
306 if (expectsize != result.size()) {
307 fail ("We expected " + expectsize + " Attribute results. We got " + result.size());
308 }
309 return;
310 }
311
312 String sze = result.size() == expect.length ? "" :
313 (" Also Different Sizes: expect=" + expect.length + " actual=" + result.size());
314 int pos = 0;
315 for (Object o : result) {
316 if (pos >= expect.length) {
317 fail ("Results contained additional content at position " +
318 pos + " for xpath '" + xpath + "': " + o + sze);
319 }
320 if (o != expect[pos]) {
321 assertEquals("Failed result at position " + pos +
322 " for xpath '" + xpath + "'." + sze, expect[pos], o);
323 }
324 pos++;
325 }
326 if (pos < expect.length) {
327 fail ("Results are missing " + (expect.length - pos) +
328 " content at position " + pos + " for xpath '" + xpath +
329 "'. First missing content is: " + expect[pos] + sze);
330 }
331
332 // Check the selectSingleNode operation.
333 Object o = xpath.evaluateFirst(context);
334 //checkDiagnostic(Collections.singletonList(o), xpath.diagnose(context, true));
335 if (expect.length == 0 && o != null) {
336 fail("Expected XPath.selectSingleNode() to return nothing, " +
337 "but it returned " + o + sze);
338 }
339 if (expect.length > 0 && o == null) {
340 fail("XPath.selectSingleNode() returned nothing, but it should " +
341 "have returned " + expect[0] + sze);
342 }
343 if (expect.length > 0 && o != expect[0]) {
344 assertEquals("XPath.selectSingleNode() was expected to return " +
345 expect[0] + "' but instead it returned '" + o + "'" + sze,
346 expect[0], o);
347 }
348
349 }
350
351 protected void checkXPath(String xpath, Object context, String value, Object...expect) {
352 checkXPath(setupXPath(Filters.fpassthrough(), xpath, null, context), context, expect);
353 if (teststring && value != null) {
354 String npath = "string(" + xpath + ")";
355 checkXPath(setupXPath(Filters.fstring(), npath, null, context), context, value);
356 }
357 }
358
359 private void checkComplexXPath(String xpath, Object context, Map<String, Object> variables,
360 Collection<Namespace> namespaces, String value, Number number, Object...expect) {
361 HashSet<Namespace> nset = new HashSet<Namespace>();
362 if (namespaces != null) {
363 nset.addAll(namespaces);
364 }
365 if (context instanceof NamespaceAware) {
366 nset.addAll(((NamespaceAware)context).getNamespacesInScope());
367 }
368
369 Namespace[] nsa = nset.toArray(new Namespace[0]);
370 checkXPath(setupXPath(Filters.fpassthrough(), xpath, variables, context, nsa), context, expect);
371 if (teststring && value != null) {
372 String npath = "string(" + xpath + ")";
373 checkXPath(setupXPath(Filters.fstring(), npath, variables, context, nsa), context, value);
374 }
375 if (teststring && number != null) {
376 String npath = "number(" + xpath + ")";
377 checkXPath(setupXPath(Filters.fdouble(), npath, variables, context, nsa), context, number);
378 }
379 }
380
381 // @Test
382 // public void testSerialization() {
383 // XPath xpath = setupXPath("//main", null);
384 // XPath xser = UnitTestUtil.deSerialize(xpath);
385 // assertTrue(xpath != xser);
386 // // TODO JaxenXPath has useless equals(). See issue #43
387 // // Additionally, all XPath deserialization is done on the default
388 // // factory... will never be equals() if the factory used to create
389 // // the xpath is different.
390 // // UnitTestUtil.checkEquals(xpath, xser);
391 // assertEquals(xpath.toString(), xser.toString());
392 // }
393
394 @Test
395 public void testNullQuery() {
396 try {
397 getFactory().compile(null, Filters.element());
398 fail("excpected NPE");
399 } catch (NullPointerException noe) {
400 // great
401 }
402 }
403
404 @Test
405 public void testNullFilter() {
406 try {
407 getFactory().compile("/", null);
408 fail("excpected NPE");
409 } catch (NullPointerException noe) {
410 // great
411 }
412 }
413
414 @Test
415 public void testNullNamespace() {
416 try {
417 getFactory().compile("/", Filters.element(), null, Namespace.NO_NAMESPACE, null, Namespace.XML_NAMESPACE);
418 fail("excpected NPE");
419 } catch (NullPointerException noe) {
420 // great
421 }
422 }
423
424 @Test
425 public void testNullNamespaceArray() {
426 Namespace[] nsa = null;
427 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), null, nsa);
428 assertEquals("", xp.getNamespace("").getURI());
429 }
430
431 @Test
432 public void testNullVariableName() {
433 try {
434 Map<String, Object> vars = new HashMap<String, Object>();
435 vars.put(null, "");
436 vars.put("a", "b");
437 getFactory().compile("/", Filters.element(), vars);
438 fail("excpected NPE");
439 } catch (NullPointerException noe) {
440 // great
441 }
442 }
443
444 @Test
445 public void testDuplicatePrefix() {
446 try {
447 Namespace nsa = Namespace.getNamespace("pfx", "one");
448 Namespace nsb = Namespace.getNamespace("pfx", "two");
449 getFactory().compile("/", Filters.element(), null, Namespace.NO_NAMESPACE, nsa, Namespace.XML_NAMESPACE, nsb);
450 fail("excpected IAE");
451 } catch (IllegalArgumentException noe) {
452 // great
453 }
454 }
455
456 @Test
457 public void testRedefineNO_PREFIX() {
458 try {
459 Namespace nsa = Namespace.getNamespace("pfx", "one");
460 Namespace nsb = Namespace.getNamespace("", "two");
461 getFactory().compile("/", Filters.element(), null, Namespace.NO_NAMESPACE, nsa, Namespace.XML_NAMESPACE, nsb);
462 fail("excpected IAE");
463 } catch (IllegalArgumentException noe) {
464 // great
465 }
466 }
467
468 @Test
469 public void testDoubleSupplyNS() {
470 // call the same thing twice.... this is not an error
471 Namespace nsa = Namespace.getNamespace("pfx", "one");
472 getFactory().compile("/", Filters.element(), null, Namespace.NO_NAMESPACE, nsa, Namespace.NO_NAMESPACE, nsa);
473 }
474
475 @Test
476 public void testRedeclareNoPrefixMessageDifferentToPrefix() {
477 // redeclare a namespace, and the defalt namespace. The Default versions should have a
478 // different message
479 Namespace nsa = Namespace.getNamespace("pfx", "one");
480 Namespace nsb = Namespace.getNamespace("pfx", "two");
481 Namespace nsd = Namespace.getNamespace("", "three");
482
483 String ma = null;
484 String mb = null;
485
486 try {
487 // cannot redeclare "" namespace prefix.
488 getFactory().compile("/", Filters.element(), null, Namespace.NO_NAMESPACE, nsd);
489 fail("excpected IAE");
490 } catch (IllegalArgumentException iae) {
491 ma = iae.getMessage();
492 }
493
494 try {
495 // cannot redeclare "pfx" namespace prefix.
496 getFactory().compile("/", Filters.element(), null, nsa, nsb);
497 fail("excpected IAE");
498 } catch (IllegalArgumentException iae) {
499 mb = iae.getMessage();
500 }
501
502 assertFalse(ma.equals(mb));
503 }
504
505 @Test
506 public void testDuplicateVariable() {
507 try {
508 Map<String,Object> vars = new HashMap<String, Object>();
509 vars.put("pfa:name", "dupa");
510 vars.put("pfb:name", "dupb");
511 Namespace nsa = Namespace.getNamespace("pfa", "ns");
512 Namespace nsb = Namespace.getNamespace("pfb", "ns");
513 getFactory().compile("/", Filters.element(), vars, Namespace.NO_NAMESPACE, nsa, Namespace.XML_NAMESPACE, nsb);
514 fail("excpected IAE");
515 } catch (IllegalArgumentException noe) {
516 // great
517 }
518 }
519
520 @Test
521 public void testBadVariablePrefix() {
522 try {
523 Map<String,Object> vars = new HashMap<String, Object>();
524 vars.put("pfa : name", "dupa");
525 vars.put("pfb:name", "dupb");
526 Namespace nsa = Namespace.getNamespace("pfa", "ns");
527 Namespace nsb = Namespace.getNamespace("pfb", "ns");
528 getFactory().compile("/", Filters.element(), vars, Namespace.NO_NAMESPACE, nsa, Namespace.XML_NAMESPACE, nsb);
529 fail("excpected IAE");
530 } catch (IllegalArgumentException noe) {
531 // great
532 }
533 }
534
535 @Test
536 public void testBadVariableName1() {
537 try {
538 Map<String,Object> vars = new HashMap<String, Object>();
539 vars.put("pfa:123", "dupa");
540 vars.put("pfb:name", "dupb");
541 Namespace nsa = Namespace.getNamespace("pfa", "ns");
542 Namespace nsb = Namespace.getNamespace("pfb", "ns");
543 getFactory().compile("/", Filters.element(), vars, Namespace.NO_NAMESPACE, nsa, Namespace.XML_NAMESPACE, nsb);
544 fail("excpected IAE");
545 } catch (IllegalArgumentException noe) {
546 // great
547 }
548 }
549
550 @Test
551 public void testBadVariableName2() {
552 try {
553 Map<String,Object> vars = new HashMap<String, Object>();
554 vars.put("pfa: ", "dupa");
555 vars.put("pfb:name", "dupb");
556 Namespace nsa = Namespace.getNamespace("pfa", "ns");
557 Namespace nsb = Namespace.getNamespace("pfb", "ns");
558 getFactory().compile("/", Filters.element(), vars, Namespace.NO_NAMESPACE, nsa, Namespace.XML_NAMESPACE, nsb);
559 fail("excpected IAE");
560 } catch (IllegalArgumentException noe) {
561 // great
562 }
563 }
564
565 @Test
566 public void testBadVariableName3() {
567 XPathExpression<Element> xpe = getFactory().compile("/", Filters.element());
568 try {
569 xpe.getVariable(null);
570 failNoException(NullPointerException.class);
571 } catch (Exception e) {
572 checkException(NullPointerException.class, e);
573 }
574 try {
575 xpe.setVariable(null, "hi");
576 failNoException(NullPointerException.class);
577 } catch (Exception e) {
578 checkException(NullPointerException.class, e);
579 }
580 }
581
582 @Test
583 public void testBadVariableNamespace() {
584 try {
585 Map<String,Object> vars = new HashMap<String, Object>();
586 // pfd is not defined.
587 vars.put("pfd:name", "dupa");
588 vars.put("pfb:name", "dupb");
589 Namespace nsa = Namespace.getNamespace("pfa", "ns");
590 Namespace nsb = Namespace.getNamespace("pfb", "ns");
591 getFactory().compile("/", Filters.element(), vars, Namespace.NO_NAMESPACE, nsa, Namespace.XML_NAMESPACE, nsb);
592 fail("excpected IAE");
593 } catch (IllegalArgumentException noe) {
594 // great
595 }
596 }
597
598 @Test
599 public void testGetNamespace1() {
600 assertEquals("", getFactory().compile("/").getNamespace("").getURI());
601 }
602
603 @Test
604 public void testGetNamespace2() {
605 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), null, Namespace.getNamespace("x", "y"));
606 assertEquals("y", xp.getNamespace("x").getURI());
607 }
608
609 @Test
610 public void testGetNamespaces() {
611 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), null, Namespace.getNamespace("x", "y"));
612 Namespace[] nsa = xp.getNamespaces();
613 assertEquals("", nsa[0].getURI());
614 assertEquals("y", nsa[1].getURI());
615 }
616
617 @Test
618 public void testGetNamespace3() {
619 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), null, Namespace.getNamespace("x", "y"));
620 try {
621 xp.getNamespace("hello");
622 fail("expected IAE");
623 } catch (IllegalArgumentException ise) {
624 // good.
625 }
626 }
627
628 @Test
629 public void testGetVariable1() {
630 Map<String,Object> vars = new HashMap<String, Object>();
631 vars.put("one", 1);
632 vars.put("nsa:one", 2);
633 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), vars, Namespace.getNamespace("nsa", "zzz"));
634
635 assertEquals(1, xp.getVariable("one"));
636 assertEquals(1, xp.getVariable("one", Namespace.NO_NAMESPACE));
637 assertEquals(2, xp.getVariable("nsa:one"));
638 assertEquals(2, xp.getVariable("one", Namespace.getNamespace("zzz")));
639
640 }
641
642 @Test
643 public void testGetVariable2() {
644 Map<String,Object> vars = new HashMap<String, Object>();
645 vars.put("one", 1);
646 vars.put("three", 3);
647 vars.put("nsa:one", 2);
648 vars.put("nsa:two", 2);
649 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), vars, Namespace.getNamespace("nsa", "zzz"));
650
651 try {
652 xp.getVariable("two");
653 fail("expected IAE");
654 } catch (IllegalArgumentException ise) {
655 // good.
656 }
657
658 try {
659 xp.getVariable("two", Namespace.NO_NAMESPACE);
660 fail("expected IAE");
661 } catch (IllegalArgumentException ise) {
662 // good.
663 }
664
665 try {
666 xp.getVariable("nsa:three");
667 fail("expected IAE");
668 } catch (IllegalArgumentException ise) {
669 // good.
670 }
671
672 try {
673 xp.getVariable("three", Namespace.getNamespace("zzz"));
674 fail("expected IAE");
675 } catch (IllegalArgumentException ise) {
676 // good.
677 }
678 }
679
680 @Test
681 public void testGetNullVariableValue() {
682 Map<String,Object> vars = new HashMap<String, Object>();
683 vars.put("one", 1);
684 vars.put("nsa:one", null);
685 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), vars, Namespace.getNamespace("nsa", "zzz"));
686
687 assertEquals(1, xp.getVariable("one"));
688 assertEquals(1, xp.getVariable("one", null));
689 assertEquals(1, xp.getVariable("one", Namespace.NO_NAMESPACE));
690 assertEquals(null, xp.getVariable("nsa:one"));
691 assertEquals(null, xp.getVariable("one", Namespace.getNamespace("zzz")));
692 }
693
694 @Test
695 public void testSetNullVariableValue() {
696 Map<String,Object> vars = new HashMap<String, Object>();
697 vars.put("one", 1);
698 vars.put("nsa:one", 2);
699 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), vars, Namespace.getNamespace("nsa", "zzz"));
700
701 assertEquals(1, xp.getVariable("one"));
702 assertEquals(1, xp.getVariable("one", Namespace.NO_NAMESPACE));
703 assertEquals(2, xp.getVariable("nsa:one"));
704 assertEquals(2, xp.getVariable("one", Namespace.getNamespace("zzz")));
705
706 assertEquals(2, xp.setVariable("one", Namespace.getNamespace("zzz"), null));
707 assertEquals(1, xp.getVariable("one"));
708 assertEquals(1, xp.getVariable("one", Namespace.NO_NAMESPACE));
709 assertEquals(null, xp.getVariable("one", Namespace.getNamespace("zzz")));
710 assertEquals(null, xp.getVariable("nsa:one"));
711
712 assertEquals(null, xp.setVariable("nsa:one", 3));
713 assertEquals(1, xp.getVariable("one"));
714 assertEquals(1, xp.getVariable("one", Namespace.NO_NAMESPACE));
715 assertEquals(3, xp.getVariable("one", Namespace.getNamespace("zzz")));
716 assertEquals(3, xp.getVariable("nsa:one"));
717 }
718
719 @Test
720 public void testGetFilter() {
721 Filter<Element> filter = Filters.element();
722 XPathExpression<Element> xp = getFactory().compile("/", filter);
723 assertTrue(filter == xp.getFilter());
724 }
725
726 @Test
727 public void testToString() {
728 Map<String,Object> vars = new HashMap<String, Object>();
729 vars.put("one", 1);
730 vars.put("nsa:one", 2);
731 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), vars, Namespace.getNamespace("nsa", "zzz"));
732 assertTrue(null != xp.toString());
733
734 }
735
736 @Test
737 public void testClone() {
738 Map<String,Object> vars = new HashMap<String, Object>();
739 vars.put("one", 1);
740 vars.put("nsa:one", 2);
741 XPathExpression<Element> xp = getFactory().compile("/", Filters.element(), vars, Namespace.getNamespace("nsa", "zzz"));
742 XPathExpression<Element> xq = xp.clone();
743 assertTrue(xp != xq);
744 assertTrue(xp.getExpression() == xq.getExpression());
745 assertTrue(xp.getVariable("one") == xq.getVariable("one"));
746 assertTrue(xp.getVariable("nsa:one") == xq.getVariable("one", Namespace.getNamespace("zzz")));
747 assertTrue(xq.getVariable("one", Namespace.NO_NAMESPACE) ==
748 xp.setVariable("one", "newval"));
749 assertEquals("newval", xp.getVariable("one"));
750 assertEquals(1, xq.getVariable("one"));
751
752 }
753
754 @Test
755 public void testCloneVariables() {
756 List<Element> lst = null;
757 HashMap<String,Object> vars = new HashMap<String,Object>();
758 vars.put("vns:vname", "1");
759 Namespace vns = Namespace.getNamespace("vns", "http://jdom.org/xpath_variable_namespace");
760 XPathExpression<Element> xpathhc = XPathFactory.instance().compile(
761 "/main/child[1]", Filters.element());
762 lst = xpathhc.evaluate(doc);
763 assertTrue(1 == lst.size());
764 assertTrue(child1emt == lst.get(0));
765
766 XPathExpression<Element> xpath = XPathFactory.instance().compile(
767 "/main/child[position() = $vns:vname]", Filters.element(), vars, vns);
768 lst = xpath.evaluate(doc);
769 assertTrue(1 == lst.size());
770 assertTrue(child1emt == lst.get(0));
771 xpath.setVariable("vns:vname", "2");
772 assertTrue("2" == xpath.getVariable("vname", vns));
773 lst = xpath.evaluate(doc);
774 assertTrue(1 == lst.size());
775 assertTrue(child2emt == lst.get(0));
776
777 XPathExpression<Element> cloned = xpath.clone();
778 lst = cloned.evaluate(doc);
779 assertTrue(1 == lst.size());
780 assertTrue(child2emt == lst.get(0));
781
782 cloned.setVariable("vns:vname", "1");
783 assertTrue("2" == xpath.getVariable("vname", vns));
784 assertTrue("1" == cloned.getVariable("vname", vns));
785 lst = cloned.evaluate(doc);
786 assertTrue(1 == lst.size());
787 assertTrue(child1emt == lst.get(0));
788 }
789
790 @Test
791 public void testSelectDocumentDoc() {
792 checkXPath("/", doc, mainvalue, doc);
793 }
794
795 @Test
796 public void testSelectDocumentMain() {
797 checkXPath("/", main, mainvalue, doc);
798 }
799
800 @Test
801 public void testSelectDocumentAttr() {
802 checkXPath("/", child3attint, mainvalue, doc);
803 }
804
805 @Test
806 public void testSelectDocumentPI() {
807 checkXPath("/", mainpi, mainvalue, doc);
808 }
809
810 @Test
811 public void testSelectDocumentText() {
812 checkXPath("/", child1text, mainvalue, doc);
813 }
814
815 @Test
816 public void testSelectMainByName() {
817 checkXPath("main", doc, mainvalue, main);
818 }
819
820 @Test
821 public void testSelectMainFromDoc() {
822 checkXPath("//main", doc, mainvalue, main);
823 }
824
825 @Test
826 public void testAncestorsFromRoot() {
827 checkXPath("ancestor::node()", doc, "");
828 }
829
830 @Test
831 public void testAncestorsFromMain() {
832 checkXPath("ancestor::node()", main, mainvalue, doc);
833 }
834
835 @Test
836 public void testAncestorsFromChild() {
837 checkXPath("ancestor::node()", child1emt, mainvalue, doc, main);
838 }
839
840 @Test
841 public void testAncestorOrSelfFromRoot() {
842 checkXPath("ancestor-or-self::node()", doc, mainvalue, doc);
843 }
844
845 @Test
846 public void testAncestorOrSelfFromMain() {
847 checkXPath("ancestor-or-self::node()", main, mainvalue, doc, main);
848 }
849
850 @Test
851 public void testAncestorOrSelfFromMainAttribute() {
852 checkXPath("ancestor-or-self::node()", mainatt, mainvalue, doc, main, mainatt);
853 }
854
855 @Test
856 public void testAncestorOrSelfFromNamespace() {
857 checkXPath("ancestor-or-self::node()", child3nsa, null, child3nsa);
858 }
859
860 @Test
861 public void testAncestorOrSelfFromChild() {
862 checkXPath("ancestor-or-self::node()", child1emt, mainvalue, doc, main, child1emt);
863 }
864
865
866 /* *************************************
867 * Boolean/Double/String tests.
868 * ************************************* */
869
870 @Test
871 public void getXPathDouble() {
872 checkXPath("count( //* )", doc, null, Double.valueOf(4));
873 }
874
875 @Test
876 public void getXPathString() {
877 checkXPath("string( . )", child1emt, null, child1text.getText());
878 }
879
880 @Test
881 public void getXPathBoolean() {
882 checkXPath("count (//*) > 1", child1emt, null, Boolean.TRUE);
883 }
884
885 /* *************************************
886 * Element tests.
887 * ************************************* */
888
889 @Test
890 public void getXPathElementName() {
891 checkXPath("//*[name() = 'main']", doc, null, main);
892 }
893
894 @Test
895 public void getXPathElementText() {
896 checkXPath("//*[string() = 'child1text']", doc, null, child1emt);
897 }
898
899
900 /* *************************************
901 * Processing Instruction tests.
902 * ************************************* */
903
904 @Test
905 public void getXPathProcessingInstructionAll() {
906 checkXPath("//processing-instruction()", doc, null, docpi, mainpi);
907 }
908
909 @Test
910 public void getXPathProcessingInstructionByTarget() {
911 checkXPath("//processing-instruction()[name() = 'jdomtest']", doc, null, docpi, mainpi);
912 }
913
914 @Test
915 public void getXPathProcessingInstructionByData() {
916 checkXPath("//processing-instruction()[string() = 'doc']", doc, null, docpi);
917 }
918
919 /* *************************************
920 * Attribute tests.
921 * ************************************* */
922
923 @Test
924 public void getXPathAttributeAll() {
925 checkXPath("//@*", doc, null, mainatt, child3attint, child3attdoub);
926 }
927
928 @Test
929 public void getXPathAttributeByName() {
930 checkXPath("//@*[name() = 'atta']", doc, null, mainatt);
931 }
932
933 @Test
934 public void getXPathAttributeByValue() {
935 checkXPath("//@*[string() = '-123']", doc, null, child3attint);
936 }
937
938 /* *************************************
939 * XPath Variable tests.
940 * ************************************* */
941
942 @Test
943 public void testSetVariable() {
944 HashMap<String,Object> hm = new HashMap<String, Object>();
945 String attval = mainatt.getValue();
946 hm.put("valvar", attval);
947 checkComplexXPath("//@*[string() = $valvar]", doc, hm, null, attval, null, mainatt);
948 }
949
950 /* *************************************
951 * XPath namespace tests.
952 * ************************************* */
953 @Test
954 public void testAttributeNamespaceAsNumberToo() {
955 checkComplexXPath("//@c3nsb:intatt", child3emt, null, null,
956 "-123", Double.valueOf(-123), child3attint);
957 checkComplexXPath("//@c3nsb:doubatt", child3emt, null, null,
958 "-123.45", Double.valueOf(-123.45), child3attdoub);
959 }
960
961 @Test
962 public void testAddNamespaceNamespace() {
963 checkComplexXPath("//c3nsa:child", doc, null, Collections.singleton(child3nsa),
964 child3emt.getValue(), null, child3emt);
965 }
966
967 @Test
968 public void testGetALLNamespaces() {
969 //Namespace.NO_NAMESPACE is declared earlier in documentOrder.
970 // so it comes first.
971 // we do not specify which Namespace should be first....
972 checkXPath("//c3nsa:child/namespace::*", child3emt, null,
973 child3nsa, Namespace.NO_NAMESPACE, child3nsb, Namespace.XML_NAMESPACE);
974 }
975
976 @Test
977 // This fails the Jaxen Builder because the returned attributes are not in document order.
978 public void testAttributesNamespace() {
979 checkComplexXPath("//@*[namespace-uri() = 'jdom:c3nsb']", doc, null, null,
980 null, null /*"-123", Double.valueOf(-123)*/, child3emt.getAttributes().toArray());
981 }
982
983 @Test
984 public void testAttributeParent() {
985 checkXPath("..", mainatt, null, main);
986 }
987
988 @Test
989 public void testXPathDefaultNamespacesFromElement() {
990 // the significance here is that the c3nsb namespace should already be
991 // available because it is in scope on the 'context' element.
992 // so, there should be no need to re-declare it for the xpath.
993 checkComplexXPath("//@c3nsb:*[string() = '-123']", child3emt, null, null,
994 "-123", Double.valueOf(-123), child3attint);
995 }
996
997 @Test
998 public void testXPathDefaultNamespacesFromAttribute() {
999 // the significance here is that the c3nsb namespace should already be
1000 // available because it is in scope on the 'context' element.
1001 // so, there should be no need to re-declare it for the xpath.
1002 checkComplexXPath("//@c3nsb:*[string() = '-123']", child3attdoub, null, null,
1003 "-123", Double.valueOf(-123), child3attint);
1004 }
1005
1006 @Test
1007 public void testXPathDefaultNamespacesFromText() {
1008 // the significance here is that the c3nsb namespace should already be
1009 // available because it is in scope on the 'context' element.
1010 // so, there should be no need to re-declare it for the xpath.
1011 checkComplexXPath("//@c3nsb:*[string() = '-123']", child3txt, null, null,
1012 "-123", Double.valueOf(-123), child3attint);
1013 }
1014
1015 /* *******************************
1016 * Axis TestCases
1017 * ******************************* */
1018
1019 @Test
1020 public void testXPathAncestor() {
1021 checkXPath("ancestor::*", child3txt, null, main, child3emt);
1022 }
1023
1024 @Test
1025 public void testXPathAncestorOrSelf() {
1026 checkXPath("ancestor-or-self::*", child3txt, null, main, child3emt);
1027 }
1028
1029 @Test
1030 public void testXPathAncestorNodes() {
1031 checkXPath("ancestor::node()", child3txt, null, doc, main, child3emt);
1032 }
1033
1034 @Test
1035 public void testXPathAncestorOrSelfNodes() {
1036 checkXPath("ancestor-or-self::node()", child3txt, null, doc, main, child3emt, child3txt);
1037 }
1038
1039 @Test
1040 public void testXPathAncestorOrSelfNodesFromAtt() {
1041 checkXPath("ancestor-or-self::node()", child3attint, null, doc, main, child3emt, child3attint);
1042 }
1043
1044 @Test
1045 public void testXPathAttributes() {
1046 checkXPath("attribute::*", child3emt, null, child3attint, child3attdoub);
1047 }
1048
1049 @Test
1050 public void testXPathChild() {
1051 checkXPath("child::*", main, null, child1emt, child2emt, child3emt);
1052 }
1053
1054 @Test
1055 public void testXPathDescendant() {
1056 checkXPath("descendant::*", doc, null, main, child1emt, child2emt, child3emt);
1057 }
1058
1059 @Test
1060 public void testXPathDescendantNode() {
1061 checkXPath("descendant::node()", doc, null, doccomment, docpi, main,
1062 maincomment, mainpi, maintext1, child1emt, child1text,
1063 maintext2, child2emt, child3emt, child3txt);
1064 }
1065
1066 @Test
1067 public void testXPathDescendantOrSelf() {
1068 checkXPath("descendant-or-self::*", doc, null, main, child1emt, child2emt, child3emt);
1069 }
1070
1071 @Test
1072 public void testXPathFollowing() {
1073 checkXPath("following::*", child2emt, null, child3emt);
1074 }
1075
1076 @Test
1077 public void testXPathFollowingNode() {
1078 checkXPath("following::node()", child2emt, null, child3emt, child3txt);
1079 }
1080
1081 @Test
1082 public void testXPathFollowingSibling() {
1083 checkXPath("following-sibling::*", child1emt, null, child2emt, child3emt);
1084 }
1085
1086 @Test
1087 public void testXPathFollowingSiblingNode() {
1088 checkXPath("following-sibling::node()", child1emt, null, maintext2, child2emt, child3emt);
1089 }
1090
1091 @Test
1092 public void testXPathNamespaces() {
1093 checkXPath("namespace::*", child3emt, null, child3nsa, Namespace.NO_NAMESPACE, child3nsb, Namespace.XML_NAMESPACE);
1094 }
1095
1096 @Test
1097 public void testXPathNamespacesForText() {
1098 checkXPath("namespace::*", maintext1, null);
1099 }
1100
1101
1102 @Test
1103 public void testXPathParent() {
1104 checkXPath("parent::*", child3emt, null, main);
1105 }
1106
1107 @Test
1108 public void testXPathParentNode() {
1109 checkXPath("parent::node()", child3emt, null, main);
1110 }
1111
1112 @Test
1113 public void testXPathPreceding() {
1114 checkXPath("preceding::*", child2emt, null, child1emt);
1115 }
1116
1117 @Test
1118 public void testXPathPrecedingNode() {
1119 checkXPath("preceding::node()", child2emt, null, doccomment, docpi,
1120 maincomment, mainpi, maintext1, child1emt, child1text, maintext2);
1121 }
1122
1123 @Test
1124 public void testXPathPrecedingSibling() {
1125 checkXPath("preceding-sibling::*", child3emt, null, child1emt, child2emt);
1126 }
1127
1128 @Test
1129 public void testXPathPrecedingSiblingNode() {
1130 checkXPath("preceding-sibling::node()", child3emt, null, maincomment,
1131 mainpi, maintext1, child1emt, maintext2, child2emt);
1132 }
1133
1134 @Test
1135 public void testXPathSelf() {
1136 checkXPath("self::*", child3emt, null, child3emt);
1137 }
1138
1139 @Test
1140 public void testXPathOR() {
1141 checkXPath("/main/node()[1] | /main/@*", child3emt, null, mainatt, maincomment);
1142 }
1143
1144 @Test
1145 public void testXPathNoMatch() {
1146 checkXPath("//dummy", doc, null);
1147 }
1148
1149
1150 /* *******************************
1151 * Negative TestCases
1152 * ******************************* */
1153
1154 @Test
1155 public void testNegativeBrokenPath() {
1156 try {
1157 XPathFactory.instance().compile("//badaxis::dummy");
1158 fail("Expected a JDOMException");
1159 } catch (IllegalArgumentException jde) {
1160 // good
1161 } catch (Exception e) {
1162 e.printStackTrace();
1163 fail("Expected a JDOMException but got " + e.getClass());
1164 }
1165
1166 }
1167
1168 @Test
1169 public void testNegativeBrokenExpression() {
1170 final String path = "//node()[string() = $novar]";
1171 XPathExpression<Object> xp = XPathFactory.instance().compile(path);
1172 assertEquals(xp.getExpression(), path);
1173 try {
1174 // we have not declared a value for $novar, so, expect a failure.
1175 xp.evaluateFirst(doc);
1176 fail("Expected a JDOMException");
1177 } catch (IllegalStateException jde) {
1178 //System.out.println(jde.getMessage());
1179 // good
1180 } catch (Exception e) {
1181 e.printStackTrace();
1182 fail("Expected a JDOMException but got " + e.getClass());
1183 }
1184
1185 try {
1186 // we have not declared a value for $novar, so, expect a failure.
1187 xp.evaluate(doc);
1188 fail("Expected a JDOMException");
1189 } catch (IllegalStateException jde) {
1190 //System.out.println(jde.getMessage());
1191 // good
1192 } catch (Exception e) {
1193 e.printStackTrace();
1194 fail("Expected a JDOMException but got " + e.getClass());
1195 }
1196
1197 try {
1198 // we have not declared a value for $novar, so, expect a failure.
1199 xp.diagnose(doc, true);
1200 fail("Expected a JDOMException");
1201 } catch (IllegalStateException jde) {
1202 //System.out.println(jde.getMessage());
1203 // good
1204 } catch (Exception e) {
1205 e.printStackTrace();
1206 fail("Expected a JDOMException but got " + e.getClass());
1207 }
1208
1209 }
1210
1211 @Test
1212 public void testXPathFilteredDiagnostic() {
1213 final XPathExpression<Element> xpe =
1214 setupXPath(Filters.element("child"), "//*", null, null);
1215 final ArrayList<Element> res = new ArrayList<Element>();
1216 res.add(child1emt);
1217 res.add(child2emt);
1218 // child3 is not in the NO_NAMESPACE ... res.add(child3emt);
1219 final XPathDiagnostic<Element> diag = xpe.diagnose(doc, false);
1220 checkDiagnostic(xpe, doc, res, diag);
1221 final XPathDiagnostic<Element> diagz = xpe.diagnose(doc, true);
1222 // size is zero because first result ('main') does not pass the filter.
1223 assertTrue(diagz.getResult().size() == 0);
1224 assertTrue(diagz.toString() != null);
1225
1226 final XPathExpression<Element> xpf =
1227 setupXPath(Filters.element("main"), "//*", null, null);
1228 final XPathDiagnostic<Element> diagf = xpf.diagnose(doc, false);
1229
1230 assertTrue(main == diagf.getResult().get(0));
1231 assertTrue(diagf.getFilteredResults().size() == 3);
1232 assertTrue(child1emt == diagf.getFilteredResults().get(0));
1233 assertTrue(child2emt == diagf.getFilteredResults().get(1));
1234 assertTrue(child3emt == diagf.getFilteredResults().get(2));
1235
1236 final XPathDiagnostic<Element> diagg = xpf.diagnose(doc, true);
1237
1238 assertTrue(main == diagg.getResult().get(0));
1239 assertTrue(diagg.getFilteredResults().size() == 0);
1240 }
1241
1242 private void checkDetached(final NamespaceAware nsa) {
1243 checkXPath(".", nsa, null, nsa);
1244 }
1245
1246 @Test
1247 public void testDetachedAttribute() {
1248 // non-Element content...
1249 checkDetached(new Attribute("detached", "value"));
1250 }
1251
1252 @Test
1253 public void testDetachedText() {
1254 checkDetached(new Text("detached"));
1255 }
1256
1257 @Test
1258 public void testDetachedCDATA() {
1259 checkDetached(new CDATA("detached"));
1260 }
1261
1262 @Test
1263 public void testDetachedProcessingInstruction() {
1264 checkDetached(new ProcessingInstruction("detached"));
1265 }
1266
1267 @Test
1268 public void testDetachedEntityRef() {
1269 checkDetached(new EntityRef("detached"));
1270 }
1271
1272 @Test
1273 public void testDetachedComment() {
1274 checkDetached(new Comment("detached"));
1275
1276 }
1277
1278 @Test
1279 public void testDetachedElement() {
1280 checkDetached(new Element("detached"));
1281
1282 }
1283
1284 @Test
1285 public void testDeepNesting() {
1286 Element root = new Element("root");
1287 Document docx = new Document(root);
1288 Element p = root;
1289 for (int d = 15; d >= 0; d--) {
1290 for (int i = 0; i < 64; i++) {
1291 p.addContent(new Element("child"));
1292 }
1293 p = (Element)p.getContent(0);
1294 }
1295 XPathExpression<Element> xpe = setupXPath(Filters.element(), "//child", null, docx);
1296 final int sz = xpe.evaluate(docx).size();
1297 assertEquals("Expected ", 16*64, sz);
1298 }
1299
1300
1301 @Test
1302 public void testDeepBackNesting() {
1303 // same as DeepNesting but the chold is attached to the last parent sibling instead of the first
1304 Element root = new Element("root");
1305 Document docx = new Document(root);
1306 ArrayList<Element> al = new ArrayList<Element>();
1307 Element p = root;
1308 for (int d = 15; d >= 0; d--) {
1309 for (int i = 0; i < 64; i++) {
1310 Element k = new Element("child");
1311 k.addContent(new Text(""));
1312 k.addContent(new Text(""));
1313 al.add(k);
1314 p.addContent(k);
1315 }
1316 p = (Element)p.getContent(p.getContentSize() - 1);
1317 }
1318 XPathExpression<Element> xpe = setupXPath(Filters.element(), "//child", null, docx);
1319 List<Element> res = xpe.evaluate(docx);
1320 assertEquals("Expected ", al.size(), res.size());
1321 Iterator<Element> ita = res.iterator();
1322 Iterator<Element> itb = al.iterator();
1323 while (ita.hasNext() && itb.hasNext()) {
1324 final Element a = ita.next();
1325 final Element b = itb.next();
1326 assertTrue(a == b);
1327 }
1328 assertFalse(ita.hasNext());
1329 assertFalse(itb.hasNext());
1330 }
1331
1332 }
0 package org.jdom.test.cases.xpath;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.fail;
4
5 import java.io.IOException;
6 import java.util.ArrayList;
7 import java.util.Iterator;
8
9 import org.junit.Test;
10
11 import org.jdom.Attribute;
12 import org.jdom.CDATA;
13 import org.jdom.Comment;
14 import org.jdom.Content;
15 import org.jdom.Document;
16 import org.jdom.Element;
17 import org.jdom.EntityRef;
18 import org.jdom.JDOMException;
19 import org.jdom.NamespaceAware;
20 import org.jdom.ProcessingInstruction;
21 import org.jdom.Text;
22 import org.jdom.input.SAXBuilder;
23 import org.jdom.test.util.FidoFetch;
24 import org.jdom.test.util.UnitTestUtil;
25 import org.jdom.xpath.XPathDiagnostic;
26 import org.jdom.xpath.XPathExpression;
27 import org.jdom.xpath.XPathFactory;
28 import org.jdom.xpath.XPathHelper;
29
30 @SuppressWarnings("javadoc")
31 public abstract class AbstractTestXPathHepler {
32
33 abstract XPathFactory getFactory();
34
35 @Test
36 public void testGetPathStringElement() {
37 Element emt = new Element("root");
38 assertEquals("/root", XPathHelper.getAbsolutePath(emt));
39 Element kid = new Element("kid");
40 assertEquals("/kid", XPathHelper.getAbsolutePath(kid));
41 emt.addContent(kid);
42 assertEquals("/root/kid", XPathHelper.getAbsolutePath(kid));
43 }
44
45 private static final void checkAbsolute(final XPathFactory xfac, final NamespaceAware nsa) {
46 String xq = null;
47 if (nsa instanceof Attribute) {
48 xq = XPathHelper.getAbsolutePath((Attribute)nsa);
49 } else if (nsa instanceof Content) {
50 xq = XPathHelper.getAbsolutePath((Content)nsa);
51 } else {
52 xq = "/";
53 }
54 System.out.println("Running XPath for " + nsa + ": " + xq);
55 try {
56 final XPathExpression<Object> xp = xfac.compile(xq);
57 final XPathDiagnostic<Object> xd = xp.diagnose(nsa, false);
58 if (xd.getResult().size() != 1) {
59 fail ("expected exactly one result, not " + xd.getResult().size());
60 }
61 if (nsa != xd.getResult().get(0)) {
62 fail ("Expect the only result for '" + xq + "' to be " + nsa + " but it was " +
63 xd.getResult().get(0));
64 }
65 } catch (IllegalArgumentException e) {
66 String xxq = null;
67 if (nsa instanceof Attribute) {
68 xxq = XPathHelper.getAbsolutePath((Attribute)nsa);
69 } else if (nsa instanceof Content) {
70 xxq = XPathHelper.getAbsolutePath((Content)nsa);
71 }
72
73 AssertionError ae = new AssertionError("Unable to compile expression '" + xxq + "' to node " + nsa);
74 ae.initCause(e);
75 throw ae;
76 }
77
78
79 }
80
81 private static final void checkRelative(final XPathFactory xfac, final NamespaceAware nsa, final NamespaceAware nsb) {
82 String xq = null;
83 if (nsa instanceof Attribute) {
84 if (nsb instanceof Attribute) {
85 xq = XPathHelper.getRelativePath((Attribute)nsa, (Attribute)nsb);
86 } else {
87 xq = XPathHelper.getRelativePath((Attribute)nsa, (Content)nsb);
88 }
89 } else if (nsa instanceof Content) {
90 if (nsb instanceof Attribute) {
91 xq = XPathHelper.getRelativePath((Content)nsa, (Attribute)nsb);
92 } else {
93 xq = XPathHelper.getRelativePath((Content)nsa, (Content)nsb);
94 }
95 } else {
96 xq = "/";
97 }
98 final XPathExpression<Object> xp = xfac.compile(xq);
99 final XPathDiagnostic<Object> xd = xp.diagnose(nsa, false);
100 if(xd.getResult().size() != 1) {
101 fail ("Expected single result from " + nsa + " to " + nsb + " but got " + xd);
102 }
103 if (nsb != xd.getResult().get(0)) {
104 fail ("Expected single result to be " + nsb + " not " + xd.getResult());
105 }
106
107 }
108
109 /**
110 * This test loads up an XML document and calculates the absolute expression
111 * for each node, and also the expression for each node relative to *every*
112 * other node. It then runs every expression and ensures that the exact
113 * right node is selected.
114 * The input XML document is designed to have all sorts of tricky nodes to
115 * process. This ensures that all (for a limited set of 'all') combinations
116 * of valid input data are tested.
117 *
118 * @throws JDOMException If the document fails to parse.
119 * @throws IOException
120 */
121 @Test
122 public void testComplex() throws JDOMException, IOException {
123 SAXBuilder sb = new SAXBuilder();
124 sb.setExpandEntities(false);
125 Document doc = sb.build(FidoFetch.getFido().getURL("/complex.xml"));
126 final Iterator<Content> des = doc.getDescendants();
127 final ArrayList<NamespaceAware> allc = new ArrayList<NamespaceAware>();
128 final XPathFactory fac = getFactory();
129 while (des.hasNext()) {
130 final Content c = des.next();
131 // if (c.getParent() == doc && c != doc.getRootElement()) {
132 // // ignore document level content (except root element.
133 // continue;
134 // }
135 checkAbsolute(fac, c);
136 allc.add(c);
137 if (c instanceof Element) {
138 if (((Element) c).hasAttributes()) {
139 for (Attribute a : ((Element)c).getAttributes()) {
140 checkAbsolute(fac, a);
141 allc.add(a);
142 }
143 }
144 }
145 }
146 for (NamespaceAware nsa : allc) {
147 for (NamespaceAware nsb : allc) {
148 checkRelative(fac, nsa, nsb);
149 }
150 }
151 }
152
153 @Test
154 public void testGetAbsolutePathAttribute() {
155 // testComplex() covers working case. We need to do negative testing
156 try {
157 final Attribute att = null;
158 XPathHelper.getAbsolutePath(att);
159 UnitTestUtil.failNoException(NullPointerException.class);
160 } catch (Exception e) {
161 UnitTestUtil.checkException(NullPointerException.class, e);
162 }
163 try {
164 final Attribute att = new Attribute("detached", "value");
165 XPathHelper.getAbsolutePath(att);
166 UnitTestUtil.failNoException(IllegalArgumentException.class);
167 } catch (Exception e) {
168 UnitTestUtil.checkException(IllegalArgumentException.class, e);
169 }
170 }
171
172 @Test
173 public void testGetAbsolutePathContent() {
174 // testComplex() covers working case. We need to do negative testing
175 try {
176 final Text att = null;
177 XPathHelper.getAbsolutePath(att);
178 UnitTestUtil.failNoException(NullPointerException.class);
179 } catch (Exception e) {
180 UnitTestUtil.checkException(NullPointerException.class, e);
181 }
182 try {
183 final Text att = new Text("detached");
184 XPathHelper.getAbsolutePath(att);
185 UnitTestUtil.failNoException(IllegalArgumentException.class);
186 } catch (Exception e) {
187 UnitTestUtil.checkException(IllegalArgumentException.class, e);
188 }
189 }
190
191 @Test
192 public void testGetRelativePathAttributeAttribute() {
193 // testComplex() covers working case. We need to do negative testing
194 try {
195 final Attribute atta = new Attribute("att", "value");
196 final Attribute attb = null;
197 XPathHelper.getRelativePath(atta, attb);
198 UnitTestUtil.failNoException(NullPointerException.class);
199 } catch (Exception e) {
200 UnitTestUtil.checkException(NullPointerException.class, e);
201 }
202 try {
203 final Attribute atta = new Attribute("att", "value");
204 final Attribute attb = new Attribute("detached", "value");
205 XPathHelper.getRelativePath(atta, attb);
206 UnitTestUtil.failNoException(IllegalArgumentException.class);
207 } catch (Exception e) {
208 UnitTestUtil.checkException(IllegalArgumentException.class, e);
209 }
210 try {
211 final Attribute atta = null;
212 final Attribute attb = new Attribute("att", "value");
213 XPathHelper.getRelativePath(atta, attb);
214 UnitTestUtil.failNoException(NullPointerException.class);
215 } catch (Exception e) {
216 UnitTestUtil.checkException(NullPointerException.class, e);
217 }
218 }
219
220 @Test
221 public void testGetRelativePathContentAttribute() {
222 // testComplex() covers working case. We need to do negative testing
223 try {
224 final Element root = new Element("root");
225 final Attribute att = null;
226 XPathHelper.getRelativePath(root, att);
227 UnitTestUtil.failNoException(NullPointerException.class);
228 } catch (Exception e) {
229 UnitTestUtil.checkException(NullPointerException.class, e);
230 }
231 try {
232 final Element root = new Element("root");
233 final Attribute att = new Attribute("detached", "value");
234 XPathHelper.getRelativePath(root, att);
235 UnitTestUtil.failNoException(IllegalArgumentException.class);
236 } catch (Exception e) {
237 UnitTestUtil.checkException(IllegalArgumentException.class, e);
238 }
239 // testComplex() covers working case. We need to do negative testing
240 try {
241 final Element root = null;
242 final Attribute att = new Attribute("att", "value");
243 XPathHelper.getRelativePath(root, att);
244 UnitTestUtil.failNoException(NullPointerException.class);
245 } catch (Exception e) {
246 UnitTestUtil.checkException(NullPointerException.class, e);
247 }
248 }
249
250 @Test
251 public void testGetRelativePathAttributeContent() {
252 // testComplex() covers working case. We need to do negative testing
253 try {
254 final Attribute att = null;
255 final Element root = new Element("root");
256 XPathHelper.getRelativePath(att, root);
257 UnitTestUtil.failNoException(NullPointerException.class);
258 } catch (Exception e) {
259 UnitTestUtil.checkException(NullPointerException.class, e);
260 }
261 try {
262 final Attribute att = new Attribute("detached", "value");
263 final Element root = new Element("root");
264 XPathHelper.getRelativePath(att, root);
265 UnitTestUtil.failNoException(IllegalArgumentException.class);
266 } catch (Exception e) {
267 UnitTestUtil.checkException(IllegalArgumentException.class, e);
268 }
269 try {
270 final Attribute att = new Attribute("detached", "value");
271 final Element root = null;
272 XPathHelper.getRelativePath(att, root);
273 UnitTestUtil.failNoException(NullPointerException.class);
274 } catch (Exception e) {
275 UnitTestUtil.checkException(NullPointerException.class, e);
276 }
277 }
278
279 @Test
280 public void testGetRelativePathContentContent() {
281 // testComplex() covers working case. We need to do negative testing
282 try {
283 final Element root = new Element("root");
284 final Text att = null;
285 XPathHelper.getRelativePath(root, att);
286 UnitTestUtil.failNoException(NullPointerException.class);
287 } catch (Exception e) {
288 UnitTestUtil.checkException(NullPointerException.class, e);
289 }
290 try {
291 final Element root = new Element("root");
292 final Text att = new Text("detached");
293 XPathHelper.getRelativePath(root, att);
294 UnitTestUtil.failNoException(IllegalArgumentException.class);
295 } catch (Exception e) {
296 UnitTestUtil.checkException(IllegalArgumentException.class, e);
297 }
298 try {
299 // no common ancestor
300 final Element roota = new Element("root");
301 final Element rootb = new Element("root");
302 XPathHelper.getRelativePath(roota, rootb);
303 UnitTestUtil.failNoException(IllegalArgumentException.class);
304 } catch (Exception e) {
305 UnitTestUtil.checkException(IllegalArgumentException.class, e);
306 }
307 try {
308 final Element roota = null;
309 final Element rootb = new Element("root");
310 XPathHelper.getRelativePath(roota, rootb);
311 UnitTestUtil.failNoException(NullPointerException.class);
312 } catch (Exception e) {
313 UnitTestUtil.checkException(NullPointerException.class, e);
314 }
315 }
316
317 private void checkDetached(final XPathFactory fac, final NamespaceAware nsa) {
318 try {
319 checkAbsolute(fac, nsa);
320 UnitTestUtil.failNoException(IllegalArgumentException.class);
321 } catch (Exception e) {
322 UnitTestUtil.checkException(IllegalArgumentException.class, e);
323 }
324 checkRelative(fac, nsa, nsa);
325 }
326
327 @Test
328 public void testDetached() {
329 // non-Element content...
330 final XPathFactory fac = getFactory();
331 checkDetached(fac, new Text("detached"));
332 checkDetached(fac, new CDATA("detached"));
333 checkDetached(fac, new Attribute("detached", "value"));
334 checkDetached(fac, new ProcessingInstruction("detached"));
335 checkDetached(fac, new EntityRef("detached"));
336 checkDetached(fac, new Comment("detached"));
337
338 }
339
340 }
0 package org.jdom.test.cases.xpath;
1
2 import org.jdom.xpath.XPathFactory;
3
4 @SuppressWarnings("javadoc")
5 public class TestDefaultXPathHelper extends AbstractTestXPathHepler {
6 @Override
7 XPathFactory getFactory() {
8 return XPathFactory.instance();
9 }
10 }
0 package org.jdom.test.cases.xpath;
1
2 import org.junit.Test;
3
4 import org.jdom.contrib.xpath.java.JavaXPathFactory;
5 import org.jdom.xpath.XPathFactory;
6
7 @SuppressWarnings({"javadoc"})
8 public class TestJavaCompiled extends AbstractTestXPathCompiled {
9
10 public TestJavaCompiled() {
11 super(false);
12 }
13
14 private static final XPathFactory myfac = new JavaXPathFactory();
15
16 @Override
17 XPathFactory getFactory() {
18 return myfac;
19 }
20
21 @Override
22 public void testAncestorOrSelfFromNamespace() {
23 // nothing
24 }
25
26 @Override
27 public void getXPathDouble() {
28 // nothing
29 }
30
31 @Override
32 public void getXPathString() {
33 // nothing
34 }
35
36 @Override
37 public void getXPathBoolean() {
38 // nothing
39 }
40
41 @Override
42 @Test
43 public void testXPathPrecedingNode() {
44 // we do not get items outside the root node for Document stuff.
45 checkXPath("preceding::node()", child2emt, null,
46 maincomment, mainpi, maintext1, child1emt, child1text, maintext2);
47 }
48
49
50 @Override
51 public void testDetachedAttribute() {
52 // TODO Not Supported
53 }
54
55 @Override
56 public void testDetachedText() {
57 // TODO Not Supported
58 }
59
60 @Override
61 public void testDetachedCDATA() {
62 // TODO Not Supported
63 }
64
65 @Override
66 public void testDetachedProcessingInstruction() {
67 // TODO Not Supported
68 }
69
70 @Override
71 public void testDetachedEntityRef() {
72 // TODO Not Supported
73 }
74
75 @Override
76 public void testDetachedComment() {
77 // TODO Not Supported
78 }
79
80 @Override
81 public void testDetachedElement() {
82 // TODO Not Supported
83 }
84
85 }
0 package org.jdom.test.cases.xpath;
1
2 import org.junit.Ignore;
3 import org.junit.Test;
4
5 import org.jdom.Comment;
6 import org.jdom.Element;
7 import org.jdom.xpath.XPathFactory;
8 import org.jdom.xpath.jaxen.JaxenXPathFactory;
9
10 @SuppressWarnings({"javadoc"})
11 public class TestJaxenCompiled extends AbstractTestXPathCompiled {
12
13 public TestJaxenCompiled() {
14 super(true);
15 }
16
17 private static final XPathFactory myfac = new JaxenXPathFactory();
18
19 @Override
20 XPathFactory getFactory() {
21 return myfac;
22 }
23
24 public static void main(String[] args) {
25 System.setProperty("jaxp.debug", "true");
26 javax.xml.xpath.XPathFactory myfacx = javax.xml.xpath.XPathFactory.newInstance();
27 System.out.println(myfacx);
28 }
29
30 @Override
31 @Test
32 @Ignore
33 public void testXPathOR() {
34 // JAXEN Does not support document order for unions....
35 super.testXPathOR();
36 }
37
38 @Test
39 @Ignore
40 public void testSpecialOR() {
41 Element m = new Element("main");
42 m.setAttribute("att", "value");
43 m.addContent(new Comment("comment"));
44 checkXPath("/main/node()[1] | /main/@*", main, null, m.getAttribute("att"), m.getContent(0));
45 }
46
47
48 }
0 package org.jdom.test.cases.xpath;
1
2 import org.jdom.xpath.XPathFactory;
3 import org.jdom.xpath.jaxen.JaxenXPathFactory;
4
5 @SuppressWarnings("javadoc")
6 public class TestJaxenXPathHelper extends AbstractTestXPathHepler {
7 @Override
8 XPathFactory getFactory() {
9 return XPathFactory.newInstance(JaxenXPathFactory.class.getName());
10 }
11 }
0 package org.jdom.test.cases.xpath;
1
2 import org.jdom.JDOMException;
3 import org.jdom.xpath.XPath;
4 import org.jdom.xpath.jaxen.JDOMXPath;
5
6 /**
7 *
8 * @author Rolf Lear
9 * @deprecated in lieu of TestJaxenCompiled
10 */
11 @Deprecated
12 public class TestLocalJaxenXPath extends AbstractTestXPath {
13
14 @Override
15 @Deprecated
16 XPath buildPath(String path) throws JDOMException {
17 final XPath ret = new JDOMXPath(path);
18 return ret;
19 }
20
21 }
0 package org.jdom.test.cases.xpath;
1
2 import static org.junit.Assert.*;
3
4 import java.util.Collections;
5
6 import org.junit.Test;
7
8 import org.jdom.Namespace;
9 import org.jdom.filter2.Filters;
10 import org.jdom.test.util.UnitTestUtil;
11 import org.jdom.xpath.XPathBuilder;
12 import org.jdom.xpath.XPathExpression;
13 import org.jdom.xpath.XPathFactory;
14
15 @SuppressWarnings("javadoc")
16 public class TestXPathBuilder {
17
18 @Test
19 public void testXPathBuilder() {
20 try {
21 new XPathBuilder<Object>(null, Filters.fpassthrough()).toString();
22 UnitTestUtil.failNoException(NullPointerException.class);
23 } catch (Exception e) {
24 UnitTestUtil.checkException(NullPointerException.class, e);
25 }
26 try {
27 new XPathBuilder<Object>("/", null).toString();
28 UnitTestUtil.failNoException(NullPointerException.class);
29 } catch (Exception e) {
30 UnitTestUtil.checkException(NullPointerException.class, e);
31 }
32 assertNotNull(new XPathBuilder<Object>("/", Filters.fpassthrough()).toString());
33 }
34
35 @Test
36 public void testGetSetVariable() {
37 XPathBuilder<Object> xpb =
38 new XPathBuilder<Object>("/", Filters.fpassthrough());
39 try {
40 xpb.getVariable(null);
41 UnitTestUtil.failNoException(NullPointerException.class);
42 } catch (Exception e) {
43 UnitTestUtil.checkException(NullPointerException.class, e);
44 }
45 try {
46 xpb.setVariable(null, "");
47 UnitTestUtil.failNoException(NullPointerException.class);
48 } catch (Exception e) {
49 UnitTestUtil.checkException(NullPointerException.class, e);
50 }
51 try {
52 xpb.setVariable(null, "");
53 UnitTestUtil.failNoException(NullPointerException.class);
54 } catch (Exception e) {
55 UnitTestUtil.checkException(NullPointerException.class, e);
56 }
57 assertNull(xpb.getVariable("hello"));
58 assertTrue(xpb.setVariable("name", ""));
59 assertEquals("", xpb.getVariable("name"));
60 assertFalse(xpb.setVariable("name", "xxx"));
61 assertEquals("xxx", xpb.getVariable("name"));
62 }
63
64 @Test
65 public void testSetNamespaceStringString() {
66 XPathBuilder<Object> xpb =
67 new XPathBuilder<Object>("/", Filters.fpassthrough());
68 try {
69 xpb.setNamespace("", "hello");
70 UnitTestUtil.failNoException(IllegalArgumentException.class);
71 } catch (Exception e) {
72 UnitTestUtil.checkException(IllegalArgumentException.class, e);
73 }
74 try {
75 xpb.setNamespace("", null);
76 UnitTestUtil.failNoException(NullPointerException.class);
77 } catch (Exception e) {
78 UnitTestUtil.checkException(NullPointerException.class, e);
79 }
80 try {
81 xpb.setNamespace(null, "");
82 UnitTestUtil.failNoException(NullPointerException.class);
83 } catch (Exception e) {
84 UnitTestUtil.checkException(NullPointerException.class, e);
85 }
86
87 assertFalse(xpb.setNamespace("", ""));
88
89 assertEquals(Namespace.NO_NAMESPACE, xpb.getNamespace(""));
90
91 assertNull(xpb.getNamespace("hello"));
92 Namespace hello = Namespace.getNamespace("h", "hello");
93 assertTrue(xpb.setNamespace("h", "hello"));
94 assertTrue(hello == xpb.getNamespace("h"));
95
96 try {
97 xpb.getNamespace(null);
98 UnitTestUtil.failNoException(NullPointerException.class);
99 } catch (Exception e) {
100 UnitTestUtil.checkException(NullPointerException.class, e);
101 }
102
103 }
104
105 @Test
106 public void testSetNamespaceNamespace() {
107 XPathBuilder<Object> xpb =
108 new XPathBuilder<Object>("/", Filters.fpassthrough());
109 try {
110 Namespace nsx = Namespace.getNamespace("", "hello");
111 xpb.setNamespace(nsx);
112 UnitTestUtil.failNoException(IllegalArgumentException.class);
113 } catch (Exception e) {
114 UnitTestUtil.checkException(IllegalArgumentException.class, e);
115 }
116 try {
117 xpb.setNamespace(null);
118 UnitTestUtil.failNoException(NullPointerException.class);
119 } catch (Exception e) {
120 UnitTestUtil.checkException(NullPointerException.class, e);
121 }
122
123 assertFalse(xpb.setNamespace(Namespace.NO_NAMESPACE));
124
125 assertEquals(Namespace.NO_NAMESPACE, xpb.getNamespace(""));
126
127 assertNull(xpb.getNamespace("hello"));
128 Namespace hello = Namespace.getNamespace("h", "hello");
129 assertTrue(xpb.setNamespace(hello));
130 assertTrue(hello == xpb.getNamespace("h"));
131 }
132
133 @Test
134 public void testSetNamespaces() {
135 XPathBuilder<Object> xpb =
136 new XPathBuilder<Object>("/", Filters.fpassthrough());
137 try {
138 Namespace nsx = Namespace.getNamespace("", "hello");
139 xpb.setNamespaces(Collections.singleton(nsx));
140 UnitTestUtil.failNoException(IllegalArgumentException.class);
141 } catch (Exception e) {
142 UnitTestUtil.checkException(IllegalArgumentException.class, e);
143 }
144 try {
145 xpb.setNamespaces(null);
146 UnitTestUtil.failNoException(NullPointerException.class);
147 } catch (Exception e) {
148 UnitTestUtil.checkException(NullPointerException.class, e);
149 }
150
151 assertFalse(xpb.setNamespaces(Collections.singletonList(Namespace.NO_NAMESPACE)));
152
153 assertEquals(Namespace.NO_NAMESPACE, xpb.getNamespace(""));
154
155 assertNull(xpb.getNamespace("hello"));
156 Namespace hello = Namespace.getNamespace("h", "hello");
157 assertTrue(xpb.setNamespaces(Collections.singletonList(hello)));
158 assertTrue(hello == xpb.getNamespace("h"));
159 Namespace hellp = Namespace.getNamespace("h", "hellp");
160 assertFalse(xpb.setNamespaces(Collections.singletonList(hellp)));
161 }
162
163 @Test
164 public void testGetFilter() {
165 XPathBuilder<Object> xpb =
166 new XPathBuilder<Object>("/", Filters.fpassthrough());
167 assertTrue(xpb.getFilter() == Filters.fpassthrough());
168 }
169
170 @Test
171 public void testGetExpression() {
172 XPathBuilder<Object> xpb =
173 new XPathBuilder<Object>("/", Filters.fpassthrough());
174 assertEquals("/", xpb.getExpression());
175 }
176
177 @Test
178 public void testCompileWith() {
179 XPathBuilder<Object> xpb =
180 new XPathBuilder<Object>("/", Filters.fpassthrough());
181 xpb.setNamespace("p", "uri");
182 xpb.setVariable("p:var", "value");
183 XPathExpression<Object> xpe = xpb.compileWith(XPathFactory.instance());
184 assertEquals("/", xpe.getExpression());
185 assertEquals(Filters.fpassthrough(), xpe.getFilter());
186 assertEquals("", xpe.getNamespace("").getURI());
187 assertEquals("uri", xpe.getNamespace("p").getURI());
188 assertEquals("value", xpe.getVariable("var", Namespace.getNamespace("uri")));
189 }
190
191 }
0 package org.jdom.test.cases.xpath;
1
2 import static org.junit.Assert.assertNotNull;
3 import static org.junit.Assert.assertTrue;
4
5 import org.junit.Test;
6
7 import org.jdom.Element;
8 import org.jdom.filter2.Filters;
9 import org.jdom.xpath.XPathExpression;
10 import org.jdom.xpath.XPathFactory;
11 import org.jdom.xpath.jaxen.JaxenXPathFactory;
12
13 @SuppressWarnings("javadoc")
14 public class TestXPathFactory {
15
16 @Test
17 public void testNewInstance() {
18 XPathFactory xpf = XPathFactory.instance();
19 assertNotNull(xpf);
20 assertTrue(xpf != XPathFactory.newInstance(xpf.getClass().getName()));
21 XPathExpression<?> xp = xpf.compile(".");
22 Element emt = new Element("root");
23 assertTrue(emt == xp.evaluateFirst(emt));
24 }
25
26 @Test
27 public void testNewInstanceString() {
28 XPathFactory xpf = XPathFactory.newInstance(JaxenXPathFactory.class.getName());
29 assertNotNull(xpf);
30 assertTrue(xpf != XPathFactory.newInstance(JaxenXPathFactory.class.getName()));
31 XPathExpression<?> xp = xpf.compile(".");
32 Element emt = new Element("root");
33 assertTrue(emt == xp.evaluateFirst(emt));
34 }
35
36 @Test
37 public void testNewInstanceCompileNSList() {
38 XPathFactory xpf = XPathFactory.newInstance(JaxenXPathFactory.class.getName());
39 assertNotNull(xpf);
40 assertTrue(xpf != XPathFactory.newInstance(JaxenXPathFactory.class.getName()));
41 XPathExpression<?> xp = xpf.compile(".");
42 Element emt = new Element("root");
43 assertTrue(emt == xp.evaluateFirst(emt));
44 xp = xpf.compile(".", Filters.element(), null, emt.getNamespacesInScope());
45 assertTrue(emt == xp.evaluateFirst(emt));
46 }
47
48 }
0 package org.jdom.test.cases.xpath;
1
2 import org.junit.Test;
3
4 import org.jdom.contrib.xpath.xalan.XalanXPathFactory;
5 import org.jdom.xpath.XPathFactory;
6
7 @SuppressWarnings({"javadoc"})
8 public class TestXalanCompiled extends AbstractTestXPathCompiled {
9
10 public TestXalanCompiled() {
11 super(true);
12 }
13
14 private static final XPathFactory myfac = new XalanXPathFactory();
15
16 @Override
17 XPathFactory getFactory() {
18 return myfac;
19 }
20
21 @Override
22 public void testAncestorOrSelfFromNamespace() {
23 // nothing... can't set a Namespace as a context in Xalan;
24 }
25
26 @Override
27 @Test
28 public void testXPathPrecedingNode() {
29 // we do not get items outside the root node for Document stuff.
30 checkXPath("preceding::node()", child2emt, null,
31 maincomment, mainpi, maintext1, child1emt, child1text, maintext2);
32 }
33
34 @Override
35 public void testDetachedAttribute() {
36 // TODO Not Supported
37 }
38
39 @Override
40 public void testDetachedText() {
41 // TODO Not Supported
42 }
43
44 @Override
45 public void testDetachedCDATA() {
46 // TODO Not Supported
47 }
48
49 @Override
50 public void testDetachedProcessingInstruction() {
51 // TODO Not Supported
52 }
53
54 @Override
55 public void testDetachedEntityRef() {
56 // TODO Not Supported
57 }
58
59 @Override
60 public void testDetachedComment() {
61 // TODO Not Supported
62 }
63
64 @Override
65 public void testDetachedElement() {
66 // TODO Not Supported
67 }
68
69
70
71 }
0 package org.jdom.test.cases.xpath;
1
2 import static org.junit.Assert.assertTrue;
3 import static org.junit.Assert.fail;
4
5 import java.util.List;
6
7 import org.junit.Test;
8
9 import org.jdom.Document;
10 import org.jdom.Element;
11 import org.jdom.JDOMException;
12 import org.jdom.xpath.XPath;
13 import org.jdom.xpath.jaxen.JDOMXPath;
14
15 /**
16 *
17 * @author Rolf Lear
18 * @deprecated old XPath
19 */
20 @SuppressWarnings({"javadoc"} )
21 @Deprecated
22 public class TestXpath {
23 /*
24 * Test the static methods on the abstract class.
25 */
26
27 @Test
28 public void testNewInstance() {
29 try {
30 Document doc = new Document(new Element("main"));
31 XPath xp = XPath.newInstance("/");
32 assertTrue(doc == xp.selectSingleNode(doc));
33 } catch (JDOMException e) {
34 e.printStackTrace();
35 fail("Could not process XPath.newInstance()");
36 }
37 }
38
39 @Test
40 public void testSetXPathClass() throws JDOMException {
41 XPath.setXPathClass(JDOMXPath.class);
42 }
43
44 @Test
45 public void testSelectNodesObjectString() throws JDOMException {
46 Document doc = new Document(new Element("main"));
47 List<?> lst = XPath.selectNodes(doc, "/");
48 assertTrue(lst.size() == 1);
49 assertTrue(doc == lst.get(0));
50 }
51
52 @Test
53 public void testSelectSingleNodeObjectString() throws JDOMException {
54 Document doc = new Document(new Element("main"));
55 Object ret = XPath.selectSingleNode(doc, "/");
56 assertTrue(doc == ret);
57 }
58
59 }
0 package org.jdom.test.util;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertTrue;
5 import static org.junit.Assert.fail;
6 import static org.jdom.test.util.UnitTestUtil.*;
7
8 import java.lang.reflect.Array;
9 import java.util.Arrays;
10 import java.util.Collection;
11 import java.util.Collections;
12 import java.util.ConcurrentModificationException;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.ListIterator;
16 import java.util.NoSuchElementException;
17
18 import org.junit.Test;
19
20 import org.jdom.internal.ArrayCopy;
21
22 /**
23 * This base class can be used to test multiple implementations of List<?>
24 * It is reusable for different list types, and does the 'normal' type testing.
25 *
26 *
27 *
28 * @author Rolf Lear
29 *
30 */
31 @SuppressWarnings({ "unchecked", "javadoc" })
32 public abstract class AbstractTestList<T> {
33
34 /**
35 * The following is a list of somewhat binary-progressive prime numbers.
36 * sequence is +2, +2, +2, +2, +4, +4, +4, +4, +8, +8, +8, +8,
37 * +16, +16, +16, +16, +32, ......
38 * given the above sequence, get the first prime number that is larger than
39 * the sequence value.
40 */
41 private static final int[] BIGPRIMES = new int[] {3, 5, 7, 11, 13, 17, 23,
42 29, 37, 41, 53, 59, 73, 89, 107, 127, 157, 191, 223, 251, 313, 379, 443,
43 509, 641, 761, 907, 1019, 1277, 1531, 1787, 2053, 2557, 3067, 3581,
44 4091, 5113, 6143, 7177, 8191, 10243, 12281, 14341, 16381, 20477, 24571,
45 28669, 32771, 40961, 49157, 57347, 65537, 81919, 98297, 114689, 131071,
46 163841, 196613, 229373, 262139, 327673, 393209, 458747, 524287, 655357,
47 786431, 917503, 1048571};
48
49 private static final int[][] SMALLSHUFFLE = new int[][] {
50 new int[]{},
51 new int[]{0},
52 new int[]{1,0},
53 new int[]{2, 0, 1},
54 new int[]{2, 0, 3, 1},
55 new int[]{4, 1, 2, 0, 3},
56 new int[]{3, 0, 2, 4, 5, 1}
57 };
58
59 private final boolean i_nullok;
60 private final Class<T> i_tclass;
61
62 /**
63 * Generalised constructor for testing a list.
64 * @param tclass all content should be an instance (or subtype) of this class
65 * @param nullok are null values allowed on the list.
66 * @param samplecontent some sample data to load in to the list. The more, the better.
67 */
68 public AbstractTestList(Class<T> tclass, boolean nullok) {
69 super();
70 i_nullok = nullok;
71 i_tclass = tclass;
72 }
73
74 /**
75 * Create a list of the type to test. It should be empty.
76 * @return the list to test.
77 */
78 public abstract List<T> buildEmptyList();
79
80 /**
81 * This is sample data that should be legal in the list.
82 * There should be at least 10 or so elements.
83 * @return the sample data.
84 */
85 public abstract T[] buildSampleContent();
86
87 /**
88 * This should contain at least one additional valid entry
89 * that can be legally be added to the list after it is already populated
90 * with the sample data.
91 * @return the extra data.
92 */
93 public abstract T[] buildAdditionalContent();
94
95 /**
96 * This should contain data that is of the correct generic type of the data
97 * but has some property that makes it illegal. This can be empty....
98 * @return the IllegalArgument test data.
99 */
100 public abstract T[] buildIllegalArgumentContent();
101 /**
102 * This list should be of content that is of the wrong class (a class not
103 * compatible with <T>
104 * @return the ClassCast test data.
105 */
106 public abstract Object[] buildIllegalClassContent();
107
108
109 /* *********************************
110 * Private support methods
111 * ********************************* */
112
113 /**
114 * Create an array of the required type with the required length
115 * @param length The length of the array to create.
116 * @return the created array.
117 */
118 protected final T[] buildArray(int length) {
119 return (T[])Array.newInstance(i_tclass, length);
120 }
121
122 /**
123 * Remove an element from an array.
124 * @param content The original content.
125 * @param index The element to remove
126 * @return a new array with the specified element removed.
127 */
128 protected final T[] arrayRemove(T[] content, int index) {
129 if (index < 0 || index >= content.length) {
130 throw new IllegalArgumentException("Can not have index " + index
131 + " when there are only " + content.length + " elements.");
132 }
133 T[] ret = ArrayCopy.copyOf(content, content.length - 1);
134 System.arraycopy(content, index + 1, ret, index, ret.length - index);
135 return ret;
136 }
137
138 /**
139 * Insert an element in to the content at the specified index.
140 * @param content The base content to add to.
141 * @param index The position to insert (items from this position will be
142 * moved to the right). Using content.lenght will add to the end.
143 * @param insert The value to insert
144 * @return The amended content array
145 */
146 protected final T[] arrayInsert(T[] content, int index, T...insert) {
147 if (index < 0 || index > content.length) {
148 throw new IllegalArgumentException("Can not use index " + index
149 + " when there is only " + content.length + " content.");
150 }
151 if (insert == null) {
152 throw new NullPointerException("Can not have a null insert vararg array");
153 }
154 T[] ret = ArrayCopy.copyOf(content, content.length + insert.length);
155 System.arraycopy(ret, index, ret, index+insert.length, content.length - index);
156 System.arraycopy(insert, 0, ret, index, insert.length);
157 return ret;
158 }
159
160 /**
161 * Reverse the contents of an array.
162 * @param content The array to reverse.
163 * @return a new array with the same content as the input, but in reverse
164 * order
165 */
166 protected final T[] arrayReverse(T[] content) {
167 T[] ret = ArrayCopy.copyOf(content, content.length);
168 for (int i = (content.length - 1) / 2; i >= 0; i--) {
169 final T tmp = ret[i];
170 ret[i] = ret[ret.length - 1 - i];
171 ret[ret.length - 1 - i] = tmp;
172 }
173 return ret;
174 }
175
176 private final int pickPrime(final int len) {
177 if (len < SMALLSHUFFLE.length) {
178 throw new IllegalStateException("Should have a prime set already");
179 }
180 int pindex = 0;
181 while (pindex < BIGPRIMES.length && BIGPRIMES[pindex] <= (len / 2)) {
182 pindex++;
183 }
184 if (pindex >= BIGPRIMES.length) {
185 throw new IllegalStateException("Unable to create a shuffled order " +
186 "for that many elements: " + len);
187 }
188 return BIGPRIMES[pindex];
189 }
190
191 /*
192 * helper method for shuffle().
193 */
194 private final int shuffleCompute(final int offset, final int len, final int prime) {
195 // Integer.MAX_INT is a prime number... but too big
196 // Using a Prime in this way guarantees that we loop through all the values
197 // in the sequence without having duplicates.
198 return (offset + prime) % len;
199 }
200
201 /**
202 * Generate a (very) pseudo-random order of a given length.
203 * The shuffled order is always repeatable, predictable, but also
204 * appears 'random'. This is useful so that we can compare strange-ordered
205 * inserts/removes/sets.
206 * @param len How many elements to include.
207 * @return An array of int. Each value will be unique, from 0 to len-1
208 */
209 protected final int[] shuffle(final int len) {
210 if (len < SMALLSHUFFLE.length) {
211 return ArrayCopy.copyOf(SMALLSHUFFLE[len], len);
212 }
213 final int prime = pickPrime(len);
214 int[] ret = new int[len];
215 int c = shuffleCompute(0, len, prime);
216 for (int i = len - 1; i >= 0; i--) {
217 c = shuffleCompute(c, len, prime);
218 if (ret[c] != 0) {
219 // this should never happen, but this is a double-check
220 // guarantee that we never miss values in the sequence.
221 throw new IllegalStateException("Oops");
222 }
223 ret[c] = i;
224 }
225 return ret;
226 }
227
228 /**
229 * Run a list though the basic paces of operation.
230 * @param list the List<T> to exercise.
231 * @param content the content (in the order) that we expect in the list.
232 */
233 protected final void exercise(List<T> list, T...content) {
234 assertTrue("List is null", list != null);
235 assertTrue("Content is null", content != null);
236 assertTrue(content.length == list.size());
237 assertTrue(list.toString() != null);
238 if (content.length == 0) {
239 assertTrue(list.size() == 0);
240 assertTrue(list.isEmpty());
241 } else {
242 assertTrue(list.size() > 0);
243 assertFalse(list.isEmpty());
244 }
245
246 for (int i = 0; i < content.length; i++) {
247 if (list.get(i) != content[i]) {
248 fail(String.format("We expect element in list at position %d to be %s",
249 i, content[i]));
250 }
251 int pos = list.indexOf(content[i]);
252 assertTrue(pos >= 0);
253 if (pos != i) {
254 // may be duplicates in the list....
255 assertTrue(pos < i); // but pos must be first...
256 assertEquals(content[pos], content[i]);
257 }
258 assertTrue(list.contains(content[i]));
259 }
260
261 for (int i = content.length - 1; i >= 0; i--) {
262 assertTrue(list.get(i) == content[i]);
263 int pos = list.lastIndexOf(content[i]);
264 assertTrue(pos >= 0);
265 if (pos != i) {
266 // may be duplicates in the list....
267 assertTrue(pos > i); // but pos must be later...
268 assertEquals(content[pos], content[i]);
269 }
270 }
271
272 quickCheck(list, content);
273
274 {
275 // Check the iteration code.
276 // the iterator implementation can be different to the ListIterator
277 Iterator<T> it = list.iterator();
278 try {
279 it.remove();
280 failNoException(IllegalStateException.class);
281 } catch (Exception e) {
282 checkException(IllegalStateException.class, e);
283 }
284 int i = 0;
285 while (i < content.length) {
286 assertTrue(it.hasNext());
287 assertTrue(it.next() == content[i]);
288 it.remove();
289 try {
290 it.remove();
291 failNoException(IllegalStateException.class);
292 } catch (Exception e) {
293 checkException(IllegalStateException.class, e);
294 }
295 i++;
296 }
297 assertFalse(it.hasNext());
298 try {
299 it.next();
300 failNoException(NoSuchElementException.class);
301 } catch (Exception e) {
302 checkException(NoSuchElementException.class, e);
303 }
304
305 try {
306 it.remove();
307 failNoException(IllegalStateException.class);
308 } catch (Exception e) {
309 checkException(IllegalStateException.class, e);
310 }
311
312 for (T d : content) {
313 list.add(d);
314 }
315
316 }
317
318 quickCheck(list, content);
319
320 {
321 //Read-Only List iteration through list contents.
322 for (int origin = 0; origin <= content.length; origin++) {
323 // start at every place
324 ListIterator<T> li = list.listIterator(origin);
325
326 for (int i = origin; i < content.length; i++) {
327 assertTrue(li.hasNext());
328 assertTrue(li.nextIndex() == i);
329 assertTrue(li.previousIndex() == i - 1);
330 T emt = li.next();
331 assertTrue(content[i] == emt);
332 }
333
334 assertTrue(li.nextIndex() == content.length);
335 assertFalse(li.hasNext());
336 try {
337 li.next();
338 failNoException(NoSuchElementException.class);
339 } catch (Exception e) {
340 checkException(NoSuchElementException.class, e);
341 }
342
343 assertTrue(li.previousIndex() == (content.length - 1));
344 for (int i = content.length - 1; i >= 0; i--) {
345 assertTrue(li.previousIndex() == i);
346 assertTrue(li.nextIndex() == i + 1);
347 assertTrue(li.hasPrevious());
348 T emt = li.previous();
349 assertTrue(content[i] == emt);
350 }
351 assertTrue(li.previousIndex() == -1);
352 assertFalse(li.hasPrevious());
353 try {
354 li.previous();
355 failNoException(NoSuchElementException.class);
356 } catch (Exception e) {
357 checkException(NoSuchElementException.class, e);
358 }
359
360 assertTrue(li.nextIndex() == 0);
361 for (int i = 0; i < origin; i++) {
362 assertTrue(li.hasNext());
363 assertTrue(li.nextIndex() == i);
364 assertTrue(content[i] == li.next());
365 }
366
367 ListIterator<T> fbli = list.listIterator(origin);
368 assertTrue(fbli.nextIndex() == origin);
369 assertTrue(fbli.previousIndex() == (origin - 1));
370
371
372 }
373 }
374 {
375 //Read/write List iteration through list contents.
376 for (int origin = 0; origin <= content.length; origin++) {
377 // start at every place
378 ListIterator<T> li = list.listIterator(origin);
379
380 for (int i = origin; i < content.length; i++) {
381 assertTrue(li.hasNext());
382 assertTrue(li.nextIndex() == i);
383 assertTrue(li.previousIndex() == i - 1);
384 T emt = li.next();
385 assertTrue(content[i] == emt);
386 int n = li.nextIndex();
387 int p = li.previousIndex();
388 li.remove();
389 assertTrue(p - 1 == li.previousIndex());
390 assertTrue(n - 1 == li.nextIndex());
391 try {
392 li.remove();
393 failNoException(IllegalStateException.class);
394 } catch (Exception e) {
395 checkException(IllegalStateException.class, e);
396 }
397 li.add(emt);
398 assertTrue(p == li.previousIndex());
399 assertTrue(n == li.nextIndex());
400 }
401
402 assertTrue(li.nextIndex() == content.length);
403 assertFalse(li.hasNext());
404 try {
405 li.next();
406 failNoException(NoSuchElementException.class);
407 } catch (Exception e) {
408 checkException(NoSuchElementException.class, e);
409 }
410
411 assertTrue(li.previousIndex() == (content.length - 1));
412 for (int i = content.length - 1; i >= 0; i--) {
413 assertTrue(li.previousIndex() == i);
414 assertTrue(li.nextIndex() == i + 1);
415 assertTrue(li.hasPrevious());
416 T emt = li.previous();
417 assertTrue(content[i] == emt);
418 int p = li.previousIndex();
419 int n = li.nextIndex();
420 li.remove();
421 assertTrue(p == li.previousIndex());
422 assertTrue(n == li.nextIndex());
423 try {
424 li.remove();
425 failNoException(IllegalStateException.class);
426 } catch (Exception e) {
427 checkException(IllegalStateException.class, e);
428 }
429 li.add(emt);
430 assertTrue(content[i] == li.previous());
431 assertTrue(p == li.previousIndex());
432 assertTrue(n == li.nextIndex());
433 }
434 assertTrue(li.previousIndex() == -1);
435 assertFalse(li.hasPrevious());
436 try {
437 li.previous();
438 failNoException(NoSuchElementException.class);
439 } catch (Exception e) {
440 checkException(NoSuchElementException.class, e);
441 }
442
443 assertTrue(li.nextIndex() == 0);
444 for (int i = 0; i < origin; i++) {
445 assertTrue(li.hasNext());
446 assertTrue(li.nextIndex() == i);
447 assertTrue(content[i] == li.next());
448 }
449
450 ListIterator<T> fbli = list.listIterator(origin);
451 assertTrue(fbli.nextIndex() == origin);
452 assertTrue(fbli.previousIndex() == (origin - 1));
453
454
455 }
456
457 quickCheck(list, content);
458 }
459
460 {
461 // remove all, and re-add them.
462 ListIterator<T> it = list.listIterator(0);
463 for (int i = 0; i < content.length; i++) {
464 assertTrue(it.hasNext());
465 assertTrue(it.next() == content[i]);
466 it.remove();
467 }
468 for (int i = 0; i < content.length; i++) {
469 assertFalse(it.hasNext());
470 it.add(content[i]);
471 assertTrue(it.hasPrevious());
472 assertFalse(it.hasNext());
473 assertTrue(content[i] == it.previous());
474 assertTrue(content[i] == it.next());
475 assertFalse(it.hasNext());
476 }
477 assertFalse(it.hasNext());
478 quickCheck(list, content);
479
480 // then do it backwards.
481 it = list.listIterator(content.length);
482 for (int i = content.length - 1; i >= 0; i--) {
483 assertTrue(it.hasPrevious());
484 assertTrue(it.previous() == content[i]);
485 it.remove();
486 }
487 for (int i = content.length - 1; i >= 0; i--) {
488 assertFalse(it.hasPrevious());
489 it.add(content[i]);
490 assertTrue(it.hasPrevious());
491 assertTrue(content[i] == it.previous());
492 assertFalse(it.hasPrevious());
493 assertTrue(it.hasNext());
494 }
495 assertFalse(it.hasPrevious());
496 quickCheck(list, content);
497
498 }
499
500
501 if (content.length > 0) {
502 // Check the iterator set() method.
503 // first forward....
504
505 ListIterator<T> li = list.listIterator();
506
507 try {
508 li.set(content[0]);
509 failNoException(IllegalStateException.class);
510 } catch (Exception e) {
511 checkException(IllegalStateException.class, e);
512 }
513
514
515 T tmpa = li.next();
516 li.remove();
517 for (int i = 1; i < content.length; i++) {
518 T tmpb = li.next();
519 assertTrue(content[i] == tmpb);
520 li.set(tmpa);
521 tmpa = tmpb;
522 }
523 li.add(tmpa);
524 quickCheck(list, content);
525
526 // then backward ....
527 try {
528 li.set(content[0]);
529 failNoException(IllegalStateException.class);
530 } catch (Exception e) {
531 checkException(IllegalStateException.class, e);
532 }
533
534
535 tmpa = li.previous();
536 li.remove();
537 for (int i = content.length - 2; i >= 0; i--) {
538 T tmpb = li.previous();
539 assertTrue(content[i] == tmpb);
540 li.set(tmpa);
541 tmpa = tmpb;
542 }
543 li.add(tmpa);
544 quickCheck(list, content);
545 }
546
547 }
548
549 private void illegalExercise(List<T> list, T[] content, T d,
550 Class<? extends Exception> eclass) {
551
552 quickCheck(list, content);
553
554 try {
555 list.add(d);
556 failNoException(eclass);
557 } catch (Exception e) {
558 checkException(eclass, e);
559 }
560
561 try {
562 list.addAll(Collections.singleton(d));
563 failNoException(eclass);
564 } catch (Exception e) {
565 checkException(eclass, e);
566 }
567
568 for (int i = list.size() - 1; i >= 0; i--) {
569 try {
570 list.set(i, d);
571 failNoException(eclass);
572 } catch (Exception e) {
573 checkException(eclass, e);
574 }
575 }
576
577 for (int i = list.size(); i >= 0; i--) {
578 try {
579 list.add(i, d);
580 failNoException(eclass);
581 } catch (Exception e) {
582 checkException(eclass, e);
583 }
584
585 try {
586 list.addAll(i, Collections.singletonList(d));
587 failNoException(eclass);
588 } catch (Exception e) {
589 checkException(eclass, e);
590 }
591
592 try {
593 list.addAll(i, Collections.singletonList(d));
594 failNoException(eclass);
595 } catch (Exception e) {
596 checkException(eclass, e);
597 }
598 }
599
600
601 quickCheck(list, content);
602
603 ListIterator<T> li = list.listIterator();
604 for (int i = 0; i < list.size(); i++) {
605 assertTrue(li.hasNext());
606 assertTrue(content[i] == li.next());
607 try {
608 li.add(d);
609 failNoException(eclass);
610 } catch (Exception e) {
611 checkException(eclass, e);
612 }
613 // The AbstractList class increments the cursor on the iterator
614 // even if the add fails...
615 // This poor accounting means that th FilterList (which does the right thing)
616 // can't be tested as well... Create this artificail moveTo() to
617 // fix the AbstractList failings.
618 li = moveTo(list, i);
619
620 T prev = li.previous();
621 assertTrue(content[i] == prev);
622 assertTrue(content[i] == li.next());
623
624 try {
625 li.set(d);
626 failNoException(eclass);
627 } catch (Exception e) {
628 checkException(eclass, e);
629 }
630 // The ContentList class modifies the modcount for set()
631 // even if the set() fails...
632 // This poor accounting means that the FilterList (which does the right thing)
633 // can't be tested as well... Create this artificail moveTo() to
634 // fix the AbstractList failings.
635 li = moveTo(list, i);
636
637 }
638
639 quickCheck(list, content);
640
641 }
642
643 private ListIterator<T> moveTo(List<T> list, int i) {
644 ListIterator<T> li = list.listIterator();
645 while (i-- >= 0) {
646 assertTrue(li.hasNext());
647 li.next();
648 }
649 return li;
650 }
651
652 protected void quickCheck(List<T> list, T[] content) {
653 // Simple iteration through the list contents.
654 Iterator<T> it = list.iterator();
655 int i = 0;
656 while (i < content.length) {
657 assertTrue(it.hasNext());
658 assertTrue(content[i] == it.next());
659 i++;
660 }
661 assertFalse(it.hasNext());
662 try {
663 T overflow = it.next();
664 fail("There should be no element after hasNext() fails, but we got: " + overflow);
665 } catch (NoSuchElementException nsee) {
666 // this is what should happen!
667 }
668 }
669
670
671
672 /* *********************************
673 * Test the quality of the input data
674 * ********************************* */
675
676 @Test
677 public void testSamples() {
678 for (T s : buildSampleContent()) {
679 if (s != null && !i_tclass.isInstance(s)) {
680 fail("We expect all sample data to be an instance of " + i_tclass.getName());
681 }
682 }
683 }
684
685 @Test
686 public void testIllegalClassData() {
687 for (Object o : buildIllegalClassContent()) {
688 if (o == null || i_tclass.isInstance(o)) {
689 fail("We expect all IllegalClass data to be something other than " + i_tclass.getName());
690 }
691 }
692 }
693
694 @Test
695 public void testIllegalArgumentData() {
696 for (T s : buildIllegalArgumentContent()) {
697 if (s != null && !i_tclass.isInstance(s)) {
698 fail("We expect all IllegalArgument data to be an instance of " + i_tclass.getName());
699 }
700 }
701 }
702
703 /* *********************************
704 * The actual tests to run.
705 * ********************************* */
706
707 @Test
708 public void testToString() {
709 // basic run
710 assertTrue(buildEmptyList().toString() != null);
711 }
712
713 @Test
714 public void testEmpty() {
715 List<T> empty = buildEmptyList();
716 assertTrue(empty.size() == 0);
717 assertTrue(empty.isEmpty());
718 exercise(empty, buildArray(0));
719 }
720
721 @Test
722 public void testAdd() {
723 for (T s : buildSampleContent()) {
724 List<T> list = buildEmptyList();
725 assertTrue(list.isEmpty());
726 assertTrue(list.add(s));
727 exercise(list, s);
728 }
729 List<T> list = buildEmptyList();
730 T[] content = buildSampleContent();
731 for (T s : content) {
732 assertTrue(list.add(s));
733 }
734 exercise(list, content);
735 }
736
737 @Test
738 public void testAddAll() {
739 for (T s : buildSampleContent()) {
740 List<T> list = buildEmptyList();
741 assertTrue(list.isEmpty());
742 assertTrue(list.addAll(Arrays.asList(s)));
743 exercise(list, s);
744 list.clear();
745 }
746 List<T> list = buildEmptyList();
747 T[] content = buildSampleContent();
748 assertTrue(list.addAll(Arrays.asList(content)));
749 exercise(list, content);
750 T[] data = buildArray(0);
751 assertFalse(list.addAll(Arrays.asList(data)));
752 }
753
754 @Test
755 public void testAddAllInt() {
756 for (T s : buildSampleContent()) {
757 List<T> list = buildEmptyList();
758 assertTrue(list.isEmpty());
759 assertTrue(list.addAll(0, Arrays.asList(s)));
760 exercise(list, s);
761 list.clear();
762 }
763 List<T> list = buildEmptyList();
764 T[] content = buildSampleContent();
765 assertTrue(list.addAll(0, Arrays.asList(content)));
766 exercise(list, content);
767 T[] data = buildArray(0);
768 assertFalse(list.addAll(0, Arrays.asList(data)));
769 }
770
771 @Test
772 public void testIllegalAddAllInt() {
773 final T[] illegal = buildIllegalArgumentContent();
774 if (illegal.length <= 0) {
775 // for android.
776 //Assume.assumeTrue(illegal.length > 0);
777 return;
778 }
779 final T[] extra = buildAdditionalContent();
780 if (extra.length <= 0) {
781 // for android.
782 //Assume.assumeTrue(extra.length > 0);
783 return;
784 }
785 final T[] content = buildSampleContent();
786 if (content.length <= 0) {
787 // for android.
788 //Assume.assumeTrue(content.length > 0);
789 return;
790 }
791 T[] toadd = ArrayCopy.copyOf(extra, extra.length + illegal.length);
792 System.arraycopy(illegal, 0, toadd, extra.length, illegal.length);
793
794 // right, we have legal content in 'content', and then in 'illegal' we
795 // have some legal content, and then some illegal content.
796
797 // populate the list.
798 List<T> list = buildEmptyList();
799 assertTrue(list.addAll(0, Arrays.asList(content)));
800 quickCheck(list, content);
801
802 // check that the first to-add can be added.
803 list.add(0, toadd[0]);
804 //then remove it again.
805 assertTrue(toadd[0] == list.remove(0));
806
807 for (int i = 0; i <= content.length; i++) {
808
809 quickCheck(list, content);
810
811 // now, add the illegal, and then inspect the list...
812 try {
813 list.addAll(i, Arrays.asList(toadd));
814 failNoException(IllegalArgumentException.class);
815 } catch (Exception e) {
816 checkException(IllegalArgumentException.class, e);
817 }
818
819 // make sure that the member that previously could be added can
820 // still be added.
821 list.add(0, toadd[0]);
822 //then remove it again.
823 assertTrue(toadd[0] == list.remove(0));
824
825 // make sure it's all OK.
826 exercise(list, content);
827
828 if (content.length < 2) {
829 // for android.
830 // Assume.assumeTrue(content.length >= 2);
831 return;
832 }
833
834 // now check to make sure that concurrency is not affected....
835 Iterator<T> it = list.iterator();
836 // move it along at least once.....
837 assertTrue(content[0] == it.next());
838 // now do a failed addAll.
839 try {
840 list.addAll(i, Arrays.asList(toadd));
841 failNoException(IllegalArgumentException.class);
842 } catch (Exception e) {
843 checkException(IllegalArgumentException.class, e);
844 }
845 // we should be able to move the iteratoe because the modcount should
846 // not have been affected.....
847 assertTrue(content[1] == it.next());
848
849
850
851 }
852
853 }
854
855 @Test
856 public void testClear() {
857 List<T> list = buildEmptyList();
858 assertTrue(list.addAll(Arrays.asList(buildSampleContent())));
859 assertFalse(list.isEmpty());
860 list.clear();
861 assertTrue(list.isEmpty());
862 }
863
864 @Test
865 public void testInsert() {
866 for (T s : buildSampleContent()) {
867 List<T> list = buildEmptyList();
868 assertTrue(list.isEmpty());
869 list.add(0, s);
870 exercise(list, s);
871 }
872 List<T> list = buildEmptyList();
873 T[] content = buildSampleContent();
874 for (T s : content) {
875 list.add(0, s);
876 }
877 exercise(list, arrayReverse(content));
878 list.clear();
879
880 int[] order = shuffle(content.length);
881 T[] mix = buildArray(order.length);
882 for (int i = 0; i < order.length; i++) {
883 mix[i] = content[order[i]];
884 }
885 for (int i = 0; i < content.length; i++) {
886 int pos = 0;
887 for (int j = 0; j < order.length; j++) {
888 if (order[j] < i) {
889 pos++;
890 }
891 if (order[j] == i) {
892 break;
893 }
894 }
895 list.add(pos, content[i]);
896 }
897 exercise(list, mix);
898
899 }
900
901 @Test
902 public void testNullAdd() {
903 if (i_nullok) {
904 List<T> list = buildEmptyList();
905 assertTrue(list.add(null));
906 assertTrue(list.get(0) == null);
907 list.add(1, null);
908 assertTrue(list.get(1) == null);
909 assertTrue(list.addAll(Arrays.asList(buildArray(10))));
910 assertTrue(list.size() == 12);
911 } else {
912 try {
913 List<T> list = buildEmptyList();
914 assertFalse(list.add(null));
915 failNoException(NullPointerException.class);
916 } catch (Exception e) {
917 checkException(NullPointerException.class, e);
918 }
919 try {
920 List<T> list = buildEmptyList();
921 list.add(0, null);
922 failNoException(NullPointerException.class);
923 } catch (Exception e) {
924 checkException(NullPointerException.class, e);
925 }
926
927 try {
928 List<T> list = buildEmptyList();
929 T[] data = buildSampleContent();
930 for (int i = 0; i < data.length; i+= 2) {
931 list.add(data[i]);
932 data[i] = null;
933 }
934 if (data.length == 1) {
935 data[0] = null;
936 }
937 list.addAll(0, Arrays.asList(data));
938 failNoException(NullPointerException.class);
939 } catch (Exception e) {
940 checkException(NullPointerException.class, e);
941 }
942
943 try {
944 List<T> list = buildEmptyList();
945 T[] data = buildSampleContent();
946 for (int i = 0; i < data.length; i+= 2) {
947 list.add(data[i]);
948 data[i] = null;
949 }
950 if (data.length == 1) {
951 data[0] = null;
952 }
953 list.addAll(Arrays.asList(data));
954 failNoException(NullPointerException.class);
955 } catch (Exception e) {
956 checkException(NullPointerException.class, e);
957 }
958
959
960 }
961
962 try {
963 List<T> list = buildEmptyList();
964 Collection<T> data = null;
965 list.addAll(0, data);
966 failNoException(NullPointerException.class);
967 } catch (Exception e) {
968 checkException(NullPointerException.class, e);
969 }
970
971 try {
972 List<T> list = buildEmptyList();
973 Collection<T> data = null;
974 list.addAll(Arrays.asList(buildSampleContent()));
975 list.addAll(data);
976 failNoException(NullPointerException.class);
977 } catch (Exception e) {
978 checkException(NullPointerException.class, e);
979 }
980 }
981
982 @Test
983 public void testIllegalIndex() {
984 T[] data = buildSampleContent();
985 try {
986 List<T> list = buildEmptyList();
987 list.add(-10, data[0]);
988 failNoException(IndexOutOfBoundsException.class);
989 } catch (Exception e) {
990 checkException(IndexOutOfBoundsException.class, e);
991 }
992 try {
993 List<T> list = buildEmptyList();
994 list.add(1, data[0]);
995 failNoException(IndexOutOfBoundsException.class);
996 } catch (Exception e) {
997 checkException(IndexOutOfBoundsException.class, e);
998 }
999 try {
1000 List<T> list = buildEmptyList();
1001 list.addAll(-10, Arrays.asList(data));
1002 failNoException(IndexOutOfBoundsException.class);
1003 } catch (Exception e) {
1004 checkException(IndexOutOfBoundsException.class, e);
1005 }
1006 try {
1007 List<T> list = buildEmptyList();
1008 list.addAll(1, Arrays.asList(data));
1009 failNoException(IndexOutOfBoundsException.class);
1010 } catch (Exception e) {
1011 checkException(IndexOutOfBoundsException.class, e);
1012 }
1013 try {
1014 List<T> list = buildEmptyList();
1015 list.set(-1, data[0]);
1016 failNoException(IndexOutOfBoundsException.class);
1017 } catch (Exception e) {
1018 checkException(IndexOutOfBoundsException.class, e);
1019 }
1020 try {
1021 List<T> list = buildEmptyList();
1022 list.set(1, data[0]);
1023 failNoException(IndexOutOfBoundsException.class);
1024 } catch (Exception e) {
1025 checkException(IndexOutOfBoundsException.class, e);
1026 }
1027 try {
1028 List<T> list = buildEmptyList();
1029 list.get(-1);
1030 failNoException(IndexOutOfBoundsException.class);
1031 } catch (Exception e) {
1032 checkException(IndexOutOfBoundsException.class, e);
1033 }
1034 try {
1035 List<T> list = buildEmptyList();
1036 list.get(1);
1037 failNoException(IndexOutOfBoundsException.class);
1038 } catch (Exception e) {
1039 checkException(IndexOutOfBoundsException.class, e);
1040 }
1041
1042 try {
1043 List<T> list = buildEmptyList();
1044 list.remove(-10);
1045 failNoException(IndexOutOfBoundsException.class);
1046 } catch (Exception e) {
1047 checkException(IndexOutOfBoundsException.class, e);
1048 }
1049 try {
1050 List<T> list = buildEmptyList();
1051 list.remove(1);
1052 failNoException(IndexOutOfBoundsException.class);
1053 } catch (Exception e) {
1054 checkException(IndexOutOfBoundsException.class, e);
1055 }
1056 }
1057
1058 @Test
1059 public void testRemove() {
1060 for (T s : buildSampleContent()) {
1061 List<T> list = buildEmptyList();
1062 assertTrue(list.isEmpty());
1063 assertTrue(list.add(s));
1064 exercise(list, s);
1065 assertTrue(list.remove(0) == s);
1066 exercise(list);
1067 }
1068 T[] samplecontent = buildSampleContent();
1069 for (int i = 0; i < samplecontent.length; i++) {
1070 T[] content = samplecontent;
1071 List<T> list = buildEmptyList();
1072 for (T s : content) {
1073 assertTrue(list.add(s));
1074 }
1075 exercise(list, content);
1076 assertTrue(content[i] == list.remove(i));
1077 content = arrayRemove(content, i);
1078 exercise(list, content);
1079
1080 while (list.size() > i) {
1081 assertTrue(content[i] == list.remove(i));
1082 content = arrayRemove(content, i);
1083 }
1084 while (!list.isEmpty()) {
1085 assertTrue(content[content.length -1] == list.remove(list.size() - 1));
1086 content = arrayRemove(content, content.length - 1);
1087 }
1088 assertTrue(list.isEmpty());
1089 }
1090 List<T> list = buildEmptyList();
1091 for (T s : samplecontent) {
1092 assertTrue(list.add(s));
1093 }
1094 exercise(list, samplecontent);
1095 if (i_nullok) {
1096 list = buildEmptyList();
1097 assertTrue(list.add(null));
1098 assertTrue(list.get(0) == null);
1099 }
1100 }
1101
1102
1103 @Test
1104 public void testIllegalArgumentContent() {
1105 for (T d : buildIllegalArgumentContent()) {
1106 List<T> list = buildEmptyList();
1107 T[] content = buildSampleContent();
1108 for (T i : content) {
1109 list.add(i);
1110 }
1111 illegalExercise(list, content, d, IllegalArgumentException.class);
1112 }
1113 }
1114
1115 @Test
1116 public void testIllegalClassContent() {
1117 for (Object d : buildIllegalClassContent()) {
1118 List<T> list = buildEmptyList();
1119 T[] content = buildSampleContent();
1120 for (T i : content) {
1121 list.add(i);
1122 }
1123 illegalExercise(list, content, (T)d, ClassCastException.class);
1124 }
1125 }
1126
1127 @Test
1128 public void testNullContent() {
1129 if (i_nullok) {
1130 return;
1131 }
1132 List<T> list = buildEmptyList();
1133 T[] content = buildSampleContent();
1134 for (T i : content) {
1135 list.add(i);
1136 }
1137 illegalExercise(list, content, (T)null, NullPointerException.class);
1138 }
1139
1140
1141 @Test
1142 public void testConcurrentMod() {
1143 List<T> list = buildEmptyList();
1144
1145 T[] sample = buildSampleContent();
1146 assertTrue("Not enough sample data " + sample.length, sample.length > 2);
1147
1148 list.add(sample[0]);
1149
1150 ListIterator<T> it = list.listIterator();
1151 Iterator<T> si = list.iterator();
1152
1153 // It is important to add some content, and do a next()
1154 // before testing concurrency, because some iterator methods
1155 // check for the Iterator state before checking concurrency.
1156 // this puts the iterator in to a valid state for remove(), set(), etc.
1157 assertTrue(sample[0] == it.next());
1158 assertTrue(sample[0] == si.next());
1159
1160 // create a concurrent issue.
1161 // we have checked for more than 2 elements so this should be fine.
1162 list.add(sample[1]);
1163 list.add(sample[2]);
1164
1165 // hasNext() should never throw CME.
1166 assertTrue(it.hasNext());
1167 assertTrue(1 == it.nextIndex());
1168
1169 // hasNext() should never throw CME.
1170 assertTrue(it.hasNext());
1171 try {
1172 it.next();
1173 failNoException(ConcurrentModificationException.class);
1174 } catch (Exception e) {
1175 checkException(ConcurrentModificationException.class, e);
1176 }
1177
1178
1179 it = list.listIterator(3);
1180 assertTrue(sample[2] == it.previous());
1181
1182 // create a concurrent issue.
1183 list.remove(2);
1184
1185 // hasPrevious() should never throw CME.
1186 assertTrue(it.hasPrevious());
1187
1188 assertTrue(1 == it.previousIndex());
1189
1190 // hasPrevious() should never throw CME.
1191 assertTrue(it.hasPrevious());
1192 try {
1193 it.previous();
1194 failNoException(ConcurrentModificationException.class);
1195 } catch (Exception e) {
1196 checkException(ConcurrentModificationException.class, e);
1197 }
1198
1199 // hasPrevious() should never throw CME.
1200 assertTrue(it.hasPrevious());
1201 try {
1202 it.set(sample[sample.length - 1]);
1203 failNoException(ConcurrentModificationException.class);
1204 } catch (Exception e) {
1205 checkException(ConcurrentModificationException.class, e);
1206 }
1207
1208 // hasPrevious() should never throw CME.
1209 assertTrue(it.hasPrevious());
1210 try {
1211 it.add(sample[sample.length - 1]);
1212 failNoException(ConcurrentModificationException.class);
1213 } catch (Exception e) {
1214 checkException(ConcurrentModificationException.class, e);
1215 }
1216
1217 // hasPrevious() should never throw CME.
1218 assertTrue(it.hasPrevious());
1219 try {
1220 it.remove();
1221 failNoException(ConcurrentModificationException.class);
1222 } catch (Exception e) {
1223 checkException(ConcurrentModificationException.class, e);
1224 }
1225
1226
1227
1228 // Now test the Simple Iterator concurrency
1229
1230 // hasNext() should never throw CME.
1231 assertTrue(si.hasNext());
1232
1233 try {
1234 si.next();
1235 failNoException(ConcurrentModificationException.class);
1236 } catch (Exception e) {
1237 checkException(ConcurrentModificationException.class, e);
1238 }
1239
1240 try {
1241 si.remove();
1242 failNoException(ConcurrentModificationException.class);
1243 } catch (Exception e) {
1244 checkException(ConcurrentModificationException.class, e);
1245 }
1246
1247 }
1248
1249 @Test
1250 public void testConcurrentSetMod() {
1251 List<T> list = buildEmptyList();
1252
1253 T[] sample = buildSampleContent();
1254 assertTrue("Not enough sample data " + sample.length, sample.length > 2);
1255
1256 list.addAll(Arrays.asList(sample));
1257 quickCheck(list, sample);
1258
1259 T tmp = list.remove(0);
1260
1261 T[] tmpsamp = ArrayCopy.copyOfRange(sample, 1, sample.length);
1262 quickCheck(list, tmpsamp);
1263
1264 // get a handle on our iterator....
1265 ListIterator<T> it = list.listIterator();
1266
1267 // make sure a set of the underlying does not effect the iterator.
1268 tmpsamp[0] = tmp;
1269 list.set(0, tmp);
1270 quickCheck(list, tmpsamp);
1271
1272 // next() should not throw CME because set() should not change modCount.
1273 assertTrue(tmp == it.next());
1274
1275 // then, for kicks, restore the original list with
1276 it.add(sample[1]);
1277 quickCheck(list, sample);
1278 }
1279
1280
1281 }
0 package org.jdom.test.util;
1
2 import java.io.InputStream;
3 import java.net.URL;
4 import java.util.concurrent.atomic.AtomicReference;
5
6 /**
7 * Android does not have a reliable ClassLoader.getResource() set of methods.
8 * We do a poor-man's hack that works on Android too.
9 * On Android, we need to make a new class org.jdom.test.util.AndroidFetch.
10 *
11 * @author Rolf Lear
12 *
13 */
14
15 public class FidoFetch {
16
17 /**
18 * @param name The resource name to get.
19 * @return The URL to the name.
20 */
21 public URL getURL(String name) {
22 return this.getClass().getResource(name);
23 }
24
25 /**
26 * @param name The resource name to get.
27 * @return The Resource as a stream
28 */
29 public InputStream getStream(String name) {
30 return this.getClass().getResourceAsStream(name);
31 }
32
33 private static final AtomicReference<FidoFetch> fetch = new AtomicReference<FidoFetch>();
34
35 /**
36 * A singleton instance type method.
37 * @return the singleton Fido instance.
38 */
39 public static final FidoFetch getFido() {
40 FidoFetch ret = fetch.get();
41 if (ret == null) {
42 // if ("Dalvik".equalsIgnoreCase(System.getProperty("java.vm.name", "junk"))) {
43 // ret = ReflectionConstructor.construct("org.jdom.test.util.AndroidFetch", FidoFetch.class);
44 // } else {
45 ret = new FidoFetch();
46 // }
47 fetch.set(ret);
48 }
49 return ret;
50 }
51
52 }
0 package org.jdom.test.util;
1
2 import java.util.ArrayList;
3 import java.util.List;
4
5 @SuppressWarnings("javadoc")
6 public final class ListTest extends AbstractTestList<Integer> {
7
8 public ListTest() {
9 super(Integer.class, true);
10 }
11
12 @Override
13 public List<Integer> buildEmptyList() {
14 return new ArrayList<Integer>();
15 }
16
17 @Override
18 public Integer[] buildSampleContent() {
19 return new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
20 }
21
22 @Override
23 public Object[] buildIllegalClassContent() {
24 return new Object[]{};
25 }
26
27 @Override
28 public Integer[] buildIllegalArgumentContent() {
29 return new Integer[0];
30 }
31
32 @Override
33 public Integer[] buildAdditionalContent() {
34 return new Integer[0];
35 }
36
37 }
0 package org.jdom.test.util;
1
2 import static org.junit.Assert.assertEquals;
3 import static org.junit.Assert.assertFalse;
4 import static org.junit.Assert.assertNotNull;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7
8 import java.io.ByteArrayInputStream;
9 import java.io.ByteArrayOutputStream;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.io.ObjectInputStream;
13 import java.io.ObjectOutputStream;
14 import java.io.Serializable;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Comparator;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.NoSuchElementException;
21 import java.util.concurrent.atomic.AtomicBoolean;
22
23 import org.jdom.Attribute;
24 import org.jdom.Comment;
25 import org.jdom.Content;
26 import org.jdom.DocType;
27 import org.jdom.Document;
28 import org.jdom.Element;
29 import org.jdom.EntityRef;
30 import org.jdom.Namespace;
31 import org.jdom.NamespaceAware;
32 import org.jdom.ProcessingInstruction;
33
34 @SuppressWarnings("javadoc")
35 public class UnitTestUtil {
36
37 private static final AtomicBoolean isandroid = new AtomicBoolean(false);
38
39 public static final void setAndroid() {
40 isandroid.set(true);
41 }
42
43 public static final void testNamespaceIntro(NamespaceAware content, Namespace...expect) {
44 List<Namespace> intro = content.getNamespacesIntroduced();
45 List<Namespace> exp = Arrays.asList(expect);
46
47 if (!exp.equals(intro)) {
48 fail("We expect Introduced equal the Expected Namespaces." +
49 "\n Introduced: " + intro.toString() +
50 "\n Expected: " + exp.toString());
51 }
52 }
53
54 public static final void testNamespaceScope(NamespaceAware content, Namespace...expect) {
55 List<Namespace> introduced = content.getNamespacesIntroduced();
56 List<Namespace> inscope = new ArrayList<Namespace>(content.getNamespacesInScope());
57 List<Namespace> inherited = content.getNamespacesInherited();
58
59 if (introduced.size() + inherited.size() != inscope.size()) {
60 fail(String.format("InScope Namespaces do not add up: InScope=%d Inherited=%d, Introduced=%d",
61 inscope.size(), inherited.size(), introduced.size()));
62 }
63 int inher = 0;
64 int intro = 0;
65 for (Namespace ns : inscope) {
66 if (inher < inherited.size() && inherited.get(inher) == ns) {
67 inher++;
68 }
69 if (intro < introduced.size() && introduced.get(intro) == ns) {
70 intro++;
71 }
72 }
73 if (intro < introduced.size()) {
74 // we are missing content(or it is out of order) in the lists.
75 fail("Introduced list contains out-of-order, or non-intersecting Namespaces." +
76 "\n InScope: " + inscope.toString() +
77 "\n Introduced: " + introduced.toString());
78 }
79 if (inher < inherited.size()) {
80 // we are missing content(or it is out of order) in the lists.
81 fail("Inherited list contains out-of-order, or non-intersecting Namespaces." +
82 "\n InScope: " + inscope.toString() +
83 "\n Inherited: " + inherited.toString());
84 }
85
86
87 int i = 0;
88 for (Namespace ns : inscope) {
89 if (i >= expect.length) {
90 fail("We have additional Namespaces " + inscope.subList(i, inscope.size()));
91 }
92 if (expect[i] != ns) {
93 assertEquals("InScope differs from Expected at index " + i, expect[i], ns);
94 }
95 i++;
96 }
97 if (i < expect.length) {
98 ArrayList<Namespace> missing = new ArrayList<Namespace>(expect.length - i);
99 while (i < expect.length) {
100 missing.add(expect[i++]);
101 }
102 fail("InScope is missing Namespaces " + missing);
103 }
104
105 inscope.removeAll(introduced);
106 if (!inscope.equals(inherited)) {
107 fail("We expect InScope - Introduced to equal Inherited." +
108 "\n InScope: " + inscope.toString() +
109 "\n Inherited: " + inherited.toString());
110 }
111
112 }
113
114 /**
115 * Serialize, then deserialize an instance object.
116 * @param tclass
117 * @param input
118 * @return
119 */
120 public static final <T extends Serializable> T deSerialize(final T input) {
121 if (input == null) {
122 return null;
123 }
124 final Class<?> tclass = input.getClass();
125 final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
126 try {
127 final ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
128 try {
129 objectOutputStream.writeObject(input);
130 }
131 catch(final IOException ioException) {
132 failException("Unable to serialize object.", ioException);
133 }
134 finally {
135 try {
136 objectOutputStream.close();
137 }
138 catch(final IOException ioException) {
139 failException("failed to close object stream while serializing object", ioException);
140 }
141 }
142 }
143 catch(final IOException ioException) {
144 failException("unable to serialize object", ioException);
145 }
146 finally {
147 try {
148 outputStream.close();
149 }
150 catch(final IOException ioException) {
151 failException("failed to close output stream while serializing object", ioException);
152 }
153 }
154
155 final byte[] bytes = outputStream.toByteArray();
156
157 Object o = null;
158
159 final InputStream inputStream = new ByteArrayInputStream(bytes);
160 try {
161 final ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
162 try {
163 o = objectInputStream.readObject();
164 }
165 finally {
166 try {
167 objectInputStream.close();
168 }
169 catch(final IOException ioException) {
170 failException("failed to close object stream while deserializing object", ioException);
171 }
172 }
173 }
174 catch(final IOException ioException) {
175 failException("unable to deserialize object.", ioException);
176 }
177 catch(final ClassNotFoundException classNotFoundException) {
178 failException("unable to deserialize object.", classNotFoundException);
179 }
180 finally {
181 try{
182 inputStream.close();
183 }
184 catch(final IOException ioException) {
185 failException("failed to close output stream while serializing object.", ioException);
186 }
187 }
188
189 assertTrue("Deserialized (non-null) object is null!", o != null);
190
191 @SuppressWarnings("unchecked")
192 final T t = (T)tclass.cast(o);
193
194 assertTrue("Deserialized instance should not be the same instance as the pre-serialization",
195 t != input);
196
197 return t;
198
199 }
200
201 /**
202 * Attribute order is not significant in XML documents.
203 * This method re-arranges the order of the Attributes (in somewhat
204 * alphabetical order, but that's not important) so that you can easily
205 * compare the attribute content of two different elements.
206 * @param emt The element who's Attributes we should rearrange.
207 */
208 public static final void normalizeAttributes(Element emt) {
209 if (!emt.hasAttributes()) {
210 return;
211 }
212 emt.sortAttributes(new Comparator<Attribute>() {
213 @Override
214 public int compare(Attribute o1, Attribute o2) {
215 return o1.getQualifiedName().compareTo(o2.getQualifiedName());
216 }
217 });
218 for (Object o : emt.getChildren()) {
219 normalizeAttributes((Element)o);
220 }
221 }
222
223
224 /**
225 * Test whether two values are equals, in addition, check the hashCode() values
226 * This method will pass if both values are null.
227 * @param a The first value to check
228 * @param b The other value
229 */
230 public static final void checkEquals(Object a, Object b) {
231 if (a == null) {
232 if (b != null) {
233 fail("Second value is not null like the first: " + b.toString());
234 }
235 return;
236 }
237 if (b == null) {
238 fail ("First value is not null like the second: " + a.toString());
239 }
240 assertTrue(a.equals(a));
241 assertTrue(b.equals(b));
242 if (!a.equals(b)) {
243 fail("First value '" + a + "' does not equals() second value '" + b + "'.");
244 }
245 if (!b.equals(a)) {
246 fail("Second value '" + b + "' does not equals() first value '" + a + "'.");
247 }
248 if (a.hashCode() != b.hashCode()) {
249 fail("Hashcodes of equals() values are different. " +
250 "First value '" + a + "' (hashcode=" + a.hashCode() + ") " +
251 "not same as " +
252 "second value '" + b + "' (hashcode=" + b.hashCode() + ").");
253 }
254 }
255
256 public static final void testReadIterator(Iterator<?> it, Object ... values) {
257 assertTrue(it != null);
258 assertTrue(values != null);
259 for (int i = 0; i < values.length; i++) {
260 assertTrue(it.hasNext());
261 assertTrue(values[i] == it.next());
262 }
263 assertFalse("Not enough values in the test set.", it.hasNext());
264 try {
265 it.next();
266 fail("Should not be able to have next after values have run out.");
267 } catch (NoSuchElementException nsee) {
268 // the way it should be
269 } catch (Exception e) {
270 fail("next() should fail with NoSuchElementException, not " + e.getClass().getName());
271 }
272
273 }
274
275 /**
276 * Create a new String instance based on an input String.
277 * The String class tends to have these fancy ways of re-using internal
278 * data structures when creating one string from another. This method
279 * circumvents those optimisations.
280 * @param value The value to clone
281 * @return The cloned version of the input value.
282 */
283 public static final String cloneString(String value) {
284 char[] chars = value.toCharArray();
285 char[] ret = new char[chars.length];
286 System.arraycopy(chars, 0, ret, 0, chars.length);
287 return new String(ret);
288 }
289
290 /**
291 * Provide a standard way to fail when we expect an exception but did not
292 * get one...
293 */
294 public static final void failNoException(Class<? extends Throwable> expect) {
295 fail("This code was expected to produce the exception " +
296 expect.getName() + " but it was not thrown.");
297 }
298
299 /**
300 * Provide a standard test for checking for an exception.
301 * @param expect
302 * @param got
303 */
304 public static final void checkException(Class<? extends Throwable> expect,
305 Throwable got) {
306 if (expect == null) {
307 fail("We can't expect a null exception (cryptic enough?)");
308 }
309 if (got == null) {
310 fail("We expected an exception of type " + expect.getName() +
311 " but got a null value instead");
312 }
313 if (!expect.isInstance(got)) {
314 AssertionError ae = new AssertionError(
315 "We expected an exception of type " + expect.getName() +
316 " but got a " + got.getClass().getName() +
317 " instead with message " + got.getMessage());
318 if (isandroid.get()) {
319 System.out.println("ANDROID: About to throw AssertionError " +
320 "but we cannot initialize the cause... " +
321 "Here follows both the AssertionError and its cause");
322 ae.printStackTrace();
323 System.out.println("And the cause...");
324 got.printStackTrace();
325 } else {
326 ae.initCause(got);
327 }
328 throw ae;
329 }
330 }
331
332 /**
333 * Call this if you have an exception you want to fail for!
334 * @param message
335 * @param got this exception
336 */
337 public static void failException(String message, Throwable got) {
338 AssertionError ae = new AssertionError(message);
339 if (isandroid.get()) {
340 System.out.println("ANDROID: About to throw AssertionError " +
341 "but we cannot initialize the cause... " +
342 "Here follows both the AssertionError and its cause");
343 ae.printStackTrace();
344 System.out.println("And the cause...");
345 got.printStackTrace();
346 } else {
347 ae.initCause(got);
348 }
349 throw ae;
350 }
351
352 public static final void compare(final NamespaceAware ap, final NamespaceAware bp) {
353 assertNotNull(ap);
354 assertNotNull(bp);
355 assertEquals(ap.getClass(), bp.getClass());
356 assertTrue(ap != bp);
357 if (ap instanceof Content) {
358 final Content a = (Content)ap;
359 final Content b = (Content)bp;
360 if (a.getParent() != null) {
361 assertTrue(a.getParent() != b.getParent());
362 }
363
364 switch (a.getCType()) {
365 case Text:
366 assertEquals(a.getValue(), b.getValue());
367 break;
368 case CDATA:
369 assertEquals(a.getValue(), b.getValue());
370 break;
371 case Comment:
372 assertEquals(((Comment)a).getText(), ((Comment)b).getText());
373 break;
374 case DocType:
375 DocType da = (DocType)a;
376 DocType db = (DocType)b;
377 assertEquals(da.getElementName(), db.getElementName());
378 assertEquals(da.getPublicID(), db.getPublicID());
379 assertEquals(da.getSystemID(), db.getSystemID());
380 assertEquals(da.getInternalSubset(), db.getInternalSubset());
381 break;
382 case Element:
383 Element ea = (Element)a;
384 Element eb = (Element)b;
385 assertEquals(ea.getName(), eb.getName());
386 compare(ea.getAttributes(), eb.getAttributes());
387 assertEquals(ea.getNamespacesInScope(), eb.getNamespacesInScope());
388 final int sz = ea.getContentSize();
389 assertTrue(sz == eb.getContentSize());
390 for (int i = 0; i < sz; i++) {
391 compare(ea.getContent(i), eb.getContent(i));
392 }
393 break;
394 case EntityRef:
395 assertEquals(((EntityRef)a).getName(), ((EntityRef)b).getName());
396 break;
397 case ProcessingInstruction:
398 ProcessingInstruction pa = (ProcessingInstruction)a;
399 ProcessingInstruction pb = (ProcessingInstruction)b;
400 assertEquals(pa.getTarget(), pb.getTarget());
401 assertEquals(pa.getData(), pb.getData());
402 break;
403 }
404 } else if (ap instanceof Attribute) {
405 compare ((Attribute)ap, (Attribute)bp);
406 } else if (ap instanceof Document) {
407 Document a = (Document)ap;
408 Document b = (Document)bp;
409 assertEquals(a.getBaseURI(), b.getBaseURI());
410 final int sz = a.getContentSize();
411 assertTrue(sz == b.getContentSize());
412 for (int i = 0; i < sz; i++) {
413 compare(a.getContent(i), b.getContent(i));
414 }
415 }
416 }
417
418
419 public static final void compare(List<Attribute> a, List<Attribute> b) {
420 assertTrue(a != b);
421 assertTrue(a.size() == b.size());
422 Iterator<Attribute> ait = a.iterator();
423 Iterator<Attribute> bit = b.iterator();
424 while (ait.hasNext() && bit.hasNext()) {
425 Attribute aa = ait.next();
426 Attribute bb = bit.next();
427 compare(aa, bb);
428 }
429 assertFalse(ait.hasNext());
430 assertFalse(bit.hasNext());
431
432 }
433
434
435 public static final void compare(Attribute aa, Attribute bb) {
436 assertEquals(aa.getName(), bb.getName());
437 assertTrue(aa.getNamespace() == bb.getNamespace());
438 assertEquals(aa.getValue(), bb.getValue());
439 }
440
441
442 }
0 package org.jdom.test.util;
1
2 import java.lang.reflect.InvocationTargetException;
3 import java.lang.reflect.Method;
4 import java.lang.reflect.Modifier;
5 import java.lang.reflect.Type;
6
7 import org.jdom.Verifier;
8 import org.jdom.internal.ArrayCopy;
9
10 /**
11 * This class builds jUnitTestCases for the Verifier character classes.
12 * It is based on the JDOM 1.1.1 verifier. Whatever that verifier accepted,
13 * this one will too. In other words, it is for regression purposes only, not
14 * reference.
15 * @author Rolf Lear
16 *
17 */
18 public class VerifierTestBuilder {
19
20 /**
21 * @param args
22 * @throws InvocationTargetException
23 * @throws IllegalAccessException
24 * @throws IllegalArgumentException
25 */
26 public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
27 Class<Verifier> vclass = Verifier.class;
28
29 // Hunt for all Verifier methods that are of the form static boolean ...(char)
30 for (Method meth : vclass.getMethods()) {
31 if (meth.getReturnType() != Boolean.TYPE) {
32 // we only want methods that return boolean.
33 continue;
34 }
35 Type[] types = meth.getParameterTypes();
36 if (types.length != 1 || types[0] != Character.TYPE) {
37 // we want methods that take a single char argument
38 continue;
39 }
40 if (!Modifier.isPublic(meth.getModifiers()) || !Modifier.isStatic(meth.getModifiers())) {
41 // we want the public static methods only
42 continue;
43 }
44
45 String mname = meth.getName();
46
47 boolean valid = false;
48 boolean q = false;
49 int[] flips = new int[1024];
50 int flen = 0;
51
52 for (char i = 0; i < Character.MAX_VALUE; i++) {
53 q = (Boolean)meth.invoke(null, Character.valueOf(i));
54 if (q != valid) {
55 valid = q;
56 if (flen >= flips.length) {
57 flips = ArrayCopy.copyOf(flips, flen + 1024);
58 }
59 flips[flen++] = i;
60 }
61 }
62
63 buildTest(mname, ArrayCopy.copyOf(flips, flen));
64 }
65 }
66
67 private static final void buildTest(final String mname, int[] flips) {
68
69 final String tname = "test" + mname.substring(0, 1).toUpperCase() + mname.substring(1);
70
71 StringBuilder sb = new StringBuilder();
72 appendLine(0, sb, "");
73 appendLine(1, sb, "// Automated test built by VerifierTestBuilder");
74 appendLine(1, sb, "@Test");
75
76 appendLine(1, sb, "public void ", tname ,"() {");
77 appendLine(2, sb, "final int[] flips = new int[] {");
78 for (int i = 0; i < flips.length; i++) {
79 if ((i & 0x0f) == 0) {
80 sb.append("\n\t\t\t\t");
81 }
82 sb.append(String.format(" 0x%04x,", flips[i]));
83 }
84 sb.setCharAt(sb.length() - 1, '\n');
85 appendLine(2, sb, "};");
86 appendLine(2, sb, "int c = 0;");
87 appendLine(2, sb, "int fcnt = 0;");
88 appendLine(2, sb, "boolean valid = false;");
89 appendLine(2, sb, "final long ms = System.currentTimeMillis();");
90
91 appendLine(2, sb, "while (c <= Character.MAX_VALUE) {");
92 appendLine(3, sb, "if (fcnt < flips.length && flips[fcnt] == c) {");
93 appendLine(4, sb, "valid = !valid;");
94 appendLine(4, sb, "fcnt++;");
95 appendLine(3, sb, "}");
96 appendLine(3, sb, "if (valid) {");
97 appendLine(4, sb, "if (!Verifier." + mname + "((char)c)) {");
98 appendLine(5, sb, "fail(\"Expected char 0x\" + Integer.toHexString(c) + \" to pass " + mname + " but it failed.\");");
99 appendLine(4, sb, "}");
100 appendLine(3, sb, "} else {");
101 appendLine(4, sb, "if (Verifier." + mname + "((char)c)) {");
102 appendLine(5, sb, "fail(\"Expected char 0x\" + Integer.toHexString(c) + \" to fail " + mname + " but it passed.\");");
103 appendLine(4, sb, "}");
104 appendLine(3, sb, "}");
105 appendLine(3, sb, "c++;");
106 appendLine(2, sb, "}");
107 appendLine(2, sb, "System.out.printf(\"Completed test", tname, "in %dms\\n\", System.currentTimeMillis() - ms);");
108
109 appendLine(1, sb, "}");
110 System.out.println(sb);
111 }
112
113 private static final void appendLine(int indent, StringBuilder sb, String...vals) {
114 while (--indent >= 0) {
115 sb.append("\t");
116 }
117 for (String s : vals) {
118 sb.append(s).append(" ");
119 }
120 sb.setCharAt(sb.length() - 1, '\n');
121 }
122
123 }
0 <root att1="val1" att2="val2" />
0 <root att1="val1" att2="val2" >
1 <child att="child1" />
2 <child att="child2" />
3 <child att="child3" />
4 <child att="child4" />
5 <child att="child5" />
6 </root>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!-- root comment -->
2
3 <?jdomtest root level ?>
4
5 <root att1="val1" att2="val2" >
6 text
7 <child att="child1" xml:space="preserve"> hello Frodo Baggins! </child>
8 <child att="child2" />
9 <?jdomtest processing instruction ?>
10 <child att="child3" />
11 <!-- comment -->
12 <child att="child4" unresolved="&amp;"/>
13 <child att="child5" > <![CDATA[some cdata text ]]> </child>
14 <child att="child6" >
15 <leaf att="Leaf6" />
16 </child>
17 </root>
18
19
20
0 <?xml version="1.0" ?>
1 <!DOCTYPE root [<!ELEMENT root (#PCDATA)><!ENTITY xpd 'Expand Me!' >]>
2 <root>&xpd;</root>
0 <?xml version="1.0" ?>
1 <!DOCTYPE root [] >
2 <root />
0 <root xmlns="rootns" xmlns:ans="attns" xmlns:cns="childns" att1="val1" ans:att2="val2" >
1 <child xmlns="" att="child1" />
2 <child att="child2" />
3 <cns:child att="child3" />
4 <child ans:att="child4" />
5 <child att="child5" />
6 </root>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--the external dtd with comments -->
2 <!ELEMENT internalentities (#PCDATA)>
3 <!ATTLIST internalentities test CDATA #IMPLIED>
4 <!ATTLIST internalentities image ENTITY #REQUIRED>
5 <!ENTITY didsimple 'simple entity' >
6 <!ENTITY dtdsimple2 'another simple entity'>
7 <!ENTITY % param '<!ELEMENT test (#PCDATA)>' >
8 <!-- dtd closing comment -->
9
0 <?xml version="1.0" ?>
1 <!DOCTYPE internalentities SYSTEM "SAXBuilderTestDecl.dtd" [
2 <!--the internal subset -->
3 <!NOTATION n1 SYSTEM "http://www.w3.org/">
4 <!NOTATION n2 PUBLIC "//foo/foo" "http://www.w3.org/">
5
6 <!ENTITY simple 'simple entity' >
7 <!ENTITY simple2 'another simple entity'>
8 <!ENTITY annotation SYSTEM "http://www.foo.org/image.gif" NDATA n1 >
9
10
11 ]>
12
13 <internalentities test="foo" image="annotation">&simple; &simple2;
14 </internalentities>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!ELEMENT internalentites (#PCDATA)>
2 <!ATTLIST internalentities
3 test (CDATA) #IMPLIED>
4 <!ENTITY simple 'simple entity' >
5 <!ENTITY simple2 'another simple entity'>
6
0 <?xml version="1.0" ?>
1 <!DOCTYPE internalentities [
2 <!ELEMENT internalentites (#PCDATA)>
3 <!ATTLIST internalentities
4 test (CDATA) #IMPLIED>
5 <!ATTLIST internalentities
6 test2 (A|B) #IMPLIED>
7 <!ATTLIST internalentities a NOTATION (n1|n2) #IMPLIED>
8 <!NOTATION n1 SYSTEM "http://www.w3.org/">
9 <!NOTATION n2 SYSTEM "http://www.w3.org/">
10
11 <!ENTITY simple 'simple entity' >
12 <!ENTITY simple2 'another simple entity'>
13 <!ENTITY anotation SYSTEM "http://www.foo.org/image.gif" NDATA n1 >
14
15 ]>
16
17 <internalentities test="boo">&simple; &simple2;
18 </internalentities>
0 <?xml version="1.0" ?>
1 <!DOCTYPE internalentities SYSTEM "SAXBuilderTestEntity.dtd">
2
3 <internalentities test="foo">&simple; &simple2;
4 </internalentities>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!DOCTYPE application SYSTEM "test.dtd"
2 [
3 <!ENTITY rdquo "internal">
4 <!ENTITY % local.p.class "fff">
5 <!-- comment3 -->
6 ]
7 >
8 <application>&rdquo;
9 <!-- comment -->
10 <display-name>MainIndex</display-name>
11 &ldquo;
12 </application>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ENTITY unres 'Expand Me!' > ] >
2 <root att1="val1" att2="val2" >
3 text
4 <child att="child1" xml:space="preserve"> hello Frodo Baggins! </child>
5 <child att="child2" />
6 <?jdomtest processing instruction ?>
7 <child att="child3" />
8 <child xmlns="childns" att="childns 1">
9 <!-- ns comment 1 -->
10 </child>
11 <!-- comment -->
12 <child att="child4" unresolved="&amp;"/>
13 <ns:child xmlns:ns="childns" att="childns 2" ns:att="childns 2">
14 <!-- ns comment 2 -->
15 <?jdomtest processing instruction ?>
16 </ns:child>
17 &unres; some unresolved content.
18 <child att="child5" > <![CDATA[some cdata text ]]> </child>
19 <child att="child6" >
20 <leaf att="Leaf6" />
21 </child>
22 </root>
23
24
25
0 <!ELEMENT application (display-name)>
1 <!-- comment2 -->
2 <!ELEMENT display-name (#PCDATA)>
3 <!ENTITY ldquo "external">
4 <!ENTITY ext SYSTEM "entity.txt">
5 <!ENTITY % ext.statusp.class "uuu">
0 <?xml version="1.0" ?>
1 <xmlchars>
2 <prodgroup pcw3="3" pcw4="15">
3 <prod id="NT-Char">
4 <lhs>Char</lhs><rhs>#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]</rhs>
5 </prod>
6
7 <prod id="NT-Letter">
8 <lhs>Letter</lhs><rhs><nt def="NT-BaseChar">BaseChar</nt> | <nt def="NT-Ideographic">Ideographic</nt></rhs>
9 </prod>
10 <prod id="NT-BaseChar">
11 <lhs>BaseChar</lhs><rhs>[#x0041-#x005A] |[#x0061-#x007A] |[#x00C0-#x00D6]
12 |[#x00D8-#x00F6] |[#x00F8-#x00FF] |[#x0100-#x0131] |[#x0134-#x013E]
13 |[#x0141-#x0148] |[#x014A-#x017E] |[#x0180-#x01C3] |[#x01CD-#x01F0]
14 |[#x01F4-#x01F5] |[#x01FA-#x0217] |[#x0250-#x02A8] |[#x02BB-#x02C1]
15 |#x0386 |[#x0388-#x038A] |#x038C |[#x038E-#x03A1]
16 |[#x03A3-#x03CE] |[#x03D0-#x03D6] |#x03DA |#x03DC
17 |#x03DE |#x03E0 |[#x03E2-#x03F3] |[#x0401-#x040C]
18 |[#x040E-#x044F] |[#x0451-#x045C] |[#x045E-#x0481] |[#x0490-#x04C4]
19 |[#x04C7-#x04C8] |[#x04CB-#x04CC] |[#x04D0-#x04EB] |[#x04EE-#x04F5]
20 |[#x04F8-#x04F9] |[#x0531-#x0556] |#x0559 |[#x0561-#x0586]
21 |[#x05D0-#x05EA] |[#x05F0-#x05F2] |[#x0621-#x063A] |[#x0641-#x064A]
22 |[#x0671-#x06B7] |[#x06BA-#x06BE] |[#x06C0-#x06CE] |[#x06D0-#x06D3]
23 |#x06D5 |[#x06E5-#x06E6] |[#x0905-#x0939] |#x093D
24 |[#x0958-#x0961] |[#x0985-#x098C] |[#x098F-#x0990] |[#x0993-#x09A8]
25 |[#x09AA-#x09B0] |#x09B2 |[#x09B6-#x09B9] |[#x09DC-#x09DD]
26 |[#x09DF-#x09E1] |[#x09F0-#x09F1] |[#x0A05-#x0A0A] |[#x0A0F-#x0A10]
27 |[#x0A13-#x0A28] |[#x0A2A-#x0A30] |[#x0A32-#x0A33] |[#x0A35-#x0A36]
28 |[#x0A38-#x0A39] |[#x0A59-#x0A5C] |#x0A5E |[#x0A72-#x0A74]
29 |[#x0A85-#x0A8B] |#x0A8D |[#x0A8F-#x0A91] |[#x0A93-#x0AA8]
30 |[#x0AAA-#x0AB0] |[#x0AB2-#x0AB3] |[#x0AB5-#x0AB9] |#x0ABD
31 |#x0AE0 |[#x0B05-#x0B0C] |[#x0B0F-#x0B10] |[#x0B13-#x0B28]
32 |[#x0B2A-#x0B30] |[#x0B32-#x0B33] |[#x0B36-#x0B39] |#x0B3D
33 |[#x0B5C-#x0B5D] |[#x0B5F-#x0B61] |[#x0B85-#x0B8A] |[#x0B8E-#x0B90]
34 |[#x0B92-#x0B95] |[#x0B99-#x0B9A] |#x0B9C |[#x0B9E-#x0B9F]
35 |[#x0BA3-#x0BA4] |[#x0BA8-#x0BAA] |[#x0BAE-#x0BB5] |[#x0BB7-#x0BB9]
36 |[#x0C05-#x0C0C] |[#x0C0E-#x0C10] |[#x0C12-#x0C28] |[#x0C2A-#x0C33]
37 |[#x0C35-#x0C39] |[#x0C60-#x0C61] |[#x0C85-#x0C8C] |[#x0C8E-#x0C90]
38 |[#x0C92-#x0CA8] |[#x0CAA-#x0CB3] |[#x0CB5-#x0CB9] |#x0CDE
39 |[#x0CE0-#x0CE1] |[#x0D05-#x0D0C] |[#x0D0E-#x0D10] |[#x0D12-#x0D28]
40 |[#x0D2A-#x0D39] |[#x0D60-#x0D61] |[#x0E01-#x0E2E] |#x0E30
41 |[#x0E32-#x0E33] |[#x0E40-#x0E45] |[#x0E81-#x0E82] |#x0E84
42 |[#x0E87-#x0E88] |#x0E8A |#x0E8D |[#x0E94-#x0E97]
43 |[#x0E99-#x0E9F] |[#x0EA1-#x0EA3] |#x0EA5 |#x0EA7
44 |[#x0EAA-#x0EAB] |[#x0EAD-#x0EAE] |#x0EB0 |[#x0EB2-#x0EB3]
45 |#x0EBD |[#x0EC0-#x0EC4] |[#x0F40-#x0F47] |[#x0F49-#x0F69]
46 |[#x10A0-#x10C5] |[#x10D0-#x10F6] |#x1100 |[#x1102-#x1103]
47 |[#x1105-#x1107] |#x1109 |[#x110B-#x110C] |[#x110E-#x1112]
48 |#x113C |#x113E |#x1140 |#x114C |#x114E |#x1150
49 |[#x1154-#x1155] |#x1159 |[#x115F-#x1161] |#x1163
50 |#x1165 |#x1167 |#x1169 |[#x116D-#x116E] |[#x1172-#x1173]
51 |#x1175 |#x119E |#x11A8 |#x11AB |[#x11AE-#x11AF]
52 |[#x11B7-#x11B8] |#x11BA |[#x11BC-#x11C2] |#x11EB
53 |#x11F0 |#x11F9 |[#x1E00-#x1E9B] |[#x1EA0-#x1EF9]
54 |[#x1F00-#x1F15] |[#x1F18-#x1F1D] |[#x1F20-#x1F45] |[#x1F48-#x1F4D]
55 |[#x1F50-#x1F57] |#x1F59 |#x1F5B |#x1F5D |[#x1F5F-#x1F7D]
56 |[#x1F80-#x1FB4] |[#x1FB6-#x1FBC] |#x1FBE |[#x1FC2-#x1FC4]
57 |[#x1FC6-#x1FCC] |[#x1FD0-#x1FD3] |[#x1FD6-#x1FDB] |[#x1FE0-#x1FEC]
58 |[#x1FF2-#x1FF4] |[#x1FF6-#x1FFC] |#x2126 |[#x212A-#x212B]
59 |#x212E |[#x2180-#x2182] |[#x3041-#x3094] |[#x30A1-#x30FA]
60 |[#x3105-#x312C] |[#xAC00-#xD7A3] </rhs>
61 </prod>
62 <prod id="NT-Ideographic">
63 <lhs>Ideographic</lhs><rhs>[#x4E00-#x9FA5] |#x3007 |[#x3021-#x3029] </rhs>
64 </prod>
65 <prod id="NT-CombiningChar">
66 <lhs>CombiningChar</lhs><rhs>[#x0300-#x0345] |[#x0360-#x0361] |[#x0483-#x0486]
67 |[#x0591-#x05A1] |[#x05A3-#x05B9] |[#x05BB-#x05BD] |#x05BF
68 |[#x05C1-#x05C2] |#x05C4 |[#x064B-#x0652] |#x0670
69 |[#x06D6-#x06DC] |[#x06DD-#x06DF] |[#x06E0-#x06E4] |[#x06E7-#x06E8]
70 |[#x06EA-#x06ED] |[#x0901-#x0903] |#x093C |[#x093E-#x094C]
71 |#x094D |[#x0951-#x0954] |[#x0962-#x0963] |[#x0981-#x0983]
72 |#x09BC |#x09BE |#x09BF |[#x09C0-#x09C4] |[#x09C7-#x09C8]
73 |[#x09CB-#x09CD] |#x09D7 |[#x09E2-#x09E3] |#x0A02
74 |#x0A3C |#x0A3E |#x0A3F |[#x0A40-#x0A42] |[#x0A47-#x0A48]
75 |[#x0A4B-#x0A4D] |[#x0A70-#x0A71] |[#x0A81-#x0A83] |#x0ABC
76 |[#x0ABE-#x0AC5] |[#x0AC7-#x0AC9] |[#x0ACB-#x0ACD] |[#x0B01-#x0B03]
77 |#x0B3C |[#x0B3E-#x0B43] |[#x0B47-#x0B48] |[#x0B4B-#x0B4D]
78 |[#x0B56-#x0B57] |[#x0B82-#x0B83] |[#x0BBE-#x0BC2] |[#x0BC6-#x0BC8]
79 |[#x0BCA-#x0BCD] |#x0BD7 |[#x0C01-#x0C03] |[#x0C3E-#x0C44]
80 |[#x0C46-#x0C48] |[#x0C4A-#x0C4D] |[#x0C55-#x0C56] |[#x0C82-#x0C83]
81 |[#x0CBE-#x0CC4] |[#x0CC6-#x0CC8] |[#x0CCA-#x0CCD] |[#x0CD5-#x0CD6]
82 |[#x0D02-#x0D03] |[#x0D3E-#x0D43] |[#x0D46-#x0D48] |[#x0D4A-#x0D4D]
83 |#x0D57 |#x0E31 |[#x0E34-#x0E3A] |[#x0E47-#x0E4E]
84 |#x0EB1 |[#x0EB4-#x0EB9] |[#x0EBB-#x0EBC] |[#x0EC8-#x0ECD]
85 |[#x0F18-#x0F19] |#x0F35 |#x0F37 |#x0F39 |#x0F3E
86 |#x0F3F |[#x0F71-#x0F84] |[#x0F86-#x0F8B] |[#x0F90-#x0F95]
87 |#x0F97 |[#x0F99-#x0FAD] |[#x0FB1-#x0FB7] |#x0FB9
88 |[#x20D0-#x20DC] |#x20E1 |[#x302A-#x302F] |#x3099
89 |#x309A </rhs>
90 </prod>
91 <prod id="NT-Digit">
92 <lhs>Digit</lhs><rhs>[#x0030-#x0039] |[#x0660-#x0669] |[#x06F0-#x06F9]
93 |[#x0966-#x096F] |[#x09E6-#x09EF] |[#x0A66-#x0A6F] |[#x0AE6-#x0AEF]
94 |[#x0B66-#x0B6F] |[#x0BE7-#x0BEF] |[#x0C66-#x0C6F] |[#x0CE6-#x0CEF]
95 |[#x0D66-#x0D6F] |[#x0E50-#x0E59] |[#x0ED0-#x0ED9] |[#x0F20-#x0F29] </rhs>
96 </prod>
97 <prod id="NT-Extender">
98 <lhs>Extender</lhs><rhs>#x00B7 |#x02D0 |#x02D1 |#x0387 |#x0640
99 |#x0E46 |#x0EC6 |#x3005 |[#x3031-#x3035] |[#x309D-#x309E]
100 |[#x30FC-#x30FE] </rhs>
101 </prod>
102 </prodgroup>
103 </xmlchars>
104
0 <?xml version="1.0" encoding="UTF-8"?>
1 <xs:schema xmlns="http://www.jdom.org/tests/imp"
2 xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.jdom.org/tests/imp"
3 elementFormDefault="qualified">
4
5
6 <xs:attributeGroup name="simpleAG">
7 <xs:attribute name="type" type="xs:string" fixed="simple" form="qualified" />
8 <xs:attribute name="nodup" type="xs:string" fixed="impval" form="qualified" />
9 </xs:attributeGroup>
10
11 </xs:schema>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <xs:schema xmlns="http://www.jdom.org/tests/default"
2 xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.jdom.org/tests/default"
3 xmlns:imp="http://www.jdom.org/tests/imp"
4 elementFormDefault="qualified">
5
6 <!-- xmlns:tns="http://www.jdom.org/tests/default"
7 -->
8 <xs:import namespace="http://www.jdom.org/tests/imp" schemaLocation="./SAXTestComplexImport.xsd" />
9
10 <xs:element name="test">
11 <xs:complexType>
12 <xs:sequence>
13 <xs:element name="data" minOccurs="1" maxOccurs="unbounded">
14 <xs:complexType>
15 <xs:attribute name="type"/>
16 <xs:attributeGroup ref="imp:simpleAG"/>
17 <xs:attribute name="mainxs" default="mainval" form="qualified"/>
18 </xs:complexType>
19 </xs:element>
20 </xs:sequence>
21 </xs:complexType>
22 </xs:element>
23
24 </xs:schema>
0 <?xml version="1.0" encoding="ISO-8859-1"?>
1 <test xmlns="http://www.jdom.org/tests/default"
2 xmlns:imp="http://www.jdom.org/tests/imp"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://www.jdom.org/tests/default ./SAXTestComplexMain.xsd">
5 <data type="one" />
6 <data type="two" xmlns:attns0="junkns" />
7 <data type="three" xmlns:redo="http://www.jdom.org/tests/default" redo:mainxs="change" />
8 <xx:data type="four" xmlns:xx="http://www.jdom.org/tests/default" />
9 </test>
0 <?xml version="1.0" standalone="no" ?>
1
2 <root xmlns="http://www.jdom.org/schema_main" >
3 <child xmlns="http://www.jdom.org/schema_one" attribute="valueone" />
4 <child xmlns="http://www.jdom.org/schema_two" attribute="valuetwo" />
5 </root>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <xs:schema xmlns="http://www.jdom.org/schema_main"
2 xmlns:xs="http://www.w3.org/2001/XMLSchema"
3 targetNamespace="http://www.jdom.org/schema_main"
4 elementFormDefault="qualified">
5
6 <xs:element name="root">
7 <xs:complexType>
8 <xs:sequence>
9 <xs:any minOccurs="0" maxOccurs="unbounded"/>
10 </xs:sequence>
11 </xs:complexType>
12 </xs:element>
13
14 </xs:schema>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <xs:schema xmlns="http://www.jdom.org/schema_one"
2 xmlns:xs="http://www.w3.org/2001/XMLSchema"
3 targetNamespace="http://www.jdom.org/schema_one"
4 elementFormDefault="qualified">
5
6 <xs:element name="child">
7 <xs:complexType>
8 <xs:attribute name="attribute"/>
9 <xs:attribute name="source" fixed="schema_one"/>
10 </xs:complexType>
11 </xs:element>
12
13 </xs:schema>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <xs:schema xmlns="http://www.jdom.org/schema_two"
2 xmlns:xs="http://www.w3.org/2001/XMLSchema"
3 targetNamespace="http://www.jdom.org/schema_two"
4 elementFormDefault="qualified">
5
6 <xs:element name="child">
7 <xs:complexType>
8 <xs:attribute name="attribute"/>
9 <xs:attribute name="source" fixed="schema_two"/>
10 </xs:complexType>
11 </xs:element>
12
13 </xs:schema>