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