1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 // $Id: DOMResult.java 569995 2007-08-27 04:31:06Z mrglavas $
19 
20 package javax.xml.transform.dom;
21 
22 import javax.xml.transform.Result;
23 import org.w3c.dom.Node;
24 
25 /**
26  * <p>Acts as a holder for a transformation result tree in the form of a Document Object Model (DOM) tree.</p>
27  *
28  * <p>If no output DOM source is set, the transformation will create a Document node as the holder for the result of the transformation,
29  * which may be retrieved with {@link #getNode()}.</p>
30  *
31  * @author <a href="Jeff.Suttor@Sun.com">Jeff Suttor</a>
32  * @version $Revision: 569995 $, $Date: 2007-08-26 21:31:06 -0700 (Sun, 26 Aug 2007) $
33  */
34 public class DOMResult implements Result {
35 
36     /** <p>If {@link javax.xml.transform.TransformerFactory#getFeature}
37      * returns <code>true</code> when passed this value as an argument,
38      * the <code>Transformer</code> supports <code>Result</code> output of this type.</p>
39      */
40     public static final String FEATURE = "http://javax.xml.transform.dom.DOMResult/feature";
41 
42     /**
43      * <p>Zero-argument default constructor.</p>
44      *
45      * <p><code>node</code>,
46      * <code>siblingNode</code> and
47      * <code>systemId</code>
48      * will be set to <code>null</code>.</p>
49      */
DOMResult()50     public DOMResult() {
51         setNode(null);
52         setNextSibling(null);
53         setSystemId(null);
54     }
55 
56     /**
57      * <p>Use a DOM node to create a new output target.</p>
58      *
59      * <p>In practice, the node should be
60      * a {@link org.w3c.dom.Document} node,
61      * a {@link org.w3c.dom.DocumentFragment} node, or
62      * a {@link org.w3c.dom.Element} node.
63      * In other words, a node that accepts children.</p>
64      *
65      * <p><code>siblingNode</code> and
66      * <code>systemId</code>
67      * will be set to <code>null</code>.</p>
68      *
69      * @param node The DOM node that will contain the result tree.
70      */
DOMResult(Node node)71     public DOMResult(Node node) {
72         setNode(node);
73         setNextSibling(null);
74         setSystemId(null);
75     }
76 
77     /**
78      * <p>Use a DOM node to create a new output target with the specified System ID.<p>
79      *
80      * <p>In practice, the node should be
81      * a {@link org.w3c.dom.Document} node,
82      * a {@link org.w3c.dom.DocumentFragment} node, or
83      * a {@link org.w3c.dom.Element} node.
84      * In other words, a node that accepts children.</p>
85      *
86      * <p><code>siblingNode</code> will be set to <code>null</code>.</p>
87      *
88      * @param node The DOM node that will contain the result tree.
89      * @param systemId The system identifier which may be used in association with this node.
90      */
DOMResult(Node node, String systemId)91     public DOMResult(Node node, String systemId) {
92         setNode(node);
93         setNextSibling(null);
94         setSystemId(systemId);
95     }
96 
97     /**
98      * <p>Use a DOM node to create a new output target specifying the child node where the result nodes should be inserted before.</p>
99      *
100      * <p>In practice, <code>node</code> and <code>nextSibling</code> should be
101      * a {@link org.w3c.dom.Document} node,
102      * a {@link org.w3c.dom.DocumentFragment} node, or
103      * a {@link org.w3c.dom.Element} node.
104      * In other words, a node that accepts children.</p>
105      *
106      * <p>Use <code>nextSibling</code> to specify the child node
107      * where the result nodes should be inserted before.
108      * If <code>nextSibling</code> is not a sibling of <code>node</code>,
109      * then an <code>IllegalArgumentException</code> is thrown.
110      * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
111      * then an <code>IllegalArgumentException</code> is thrown.
112      * If <code>nextSibling</code> is <code>null</code>,
113      * then the behavior is the same as calling {@link #DOMResult(Node node)},
114      * i.e. append the result nodes as the last child of the specified <code>node</code>.</p>
115      *
116      * <p><code>systemId</code> will be set to <code>null</code>.</p>
117      *
118      * @param node The DOM node that will contain the result tree.
119      * @param nextSibling The child node where the result nodes should be inserted before.
120      *
121      * @throws IllegalArgumentException If <code>nextSibling</code> is not a sibling of <code>node</code>.
122      * @throws IllegalArgumentException If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>.
123      *
124      * @since 1.5
125      */
DOMResult(Node node, Node nextSibling)126     public DOMResult(Node node, Node nextSibling) {
127 
128         // does the corrent parent/child relationship exist?
129         if (nextSibling != null) {
130             // cannot be a sibling of a null node
131             if (node == null) {
132                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
133             }
134 
135             // nextSibling contained by node?
136             if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
137                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
138             }
139         }
140 
141         setNode(node);
142         setNextSibling(nextSibling);
143         setSystemId(null);
144     }
145 
146     /**
147      * <p>Use a DOM node to create a new output target specifying the child node where the result nodes should be inserted before and
148      * the specified System ID.</p>
149      *
150      * <p>In practice, <code>node</code> and <code>nextSibling</code> should be
151      * a {@link org.w3c.dom.Document} node,
152      * a {@link org.w3c.dom.DocumentFragment} node, or a
153      * {@link org.w3c.dom.Element} node.
154      * In other words, a node that accepts children.</p>
155      *
156      * <p>Use <code>nextSibling</code> to specify the child node
157      * where the result nodes should be inserted before.
158      * If <code>nextSibling</code> is not a sibling of <code>node</code>,
159      * then an <code>IllegalArgumentException</code> is thrown.
160      * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
161      * then an <code>IllegalArgumentException</code> is thrown.
162      * If <code>nextSibling</code> is <code>null</code>,
163      * then the behavior is the same as calling {@link #DOMResult(Node node, String systemId)},
164      * i.e. append the result nodes as the last child of the specified node and use the specified System ID.</p>
165      *
166      * @param node The DOM node that will contain the result tree.
167      * @param nextSibling The child node where the result nodes should be inserted before.
168      * @param systemId The system identifier which may be used in association with this node.
169      *
170      * @throws IllegalArgumentException If <code>nextSibling</code> is not a sibling of <code>node</code>.
171      * @throws IllegalArgumentException If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>.
172      *
173      * @since 1.5
174      */
DOMResult(Node node, Node nextSibling, String systemId)175     public DOMResult(Node node, Node nextSibling, String systemId) {
176 
177         // does the current parent/child relationship exist?
178         if (nextSibling != null) {
179             // cannot be a sibling of a null node
180             if (node == null) {
181                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
182             }
183 
184             // nextSibling contained by node?
185             if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
186                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
187             }
188         }
189 
190         setNode(node);
191         setNextSibling(nextSibling);
192         setSystemId(systemId);
193     }
194 
195     /**
196      * <p>Set the node that will contain the result DOM tree.<p>
197      *
198      * <p>In practice, the node should be
199      * a {@link org.w3c.dom.Document} node,
200      * a {@link org.w3c.dom.DocumentFragment} node, or
201      * a {@link org.w3c.dom.Element} node.
202      * In other words, a node that accepts children.</p>
203      *
204      * <p>An <code>IllegalStateException</code> is thrown if <code>nextSibling</code> is not <code>null</code> and
205      * <code>node</code> is not a parent of <code>nextSibling</code>.
206      * An <code>IllegalStateException</code> is thrown if <code>node</code> is <code>null</code> and
207      * <code>nextSibling</code> is not <code>null</code>.</p>
208      *
209      * @param node The node to which the transformation will be appended.
210      *
211      * @throws IllegalStateException If <code>nextSibling</code> is not <code>null</code> and
212      *   <code>nextSibling</code> is not a child of <code>node</code>.
213      * @throws IllegalStateException If <code>node</code> is <code>null</code> and
214      *   <code>nextSibling</code> is not <code>null</code>.
215      */
setNode(Node node)216     public void setNode(Node node) {
217         // does the corrent parent/child relationship exist?
218         if (nextSibling != null) {
219             // cannot be a sibling of a null node
220             if (node == null) {
221                 throw new IllegalStateException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
222             }
223 
224             // nextSibling contained by node?
225             if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
226                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
227             }
228         }
229 
230         this.node = node;
231     }
232 
233     /**
234      * <p>Get the node that will contain the result DOM tree.</p>
235      *
236      * <p>If no node was set via
237      * {@link #DOMResult(Node node)},
238      * {@link #DOMResult(Node node, String systeId)},
239      * {@link #DOMResult(Node node, Node nextSibling)},
240      * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
241      * {@link #setNode(Node node)},
242      * then the node will be set by the transformation, and may be obtained from this method once the transformation is complete.
243      * Calling this method before the transformation will return <code>null</code>.</p>
244      *
245      * @return The node to which the transformation will be appended.
246      */
getNode()247     public Node getNode() {
248         return node;
249     }
250 
251     /**
252      * <p>Set the child node before which the result nodes will be inserted.</p>
253      *
254      * <p>Use <code>nextSibling</code> to specify the child node
255      * before which the result nodes should be inserted.
256      * If <code>nextSibling</code> is not a descendant of <code>node</code>,
257      * then an <code>IllegalArgumentException</code> is thrown.
258      * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
259      * then an <code>IllegalStateException</code> is thrown.
260      * If <code>nextSibling</code> is <code>null</code>,
261      * then the behavior is the same as calling {@link #DOMResult(Node node)},
262      * i.e. append the result nodes as the last child of the specified <code>node</code>.</p>
263      *
264      * @param nextSibling The child node before which the result nodes will be inserted.
265      *
266      * @throws IllegalArgumentException If <code>nextSibling</code> is not a descendant of <code>node</code>.
267      * @throws IllegalStateException If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>.
268      *
269      * @since 1.5
270      */
setNextSibling(Node nextSibling)271     public void setNextSibling(Node nextSibling) {
272 
273         // does the corrent parent/child relationship exist?
274         if (nextSibling != null) {
275             // cannot be a sibling of a null node
276             if (node == null) {
277                 throw new IllegalStateException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
278             }
279 
280             // nextSibling contained by node?
281             if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
282                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
283             }
284         }
285 
286         this.nextSibling = nextSibling;
287     }
288 
289     /**
290      * <p>Get the child node before which the result nodes will be inserted.</p>
291      *
292      * <p>If no node was set via
293      * {@link #DOMResult(Node node, Node nextSibling)},
294      * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
295      * {@link #setNextSibling(Node nextSibling)},
296      * then <code>null</code> will be returned.</p>
297      *
298      * @return The child node before which the result nodes will be inserted.
299      *
300      * @since 1.5
301      */
getNextSibling()302     public Node getNextSibling() {
303         return nextSibling;
304     }
305 
306     /**
307      * <p>Set the systemId that may be used in association with the node.</p>
308      *
309      * @param systemId The system identifier as a URI string.
310      */
setSystemId(String systemId)311     public void setSystemId(String systemId) {
312         this.systemId = systemId;
313     }
314 
315     /**
316      * <p>Get the System Identifier.</p>
317      *
318      * <p>If no System ID was set via
319      * {@link #DOMResult(Node node, String systemId)},
320      * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
321      * {@link #setSystemId(String systemId)},
322      * then <code>null</code> will be returned.</p>
323      *
324      * @return The system identifier.
325      */
getSystemId()326     public String getSystemId() {
327         return systemId;
328     }
329 
330     //////////////////////////////////////////////////////////////////////
331     // Internal state.
332     //////////////////////////////////////////////////////////////////////
333 
334     /**
335      * <p>The node to which the transformation will be appended.</p>
336      */
337     private Node node = null;
338 
339     /**
340      * <p>The child node before which the result nodes will be inserted.</p>
341      *
342      * @since 1.5
343      */
344     private Node nextSibling = null;
345 
346     /**
347      * <p>The System ID that may be used in association with the node.</p>
348      */
349     private String systemId = null;
350 }
351