1 /*
   2  * Copyright (c) 2000, 2005, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * 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  * @since 1.4
  39  */
  40 public class DOMResult implements Result {
  41 
  42     /** <p>If {@link javax.xml.transform.TransformerFactory#getFeature}
  43      * returns <code>true</code> when passed this value as an argument,
  44      * the <code>Transformer</code> supports <code>Result</code> output of this type.</p>
  45      */
  46     public static final String FEATURE = "http://javax.xml.transform.dom.DOMResult/feature";
  47 
  48     /**
  49      * <p>Zero-argument default constructor.</p>
  50      *
  51      * <p><code>node</code>,
  52      * <code>siblingNode</code> and
  53      * <code>systemId</code>
  54      * will be set to <code>null</code>.</p>
  55      */
  56     public DOMResult() {
  57         setNode(null);
  58         setNextSibling(null);
  59         setSystemId(null);
  60     }
  61 
  62     /**
  63      * <p>Use a DOM node to create a new output target.</p>
  64      *
  65      * <p>In practice, the node should be
  66      * a {@link org.w3c.dom.Document} node,
  67      * a {@link org.w3c.dom.DocumentFragment} node, or
  68      * a {@link org.w3c.dom.Element} node.
  69      * In other words, a node that accepts children.</p>
  70      *
  71      * <p><code>siblingNode</code> and
  72      * <code>systemId</code>
  73      * will be set to <code>null</code>.</p>
  74      *
  75      * @param node The DOM node that will contain the result tree.
  76      */
  77     public DOMResult(Node node) {
  78         setNode(node);
  79         setNextSibling(null);
  80         setSystemId(null);
  81     }
  82 
  83     /**
  84      * <p>Use a DOM node to create a new output target with the specified System ID.<p>
  85      *
  86      * <p>In practice, the node should be
  87      * a {@link org.w3c.dom.Document} node,
  88      * a {@link org.w3c.dom.DocumentFragment} node, or
  89      * a {@link org.w3c.dom.Element} node.
  90      * In other words, a node that accepts children.</p>
  91      *
  92      * <p><code>siblingNode</code> will be set to <code>null</code>.</p>
  93      *
  94      * @param node The DOM node that will contain the result tree.
  95      * @param systemId The system identifier which may be used in association with this node.
  96      */
  97     public DOMResult(Node node, String systemId) {
  98         setNode(node);
  99         setNextSibling(null);
 100         setSystemId(systemId);
 101     }
 102 
 103     /**
 104      * <p>Use a DOM node to create a new output target specifying the child node where the result nodes should be inserted before.</p>
 105      *
 106      * <p>In practice, <code>node</code> and <code>nextSibling</code> should be
 107      * a {@link org.w3c.dom.Document} node,
 108      * a {@link org.w3c.dom.DocumentFragment} node, or
 109      * a {@link org.w3c.dom.Element} node.
 110      * In other words, a node that accepts children.</p>
 111      *
 112      * <p>Use <code>nextSibling</code> to specify the child node
 113      * where the result nodes should be inserted before.
 114      * If <code>nextSibling</code> is not a sibling of <code>node</code>,
 115      * then an <code>IllegalArgumentException</code> is thrown.
 116      * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
 117      * then an <code>IllegalArgumentException</code> is thrown.
 118      * If <code>nextSibling</code> is <code>null</code>,
 119      * then the behavior is the same as calling {@link #DOMResult(Node node)},
 120      * i.e. append the result nodes as the last child of the specified <code>node</code>.</p>
 121      *
 122      * <p><code>systemId</code> will be set to <code>null</code>.</p>
 123      *
 124      * @param node The DOM node that will contain the result tree.
 125      * @param nextSibling The child node where the result nodes should be inserted before.
 126      *
 127      * @throws IllegalArgumentException If <code>nextSibling</code> is not a sibling of <code>node</code> or
 128      *   <code>node</code> is <code>null</code> and <code>nextSibling</code>
 129      *   is not <code>null</code>.
 130      *
 131      * @since 1.5
 132      */
 133     public DOMResult(Node node, Node nextSibling) {
 134 
 135         // does the corrent parent/child relationship exist?
 136         if (nextSibling != null) {
 137             // cannot be a sibling of a null node
 138             if (node == null) {
 139                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
 140             }
 141 
 142             // nextSibling contained by node?
 143             if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
 144                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
 145             }
 146         }
 147 
 148         setNode(node);
 149         setNextSibling(nextSibling);
 150         setSystemId(null);
 151     }
 152 
 153     /**
 154      * <p>Use a DOM node to create a new output target specifying the child node where the result nodes should be inserted before and
 155      * the specified System ID.</p>
 156      *
 157      * <p>In practice, <code>node</code> and <code>nextSibling</code> should be
 158      * a {@link org.w3c.dom.Document} node,
 159      * a {@link org.w3c.dom.DocumentFragment} node, or a
 160      * {@link org.w3c.dom.Element} node.
 161      * In other words, a node that accepts children.</p>
 162      *
 163      * <p>Use <code>nextSibling</code> to specify the child node
 164      * where the result nodes should be inserted before.
 165      * If <code>nextSibling</code> is not a sibling of <code>node</code>,
 166      * then an <code>IllegalArgumentException</code> is thrown.
 167      * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
 168      * then an <code>IllegalArgumentException</code> is thrown.
 169      * If <code>nextSibling</code> is <code>null</code>,
 170      * then the behavior is the same as calling {@link #DOMResult(Node node, String systemId)},
 171      * i.e. append the result nodes as the last child of the specified node and use the specified System ID.</p>
 172      *
 173      * @param node The DOM node that will contain the result tree.
 174      * @param nextSibling The child node where the result nodes should be inserted before.
 175      * @param systemId The system identifier which may be used in association with this node.
 176      *
 177      * @throws IllegalArgumentException If <code>nextSibling</code> is not a
 178      *   sibling of <code>node</code> or
 179      *   <code>node</code> is <code>null</code> and <code>nextSibling</code>
 180      *   is not <code>null</code>.
 181      *
 182      * @since 1.5
 183      */
 184     public DOMResult(Node node, Node nextSibling, String systemId) {
 185 
 186         // does the corrent parent/child relationship exist?
 187         if (nextSibling != null) {
 188             // cannot be a sibling of a null node
 189             if (node == null) {
 190                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
 191             }
 192 
 193             // nextSibling contained by node?
 194             if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
 195                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
 196             }
 197         }
 198 
 199         setNode(node);
 200         setNextSibling(nextSibling);
 201         setSystemId(systemId);
 202     }
 203 
 204     /**
 205      * <p>Set the node that will contain the result DOM tree.<p>
 206      *
 207      * <p>In practice, the node should be
 208      * a {@link org.w3c.dom.Document} node,
 209      * a {@link org.w3c.dom.DocumentFragment} node, or
 210      * a {@link org.w3c.dom.Element} node.
 211      * In other words, a node that accepts children.</p>
 212      *
 213      * <p>An <code>IllegalStateException</code> is thrown if
 214      * <code>nextSibling</code> is not <code>null</code> and
 215      * <code>node</code> is not a parent of <code>nextSibling</code>.
 216      * An <code>IllegalStateException</code> is thrown if <code>node</code> is <code>null</code> and
 217      * <code>nextSibling</code> is not <code>null</code>.</p>
 218      *
 219      * @param node The node to which the transformation will be appended.
 220      *
 221      * @throws IllegalStateException If <code>nextSibling</code> is not
 222      *   <code>null</code> and
 223      *   <code>nextSibling</code> is not a child of <code>node</code> or
 224      *   <code>node</code> is <code>null</code> and
 225      *   <code>nextSibling</code> is not <code>null</code>.
 226      */
 227     public void setNode(Node node) {
 228         // does the corrent parent/child relationship exist?
 229         if (nextSibling != null) {
 230             // cannot be a sibling of a null node
 231             if (node == null) {
 232                 throw new IllegalStateException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
 233             }
 234 
 235             // nextSibling contained by node?
 236             if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
 237                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
 238             }
 239         }
 240 
 241         this.node = node;
 242     }
 243 
 244     /**
 245      * <p>Get the node that will contain the result DOM tree.</p>
 246      *
 247      * <p>If no node was set via
 248      * {@link #DOMResult(Node node)},
 249      * {@link #DOMResult(Node node, String systeId)},
 250      * {@link #DOMResult(Node node, Node nextSibling)},
 251      * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
 252      * {@link #setNode(Node node)},
 253      * then the node will be set by the transformation, and may be obtained from this method once the transformation is complete.
 254      * Calling this method before the transformation will return <code>null</code>.</p>
 255      *
 256      * @return The node to which the transformation will be appended.
 257      */
 258     public Node getNode() {
 259         return node;
 260     }
 261 
 262     /**
 263      * <p>Set the child node before which the result nodes will be inserted.</p>
 264      *
 265      * <p>Use <code>nextSibling</code> to specify the child node
 266      * before which the result nodes should be inserted.
 267      * If <code>nextSibling</code> is not a descendant of <code>node</code>,
 268      * then an <code>IllegalArgumentException</code> is thrown.
 269      * If <code>node</code> is <code>null</code> and <code>nextSibling</code> is not <code>null</code>,
 270      * then an <code>IllegalStateException</code> is thrown.
 271      * If <code>nextSibling</code> is <code>null</code>,
 272      * then the behavior is the same as calling {@link #DOMResult(Node node)},
 273      * i.e. append the result nodes as the last child of the specified <code>node</code>.</p>
 274      *
 275      * @param nextSibling The child node before which the result nodes will be inserted.
 276      *
 277      * @throws IllegalArgumentException If <code>nextSibling</code> is not a
 278      *   descendant of <code>node</code>.
 279      * @throws IllegalStateException If <code>node</code> is <code>null</code>
 280      *   and <code>nextSibling</code> is not <code>null</code>.
 281      *
 282      * @since 1.5
 283      */
 284     public void setNextSibling(Node nextSibling) {
 285 
 286         // does the corrent parent/child relationship exist?
 287         if (nextSibling != null) {
 288             // cannot be a sibling of a null node
 289             if (node == null) {
 290                 throw new IllegalStateException("Cannot create a DOMResult when the nextSibling is contained by the \"null\" node.");
 291             }
 292 
 293             // nextSibling contained by node?
 294             if ((node.compareDocumentPosition(nextSibling)&Node.DOCUMENT_POSITION_CONTAINED_BY)==0) {
 295                 throw new IllegalArgumentException("Cannot create a DOMResult when the nextSibling is not contained by the node.");
 296             }
 297         }
 298 
 299         this.nextSibling = nextSibling;
 300     }
 301 
 302     /**
 303      * <p>Get the child node before which the result nodes will be inserted.</p>
 304      *
 305      * <p>If no node was set via
 306      * {@link #DOMResult(Node node, Node nextSibling)},
 307      * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
 308      * {@link #setNextSibling(Node nextSibling)},
 309      * then <code>null</code> will be returned.</p>
 310      *
 311      * @return The child node before which the result nodes will be inserted.
 312      *
 313      * @since 1.5
 314      */
 315     public Node getNextSibling() {
 316         return nextSibling;
 317     }
 318 
 319     /**
 320      * <p>Set the systemId that may be used in association with the node.</p>
 321      *
 322      * @param systemId The system identifier as a URI string.
 323      */
 324     public void setSystemId(String systemId) {
 325         this.systemId = systemId;
 326     }
 327 
 328     /**
 329      * <p>Get the System Identifier.</p>
 330      *
 331      * <p>If no System ID was set via
 332      * {@link #DOMResult(Node node, String systemId)},
 333      * {@link #DOMResult(Node node, Node nextSibling, String systemId)} or
 334      * {@link #setSystemId(String systemId)},
 335      * then <code>null</code> will be returned.</p>
 336      *
 337      * @return The system identifier.
 338      */
 339     public String getSystemId() {
 340         return systemId;
 341     }
 342 
 343     //////////////////////////////////////////////////////////////////////
 344     // Internal state.
 345     //////////////////////////////////////////////////////////////////////
 346 
 347     /**
 348      * <p>The node to which the transformation will be appended.</p>
 349      */
 350     private Node node = null;
 351 
 352     /**
 353      * <p>The child node before which the result nodes will be inserted.</p>
 354      *
 355      * @since 1.5
 356      */
 357     private Node nextSibling = null;
 358 
 359     /**
 360      * <p>The System ID that may be used in association with the node.</p>
 361      */
 362     private String systemId = null;
 363 }