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
20package javax.xml.transform.dom;
21
22import javax.xml.transform.Result;
23import 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 */
34public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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