001: /* Copyright 2002-2005 Elliotte Rusty Harold
002:
003: This library is free software; you can redistribute it and/or modify
004: it under the terms of version 2.1 of the GNU Lesser General Public
005: License as published by the Free Software Foundation.
006:
007: This library is distributed in the hope that it will be useful,
008: but WITHOUT ANY WARRANTY; without even the implied warranty of
009: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010: GNU Lesser General Public License for more details.
011:
012: You should have received a copy of the GNU Lesser General Public
013: License along with this library; if not, write to the
014: Free Software Foundation, Inc., 59 Temple Place, Suite 330,
015: Boston, MA 02111-1307 USA
016:
017: You can contact Elliotte Rusty Harold by sending e-mail to
018: elharo@metalab.unc.edu. Please include the word "XOM" in the
019: subject line. The XOM home page is located at http://www.xom.nu/
020: */
021:
022: package nu.xom;
023:
024: /**
025: * <p>
026: * Builders use a <code>NodeFactory</code> object
027: * to construct each <code>Node</code> object (<code>Element</code>,
028: * <code>Text</code>, <code>Attribute</code>, etc.) they add to the
029: * tree. The default implementation simply calls the relevant
030: * constructor, stuffs the resulting <code>Node</code> object in a
031: * length one <code>Nodes</code> object, and returns it.
032: * </p>
033: *
034: * <p>
035: * Subclassing this class allows builders to produce
036: * instance of subclasses (for example,
037: * <code>HTMLElement</code>) instead of the
038: * base classes.
039: * </p>
040: *
041: * <p>
042: * Subclasses can also filter content while building.
043: * For example, namespaces could be added to or changed
044: * on all elements. Comments could be deleted. Processing
045: * instructions can be changed into elements. An
046: * <code>xinclude:include</code> element could be replaced
047: * with the content it references. All such changes must be
048: * consistent with the usual rules of well-formedness. For
049: * example, the <code>makeDocType()</code> method should not
050: * return a list containing two <code>DocType</code> objects
051: * because an XML document can have at most one document type
052: * declaration. Nor should it return a list containing an element,
053: * because an element cannot appear in a document prolog. However,
054: * it could return a list containing any number of comments and
055: * processing instructions, and not more than one <code>DocType</code>
056: * object.
057: * </p>
058: *
059: * @author Elliotte Rusty Harold
060: * @version 1.1d5
061: *
062: */
063: public class NodeFactory {
064:
065: /**
066: * <p>
067: * Constructs a new node factory.
068: * </p>
069: *
070: */
071: public NodeFactory() {
072: }
073:
074: /**
075: * <p>
076: * Creates a new element in the specified namespace
077: * with the specified name. The builder calls this
078: * method to make the root element of the document.
079: * </p>
080: *
081: * <p>
082: * Subclasses may change the name, namespace, content, or other
083: * characteristics of the element returned.
084: * The default implementation merely calls
085: * <code>startMakingElement</code>. However, when subclassing, it
086: * is often useful to be able to easily distinguish between the
087: * root element and a non-root element because the root element
088: * cannot be detached. Therefore, subclasses must not return null
089: * from this method. Doing so will cause a
090: * <code>NullPointerException</code>.
091: * </p>
092: *
093: * @param name the qualified name of the element
094: * @param namespace the namespace URI of the element
095: *
096: * @return the new root element
097: */
098: public Element makeRootElement(String name, String namespace) {
099: return startMakingElement(name, namespace);
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: */
126: public Element startMakingElement(String name, String namespace) {
127: return new Element(name, namespace);
128: }
129:
130: /**
131: * <p>
132: * Signals the end of an element. This method should return
133: * the <code>Nodes</code> to be added to the tree.
134: * They need not contain the <code>Element</code> that
135: * was passed to this method, though most often they will.
136: * By default the <code>Nodes</code> returned contain
137: * only the built element. However, subclasses may return
138: * a list containing any number of nodes, all of which will be
139: * added to the tree at the current position in the order given by
140: * the list (subject to the usual well-formedness constraints, of
141: * course. For instance, the list should not contain a
142: * <code>DocType</code> object unless the element is the root
143: * element, and the document does not already have a
144: * <code>DocType</code>). All of the nodes returned must be
145: * parentless. If this method returns an empty list,
146: * then the element (including all its contents) is not included
147: * in the finished document.
148: * </p>
149: *
150: * <p>
151: * To process an element at a time, override this method in a
152: * subclass so that it functions as a callback. When you're done
153: * processing the <code>Element</code>, return an empty list so
154: * that it will be removed from the tree and garbage collected.
155: * Be careful not to return an empty list for the root element
156: * though. That is, when the element passed to this method is the
157: * root element, the list returned must contain exactly one
158: * <code>Element</code> object. The simplest way to check this
159: * is testing if <code>element.getParent() instanceof
160: * Document</code>.
161: * </p>
162: *
163: * <p>
164: * Do not detach <code>element</code> or any of its ancestors
165: * while inside this method. Doing so can royally muck up the
166: * build.
167: * </p>
168: *
169: * @param element the finished <code>Element</code>
170: *
171: * @return the nodes to be added to the tree
172: *
173: */
174: public Nodes finishMakingElement(Element element) {
175: return new Nodes(element);
176: }
177:
178: /**
179: * <p>
180: * Creates a new <code>Document</code> object.
181: * The root element of this document is initially set to
182: * <code><root xmlns=http://www.xom.nu/fakeRoot""/></code>.
183: * This is only temporary. As soon as the real root element's
184: * start-tag is read, this element is replaced by the real root.
185: * This fake root should never be exposed.
186: * </p>
187: *
188: * <p>
189: * The builder calls this method at the beginning of
190: * each document, before it calls any other method in this class.
191: * Thus this is a useful place to perform per-document
192: * initialization tasks.
193: * </p>
194: *
195: * <p>
196: * Subclasses may change the root element, content,
197: * or other characteristics of the document
198: * returned. However, this method must not return null
199: * or the builder will throw a <code>ParsingException</code>.
200: * </p>
201: *
202: * @return the newly created <code>Document</code>
203: */
204: public Document startMakingDocument() {
205: return new Document(Element.build("root",
206: "http://www.xom.nu/fakeRoot", "root"));
207: }
208:
209: /**
210: * <p>
211: * Signals the end of a document. The default implementation of
212: * this method does nothing. The builder does not
213: * call this method if an exception is thrown while building
214: * a document.
215: * </p>
216: *
217: * @param document the completed <code>Document</code>
218: */
219: public void finishMakingDocument(Document document) {
220: }
221:
222: /**
223: * <p>
224: * Returns a new <code>Nodes</code> object containing an
225: * attribute in the specified namespace
226: * with the specified name and type.
227: * </p>
228: *
229: * <p>
230: * Subclasses may change the nodes returned from this method.
231: * They may return a <code>Nodes</code> object containing any
232: * number of children and attributes which are appended and
233: * added to the current parent element. This <code>Nodes</code>
234: * object may not contain any <code>Document</code> objects.
235: * All of the nodes returned must be parentless.
236: * Subclasses may return an empty <code>Nodes</code> to indicate
237: * the attribute should not be created.
238: * </p>
239: *
240: * @param name the prefixed name of the attribute
241: * @param URI the namespace URI
242: * @param value the attribute value
243: * @param type the attribute type
244: *
245: * @return the nodes to be added to the tree
246: */
247: public Nodes makeAttribute(String name, String URI, String value,
248: Attribute.Type type) {
249: return new Nodes(new Attribute(name, URI, value, type));
250: }
251:
252: /**
253: * <p>
254: * Returns a new <code>Nodes</code> object containing a
255: * comment with the specified text.
256: * </p>
257: *
258: * <p>
259: * Subclasses may change the content or other
260: * characteristics of the comment returned.
261: * Subclasses may change the nodes returned from this method.
262: * They may return a <code>Nodes</code> object containing any
263: * number of children and attributes which are appended and
264: * added to the current parent element. This <code>Nodes</code>
265: * object should not contain any <code>Document</code> objects.
266: * All of the nodes returned must be parentless.
267: * Subclasses may return an empty <code>Nodes</code> to indicate
268: * the comment should not be included in the
269: * finished document.
270: * </p>
271: *
272: * @param data the complete text content of the comment
273: *
274: * @return the nodes to be added to the tree
275: */
276: public Nodes makeComment(String data) {
277: return new Nodes(new Comment(data));
278: }
279:
280: /**
281: * <p>
282: * Returns a new <code>Nodes</code> object containing a
283: * <code>DocType</code> object with the specified root element
284: * name, system ID, and public ID.
285: * </p>
286: *
287: * <p>
288: * Subclasses may change the root element name, public ID,
289: * system ID, or other characteristics of the <code>DocType</code>
290: * returned. Subclasses may change the nodes returned from this
291: * method. They may return a <code>Nodes</code> object containing
292: * any number of comments and processing instructions which are
293: * appended to the current parent node. This <code>Nodes</code>
294: * object may not contain any <code>Document</code>,
295: * <code>Element</code>, <code>Attribute</code>, or
296: * <code>Text</code> objects. All of the nodes returned must be
297: * parentless. Subclasses may return an empty <code>Nodes</code> to
298: * indicate the <code>DocType</code> should not be included in the
299: * finished document.
300: * </p>
301: *
302: * @param rootElementName the declared, qualified name
303: * for the root element
304: * @param publicID the public ID of the external DTD subset
305: * @param systemID the URL of the external DTD subset
306: *
307: * @return the nodes to be added to the document
308: */
309: public Nodes makeDocType(String rootElementName, String publicID,
310: String systemID) {
311: return new Nodes(new DocType(rootElementName, publicID,
312: systemID));
313: }
314:
315: /**
316: * <p>
317: * Returns a new <code>Nodes</code> object containing a
318: * text node with the specified content.
319: * </p>
320: *
321: * <p>
322: * Subclasses may change the content or other characteristics of
323: * the text returned. Subclasses may also change the nodes
324: * returned from this method. They may return a <code>Nodes</code>
325: * object containing any number of nodes which are added or
326: * appended to the current parent node. This <code>Nodes</code>
327: * object must not contain any <code>Document</code> nodes. All of
328: * the nodes returned must be parentless. Subclasses may return an
329: * empty <code>Nodes</code> to indicate the text should not be
330: * included in the finished document.
331: * </p>
332: *
333: * @param data the complete text content of the node
334: *
335: * @return the nodes to be added to the tree
336: */
337: public Nodes makeText(String data) {
338: return new Nodes(new Text(data));
339: }
340:
341: /**
342: * <p>
343: * Returns a new <code>Nodes</code> object containing a
344: * <code>CDATASection</code> node with the specified content.
345: * </p>
346: *
347: * @param data the complete text content of the node
348: *
349: * @return the nodes to be added to the tree
350: */
351: Nodes makeCDATASection(String data) {
352: return makeText(data);
353: }
354:
355: /**
356: * <p>
357: * Returns a new <code>Nodes</code> object containing a
358: * new <code>ProcessingInstruction</code> object with
359: * the specified target and data.
360: * </p>
361: *
362: * <p>
363: * Subclasses may change the target, data, or other
364: * characteristics of the <code>ProcessingInstruction</code>
365: * returned. Subclasses may change the nodes returned from this
366: * method. They may return a <code>Nodes</code> object containing
367: * any number of nodes which are added or
368: * appended to the current parent node. This <code>Nodes</code>
369: * object must not contain any <code>Document</code> nodes.
370: * If the processing instruction appears in the prolog or epilog
371: * of the document, then it must also not contain any
372: * <code>Element</code>, <code>Attribute</code>, or
373: * <code>Text</code> objects.
374: * All of the nodes returned must be parentless. Subclasses
375: * may return an empty <code>Nodes</code> to indicate the
376: * processing instruction should not be included in the
377: * finished document.
378: * </p>
379: *
380: * @param target the target of the processing instruction
381: * @param data the data of the processing instruction
382: *
383: * @return the nodes to be added to the tree
384: */
385: public Nodes makeProcessingInstruction(String target, String data) {
386: return new Nodes(new ProcessingInstruction(target, data));
387: }
388:
389: void addAttribute(Element element, Attribute attribute) {
390: element.addAttribute(attribute);
391: }
392:
393: void insertChild(Element element, Node child, int position) {
394: element.insertChild(child, position);
395: }
396:
397: }
|