1 /* Copyright 2002-2005 Elliotte Rusty Harold 2 3 This library is free software; you can redistribute it and/or modify 4 it under the terms of version 2.1 of the GNU Lesser General Public 5 License as published by the Free Software Foundation. 6 7 This library is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 GNU Lesser General Public License for more details. 11 12 You should have received a copy of the GNU Lesser General Public 13 License along with this library; if not, write to the 14 Free Software Foundation, Inc., 59 Temple Place, Suite 330, 15 Boston, MA 02111-1307 USA 16 17 You can contact Elliotte Rusty Harold by sending e-mail to 18 elharo@ibiblio.org. Please include the word "XOM" in the 19 subject line. The XOM home page is located at http://www.xom.nu/ 20 */ 21 22 package nu.xom; 23 24 /** 25 * <p> 26 * Builders use a <code>NodeFactory</code> object 27 * to construct each <code>Node</code> object (<code>Element</code>, 28 * <code>Text</code>, <code>Attribute</code>, etc.) they add to the 29 * tree. The default implementation simply calls the relevant 30 * constructor, stuffs the resulting <code>Node</code> object in a 31 * length one <code>Nodes</code> object, and returns it. 32 * </p> 33 * 34 * <p> 35 * Subclassing this class allows builders to produce 36 * instance of subclasses (for example, 37 * <code>HTMLElement</code>) instead of the 38 * base classes. 39 * </p> 40 * 41 * <p> 42 * Subclasses can also filter content while building. 43 * For example, namespaces could be added to or changed 44 * on all elements. Comments could be deleted. Processing 45 * instructions can be changed into elements. An 46 * <code>xinclude:include</code> element could be replaced 47 * with the content it references. All such changes must be 48 * consistent with the usual rules of well-formedness. For 49 * example, the <code>makeDocType()</code> method should not 50 * return a list containing two <code>DocType</code> objects 51 * because an XML document can have at most one document type 52 * declaration. Nor should it return a list containing an element, 53 * because an element cannot appear in a document prolog. However, 54 * it could return a list containing any number of comments and 55 * processing instructions, and not more than one <code>DocType</code> 56 * object. 57 * </p> 58 * 59 * @author Elliotte Rusty Harold 60 * @version 1.1d5 61 * 62 */ 63 public class NodeFactory { 64 65 /** 66 * <p> 67 * Constructs a new node factory. 68 * </p> 69 * 70 */ NodeFactory()71 public NodeFactory() {} 72 73 /** 74 * <p> 75 * Creates a new element in the specified namespace 76 * with the specified name. The builder calls this 77 * method to make the root element of the document. 78 * </p> 79 * 80 * <p> 81 * Subclasses may change the name, namespace, content, or other 82 * characteristics of the element returned. 83 * The default implementation merely calls 84 * <code>startMakingElement</code>. However, when subclassing, it 85 * is often useful to be able to easily distinguish between the 86 * root element and a non-root element because the root element 87 * cannot be detached. Therefore, subclasses must not return null 88 * from this method. Doing so will cause a 89 * <code>NullPointerException</code>. 90 * </p> 91 * 92 * @param name the qualified name of the element 93 * @param namespace the namespace URI of the element 94 * 95 * @return the new root element 96 */ makeRootElement(String name, String namespace)97 public Element makeRootElement(String name, String namespace) { 98 return startMakingElement(name, namespace); 99 } 100 101 102 /** 103 * <p> 104 * Creates a new <code>Element</code> in the specified namespace 105 * with the specified name. 106 * </p> 107 * 108 * <p> 109 * Subclasses may change the name, namespace, content, or other 110 * characteristics of the <code>Element</code> returned. 111 * Subclasses may return null to indicate the 112 * <code>Element</code> should not be created. 113 * However, doing so will only remove the element's start-tag and 114 * end-tag from the result tree. Any content inside the element 115 * will be attached to the element's parent by default, unless it 116 * too is filtered. To remove an entire element, return an empty 117 * <code>Nodes</code> object from the 118 * <code>finishMakingElement()</code> method. 119 * </p> 120 * 121 * @param name the qualified name of the element 122 * @param namespace the namespace URI of the element 123 * 124 * @return the new element 125 */ startMakingElement(String name, String namespace)126 public Element startMakingElement(String name, String namespace) { 127 return new Element(name, namespace); 128 } 129 130 131 /** 132 * <p> 133 * Signals the end of an element. This method should return 134 * the <code>Nodes</code> to be added to the tree. 135 * They need not contain the <code>Element</code> that 136 * was passed to this method, though most often they will. 137 * By default the <code>Nodes</code> returned contain 138 * only the built element. However, subclasses may return 139 * a list containing any number of nodes, all of which will be 140 * added to the tree at the current position in the order given by 141 * the list (subject to the usual well-formedness constraints, of 142 * course. For instance, the list should not contain a 143 * <code>DocType</code> object unless the element is the root 144 * element, and the document does not already have a 145 * <code>DocType</code>). All of the nodes returned must be 146 * parentless. If this method returns an empty list, 147 * then the element (including all its contents) is not included 148 * in the finished document. 149 * </p> 150 * 151 * <p> 152 * To process an element at a time, override this method in a 153 * subclass so that it functions as a callback. When you're done 154 * processing the <code>Element</code>, return an empty list so 155 * that it will be removed from the tree and garbage collected. 156 * Be careful not to return an empty list for the root element 157 * though. That is, when the element passed to this method is the 158 * root element, the list returned must contain exactly one 159 * <code>Element</code> object. The simplest way to check this 160 * is testing if <code>element.getParent() instanceof 161 * Document</code>. 162 * </p> 163 * 164 * <p> 165 * Do not detach <code>element</code> or any of its ancestors 166 * while inside this method. Doing so can royally muck up the 167 * build. 168 * </p> 169 * 170 * @param element the finished <code>Element</code> 171 * 172 * @return the nodes to be added to the tree 173 * 174 */ finishMakingElement(Element element)175 public Nodes finishMakingElement(Element element) { 176 return new Nodes(element); 177 } 178 179 180 /** 181 * <p> 182 * Creates a new <code>Document</code> object. 183 * The root element of this document is initially set to 184 * <code><root xmlns=http://www.xom.nu/fakeRoot""/></code>. 185 * This is only temporary. As soon as the real root element's 186 * start-tag is read, this element is replaced by the real root. 187 * This fake root should never be exposed. 188 * </p> 189 * 190 * <p> 191 * The builder calls this method at the beginning of 192 * each document, before it calls any other method in this class. 193 * Thus this is a useful place to perform per-document 194 * initialization tasks. 195 * </p> 196 * 197 * <p> 198 * Subclasses may change the root element, content, 199 * or other characteristics of the document 200 * returned. However, this method must not return null 201 * or the builder will throw a <code>ParsingException</code>. 202 * </p> 203 * 204 * @return the newly created <code>Document</code> 205 */ startMakingDocument()206 public Document startMakingDocument() { 207 return new Document( 208 Element.build("root", "http://www.xom.nu/fakeRoot", "root") 209 ); 210 } 211 212 213 /** 214 * <p> 215 * Signals the end of a document. The default implementation of 216 * this method does nothing. The builder does not 217 * call this method if an exception is thrown while building 218 * a document. 219 * </p> 220 * 221 * @param document the completed <code>Document</code> 222 */ finishMakingDocument(Document document)223 public void finishMakingDocument(Document document) {} 224 225 226 /** 227 * <p> 228 * Returns a new <code>Nodes</code> object containing an 229 * attribute in the specified namespace 230 * with the specified name and type. 231 * </p> 232 * 233 * <p> 234 * Subclasses may change the nodes returned from this method. 235 * They may return a <code>Nodes</code> object containing any 236 * number of children and attributes which are appended and 237 * added to the current parent element. This <code>Nodes</code> 238 * object may not contain any <code>Document</code> objects. 239 * All of the nodes returned must be parentless. 240 * Subclasses may return an empty <code>Nodes</code> to indicate 241 * the attribute should not be created. 242 * </p> 243 * 244 * @param name the prefixed name of the attribute 245 * @param URI the namespace URI 246 * @param value the attribute value 247 * @param type the attribute type 248 * 249 * @return the nodes to be added to the tree 250 */ makeAttribute(String name, String URI, String value, Attribute.Type type)251 public Nodes makeAttribute(String name, String URI, 252 String value, Attribute.Type type) { 253 return new Nodes(new Attribute(name, URI, value, type)); 254 } 255 256 257 /** 258 * <p> 259 * Returns a new <code>Nodes</code> object containing a 260 * comment with the specified text. 261 * </p> 262 * 263 * <p> 264 * Subclasses may change the content or other 265 * characteristics of the comment returned. 266 * Subclasses may change the nodes returned from this method. 267 * They may return a <code>Nodes</code> object containing any 268 * number of children and attributes which are appended and 269 * added to the current parent element. This <code>Nodes</code> 270 * object should not contain any <code>Document</code> objects. 271 * All of the nodes returned must be parentless. 272 * Subclasses may return an empty <code>Nodes</code> to indicate 273 * the comment should not be included in the 274 * finished document. 275 * </p> 276 * 277 * @param data the complete text content of the comment 278 * 279 * @return the nodes to be added to the tree 280 */ makeComment(String data)281 public Nodes makeComment(String data) { 282 return new Nodes(new Comment(data)); 283 } 284 285 286 /** 287 * <p> 288 * Returns a new <code>Nodes</code> object containing a 289 * <code>DocType</code> object with the specified root element 290 * name, system ID, and public ID. 291 * </p> 292 * 293 * <p> 294 * Subclasses may change the root element name, public ID, 295 * system ID, or other characteristics of the <code>DocType</code> 296 * returned. Subclasses may change the nodes returned from this 297 * method. They may return a <code>Nodes</code> object containing 298 * any number of comments and processing instructions which are 299 * appended to the current parent node. This <code>Nodes</code> 300 * object may not contain any <code>Document</code>, 301 * <code>Element</code>, <code>Attribute</code>, or 302 * <code>Text</code> objects. All of the nodes returned must be 303 * parentless. Subclasses may return an empty <code>Nodes</code> to 304 * indicate the <code>DocType</code> should not be included in the 305 * finished document. 306 * </p> 307 * 308 * @param rootElementName the declared, qualified name 309 * for the root element 310 * @param publicID the public ID of the external DTD subset 311 * @param systemID the URL of the external DTD subset 312 * 313 * @return the nodes to be added to the document 314 */ makeDocType(String rootElementName, String publicID, String systemID)315 public Nodes makeDocType(String rootElementName, 316 String publicID, String systemID) { 317 return new Nodes(new DocType(rootElementName, publicID, systemID)); 318 } 319 320 321 /** 322 * <p> 323 * Returns a new <code>Nodes</code> object containing a 324 * text node with the specified content. 325 * </p> 326 * 327 * <p> 328 * Subclasses may change the content or other characteristics of 329 * the text returned. Subclasses may also change the nodes 330 * returned from this method. They may return a <code>Nodes</code> 331 * object containing any number of nodes which are added or 332 * appended to the current parent node. This <code>Nodes</code> 333 * object must not contain any <code>Document</code> nodes. All of 334 * the nodes returned must be parentless. Subclasses may return an 335 * empty <code>Nodes</code> to indicate the text should not be 336 * included in the finished document. 337 * </p> 338 * 339 * @param data the complete text content of the node 340 * 341 * @return the nodes to be added to the tree 342 */ makeText(String data)343 public Nodes makeText(String data) { 344 return new Nodes(new Text(data)); 345 } 346 347 348 /** 349 * <p> 350 * Returns a new <code>Nodes</code> object containing a 351 * <code>CDATASection</code> node with the specified content. 352 * </p> 353 * 354 * @param data the complete text content of the node 355 * 356 * @return the nodes to be added to the tree 357 */ makeCDATASection(String data)358 Nodes makeCDATASection(String data) { 359 return makeText(data); 360 } 361 362 363 /** 364 * <p> 365 * Returns a new <code>Nodes</code> object containing a 366 * new <code>ProcessingInstruction</code> object with 367 * the specified target and data. 368 * </p> 369 * 370 * <p> 371 * Subclasses may change the target, data, or other 372 * characteristics of the <code>ProcessingInstruction</code> 373 * returned. Subclasses may change the nodes returned from this 374 * method. They may return a <code>Nodes</code> object containing 375 * any number of nodes which are added or 376 * appended to the current parent node. This <code>Nodes</code> 377 * object must not contain any <code>Document</code> nodes. 378 * If the processing instruction appears in the prolog or epilog 379 * of the document, then it must also not contain any 380 * <code>Element</code>, <code>Attribute</code>, or 381 * <code>Text</code> objects. 382 * All of the nodes returned must be parentless. Subclasses 383 * may return an empty <code>Nodes</code> to indicate the 384 * processing instruction should not be included in the 385 * finished document. 386 * </p> 387 * 388 * @param target the target of the processing instruction 389 * @param data the data of the processing instruction 390 * 391 * @return the nodes to be added to the tree 392 */ makeProcessingInstruction( String target, String data)393 public Nodes makeProcessingInstruction( 394 String target, String data) { 395 return new Nodes(new ProcessingInstruction(target, data)); 396 } 397 398 addAttribute(Element element, Attribute attribute)399 void addAttribute(Element element, Attribute attribute) { 400 element.addAttribute(attribute); 401 } 402 403 insertChild(Element element, Node child, int position)404 void insertChild(Element element, Node child, int position) { 405 element.insertChild(child, position); 406 } 407 408 409 } 410