1 /*
2 * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package javax.xml.transform.dom;
27
28 import javax.xml.transform.Result;
29 import org.w3c.dom.Node;
30
31 /**
32 * <p>Acts as a holder for a transformation result tree in the form of a Document Object Model (DOM) tree.</p>
33 *
34 * <p>If no output DOM source is set, the transformation will create a Document node as the holder for the result of the transformation,
35 * which may be retrieved with {@link #getNode()}.</p>
36 *
37 * @author <a href="Jeff.Suttor@Sun.com">Jeff Suttor</a>
38 */
39 public class DOMResult implements Result {
40
41 /** <p>If {@link javax.xml.transform.TransformerFactory#getFeature}
42 * returns <code>true</code> when passed this value as an argument,
43 * the <code>Transformer</code> supports <code>Result</code> output of this type.</p>
44 */
45 public static final String FEATURE = "http://javax.xml.transform.dom.DOMResult/feature";
46
47 /**
48 * <p>Zero-argument default constructor.</p>
49 *
50 * <p><code>node</code>,
51 * <code>siblingNode</code> and
52 * <code>systemId</code>
53 * will be set to <code>null</code>.</p>
54 */
55 public DOMResult() {
56 setNode(null);
57 setNextSibling(null);
58 setSystemId(null);
59 }
60
61 /**
62 * <p>Use a DOM node to create a new output target.</p>
63 *
64 * <p>In practice, the node should be
65 * a {@link org.w3c.dom.Document} node,
66 * a {@link org.w3c.dom.DocumentFragment} node, or
67 * a {@link org.w3c.dom.Element} node.
68 * In other words, a node that accepts children.</p>
69 *
70 * <p><code>siblingNode</code> and
71 * <code>systemId</code>
72 * will be set to <code>null</code>.</p>
73 *
74 * @param node The DOM node that will contain the result tree.
75 */
76 public DOMResult(Node node) {
77 setNode(node);
78 setNextSibling(null);
79 setSystemId(null);
80 }
81
82 /**
83 * <p>Use a DOM node to create a new output target with the specified System ID.<p>
84 *
85 * <p>In practice, the node should be
86 * a {@link org.w3c.dom.Document} node,
87 * a {@link org.w3c.dom.DocumentFragment} node, or
88 * a {@link org.w3c.dom.Element} node.
89 * In other words, a node that accepts children.</p>
90 *
91 * <p><code>siblingNode</code> will be set to <code>null</code>.</p>
92 *
93 * @param node The DOM node that will contain the result tree.
94 * @param systemId The system identifier which may be used in association with this node.
95 */
96 public DOMResult(Node node, String systemId) {
97 setNode(node);
98 setNextSibling(null);
99 setSystemId(systemId);
100 }
101
102 /**
103 * <p>Use a DOM node to create a new output target specifying the child node where the result nodes should be inserted before.</p>
104 *
105 * <p>In practice, <code>node</code> and <code>nextSibling</code> should be
106 * a {@link org.w3c.dom.Document} node,
107 * a {@link org.w3c.dom.DocumentFragment} node, or
108 * a {@link org.w3c.dom.Element} node.
109 * In other words, a node that accepts children.</p>
110 *
111 * <p>Use <code>nextSibling</code> to specify the child node
112 * where the result nodes should be inserted before.
113 * If <code>nextSibling</code> is not a sibling of <code>node</code>,
114 * then an <code>IllegalArgumentException</code> is thrown.
115 * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
116 * then an <code>IllegalArgumentException</code> is thrown.
117 * If <code>nextSibling</code> is <code>null</code>,
118 * then the behavior is the same as calling {@link #DOMResult(Node node)},
119 * i.e. append the result nodes as the last child of the specified <code>node</code>.</p>
120 *
121 * <p><code>systemId</code> will be set to <code>null</code>.</p>
122 *
123 * @param node The DOM node that will contain the result tree.
124 * @param nextSibling The child node where the result nodes should be inserted before.
125 *
126 * @throws IllegalArgumentException If <code>nextSibling</code> is not a sibling of <code>node</code> or
127 * <code>node</code> is <code>null</code> and <code>nextSibling</code>
128 * is not <code>null</code>.
129 *
130 * @since 1.5
131 */
132 public DOMResult(Node node, Node nextSibling) {
133
134 // does the corrent parent/child relationship exist?
135 if (nextSibling != null) {
136 // cannot be a sibling of a null node
137 if (node == null) {
138 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
139 }
140
141 // nextSibling contained by node?
142 if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
143 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
144 }
145 }
146
147 setNode(node);
148 setNextSibling(nextSibling);
149 setSystemId(null);
150 }
151
152 /**
153 * <p>Use a DOM node to create a new output target specifying the child node where the result nodes should be inserted before and
154 * the specified System ID.</p>
155 *
156 * <p>In practice, <code>node</code> and <code>nextSibling</code> should be
157 * a {@link org.w3c.dom.Document} node,
158 * a {@link org.w3c.dom.DocumentFragment} node, or a
159 * {@link org.w3c.dom.Element} node.
160 * In other words, a node that accepts children.</p>
161 *
162 * <p>Use <code>nextSibling</code> to specify the child node
163 * where the result nodes should be inserted before.
164 * If <code>nextSibling</code> is not a sibling of <code>node</code>,
165 * then an <code>IllegalArgumentException</code> is thrown.
166 * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
167 * then an <code>IllegalArgumentException</code> is thrown.
168 * If <code>nextSibling</code> is <code>null</code>,
169 * then the behavior is the same as calling {@link #DOMResult(Node node, String systemId)},
170 * i.e. append the result nodes as the last child of the specified node and use the specified System ID.</p>
171 *
172 * @param node The DOM node that will contain the result tree.
173 * @param nextSibling The child node where the result nodes should be inserted before.
174 * @param systemId The system identifier which may be used in association with this node.
175 *
176 * @throws IllegalArgumentException If <code>nextSibling</code> is not a
177 * sibling of <code>node</code> or
178 * <code>node</code> is <code>null</code> and <code>nextSibling</code>
179 * is not <code>null</code>.
180 *
181 * @since 1.5
182 */
183 public DOMResult(Node node, Node nextSibling, String systemId) {
184
185 // does the corrent parent/child relationship exist?
186 if (nextSibling != null) {
187 // cannot be a sibling of a null node
188 if (node == null) {
189 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
190 }
191
192 // nextSibling contained by node?
193 if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
194 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
195 }
196 }
197
198 setNode(node);
199 setNextSibling(nextSibling);
200 setSystemId(systemId);
201 }
202
203 /**
204 * <p>Set the node that will contain the result DOM tree.<p>
205 *
206 * <p>In practice, the node should be
207 * a {@link org.w3c.dom.Document} node,
208 * a {@link org.w3c.dom.DocumentFragment} node, or
209 * a {@link org.w3c.dom.Element} node.
210 * In other words, a node that accepts children.</p>
211 *
212 * <p>An <code>IllegalStateException</code> is thrown if
213 * <code>nextSibling</code> is not <code>null</code> and
214 * <code>node</code> is not a parent of <code>nextSibling</code>.
215 * An <code>IllegalStateException</code> is thrown if <code>node</code> is <code>null</code> and
216 * <code>nextSibling</code> is not <code>null</code>.</p>
217 *
218 * @param node The node to which the transformation will be appended.
219 *
220 * @throws IllegalStateException If <code>nextSibling</code> is not
221 * <code>null</code> and
222 * <code>nextSibling</code> is not a child of <code>node</code> or
223 * <code>node</code> is <code>null</code> and
224 * <code>nextSibling</code> is not <code>null</code>.
225 */
226 public void setNode(Node node) {
227 // does the corrent parent/child relationship exist?
228 if (nextSibling != null) {
229 // cannot be a sibling of a null node
230 if (node == null) {
231 throw new IllegalStateException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
232 }
233
234 // nextSibling contained by node?
235 if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
236 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
237 }
238 }
239
240 this.node = node;
241 }
242
243 /**
244 * <p>Get the node that will contain the result DOM tree.</p>
245 *
246 * <p>If no node was set via
247 * {@link #DOMResult(Node node)},
248 * {@link #DOMResult(Node node, String systeId)},
249 * {@link #DOMResult(Node node, Node nextSibling)},
250 * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
251 * {@link #setNode(Node node)},
252 * then the node will be set by the transformation, and may be obtained from this method once the transformation is complete.
253 * Calling this method before the transformation will return <code>null</code>.</p>
254 *
255 * @return The node to which the transformation will be appended.
256 */
257 public Node getNode() {
258 return node;
259 }
260
261 /**
262 * <p>Set the child node before which the result nodes will be inserted.</p>
263 *
264 * <p>Use <code>nextSibling</code> to specify the child node
265 * before which the result nodes should be inserted.
266 * If <code>nextSibling</code> is not a descendant of <code>node</code>,
267 * then an <code>IllegalArgumentException</code> is thrown.
268 * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
269 * then an <code>IllegalStateException</code> is thrown.
270 * If <code>nextSibling</code> is <code>null</code>,
271 * then the behavior is the same as calling {@link #DOMResult(Node node)},
272 * i.e. append the result nodes as the last child of the specified <code>node</code>.</p>
273 *
274 * @param nextSibling The child node before which the result nodes will be inserted.
275 *
276 * @throws IllegalArgumentException If <code>nextSibling</code> is not a
277 * descendant of <code>node</code>.
278 * @throws IllegalStateException If <code>node</code> is <code>null</code>
279 * and <code>nextSibling</code> is not <code>null</code>.
280 *
281 * @since 1.5
282 */
283 public void setNextSibling(Node nextSibling) {
284
285 // does the corrent parent/child relationship exist?
286 if (nextSibling != null) {
287 // cannot be a sibling of a null node
288 if (node == null) {
289 throw new IllegalStateException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
290 }
291
292 // nextSibling contained by node?
293 if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
294 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
295 }
296 }
297
298 this.nextSibling = nextSibling;
299 }
300
301 /**
302 * <p>Get the child node before which the result nodes will be inserted.</p>
303 *
304 * <p>If no node was set via
305 * {@link #DOMResult(Node node, Node nextSibling)},
306 * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
307 * {@link #setNextSibling(Node nextSibling)},
308 * then <code>null</code> will be returned.</p>
309 *
310 * @return The child node before which the result nodes will be inserted.
311 *
312 * @since 1.5
313 */
314 public Node getNextSibling() {
315 return nextSibling;
316 }
317
318 /**
319 * <p>Set the systemId that may be used in association with the node.</p>
320 *
321 * @param systemId The system identifier as a URI string.
322 */
323 public void setSystemId(String systemId) {
324 this.systemId = systemId;
325 }
326
327 /**
328 * <p>Get the System Identifier.</p>
329 *
330 * <p>If no System ID was set via
331 * {@link #DOMResult(Node node, String systemId)},
332 * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
333 * {@link #setSystemId(String systemId)},
334 * then <code>null</code> will be returned.</p>
335 *
336 * @return The system identifier.
337 */
338 public String getSystemId() {
339 return systemId;
340 }
341
342 //////////////////////////////////////////////////////////////////////
343 // Internal state.
344 //////////////////////////////////////////////////////////////////////
345
346 /**
347 * <p>The node to which the transformation will be appended.</p>
348 */
349 private Node node = null;
350
351 /**
352 * <p>The child node before which the result nodes will be inserted.</p>
353 *
354 * @since 1.5
355 */
356 private Node nextSibling = null;
357
358 /**
359 * <p>The System ID that may be used in association with the node.</p>
360 */
361 private String systemId = null;
362 }