1   
2   
3   
4   
5   
6   
7   
8   package org.dom4j;
9   
10  import java.io.StringReader;
11  import java.util.List;
12  import java.util.Map;
13  import java.util.StringTokenizer;
14  
15  import org.dom4j.io.SAXReader;
16  import org.dom4j.rule.Pattern;
17  
18  import org.jaxen.VariableContext;
19  
20  import org.xml.sax.InputSource;
21  
22  /***
23   * <p>
24   * <code>DocumentHelper</code> is a collection of helper methods for using
25   * DOM4J.
26   * </p>
27   * 
28   * @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
29   * @version $Revision: 1.26 $
30   */
31  public final class DocumentHelper {
32      private DocumentHelper() {
33      }
34  
35      private static DocumentFactory getDocumentFactory() {
36          return DocumentFactory.getInstance();
37      }
38  
39      
40      public static Document createDocument() {
41          return getDocumentFactory().createDocument();
42      }
43  
44      public static Document createDocument(Element rootElement) {
45          return getDocumentFactory().createDocument(rootElement);
46      }
47  
48      public static Element createElement(QName qname) {
49          return getDocumentFactory().createElement(qname);
50      }
51  
52      public static Element createElement(String name) {
53          return getDocumentFactory().createElement(name);
54      }
55  
56      public static Attribute createAttribute(Element owner, QName qname,
57              String value) {
58          return getDocumentFactory().createAttribute(owner, qname, value);
59      }
60  
61      public static Attribute createAttribute(Element owner, String name,
62              String value) {
63          return getDocumentFactory().createAttribute(owner, name, value);
64      }
65  
66      public static CDATA createCDATA(String text) {
67          return DocumentFactory.getInstance().createCDATA(text);
68      }
69  
70      public static Comment createComment(String text) {
71          return DocumentFactory.getInstance().createComment(text);
72      }
73  
74      public static Text createText(String text) {
75          return DocumentFactory.getInstance().createText(text);
76      }
77  
78      public static Entity createEntity(String name, String text) {
79          return DocumentFactory.getInstance().createEntity(name, text);
80      }
81  
82      public static Namespace createNamespace(String prefix, String uri) {
83          return DocumentFactory.getInstance().createNamespace(prefix, uri);
84      }
85  
86      public static ProcessingInstruction createProcessingInstruction(String pi,
87              String d) {
88          return getDocumentFactory().createProcessingInstruction(pi, d);
89      }
90  
91      public static ProcessingInstruction createProcessingInstruction(String pi,
92              Map data) {
93          return getDocumentFactory().createProcessingInstruction(pi, data);
94      }
95  
96      public static QName createQName(String localName, Namespace namespace) {
97          return getDocumentFactory().createQName(localName, namespace);
98      }
99  
100     public static QName createQName(String localName) {
101         return getDocumentFactory().createQName(localName);
102     }
103 
104     /***
105      * <p>
106      * <code>createXPath</code> parses an XPath expression and creates a new
107      * XPath <code>XPath</code> instance using the singleton {@link
108      * DocumentFactory}.
109      * </p>
110      * 
111      * @param xpathExpression
112      *            is the XPath expression to create
113      * 
114      * @return a new <code>XPath</code> instance
115      * 
116      * @throws InvalidXPathException
117      *             if the XPath expression is invalid
118      */
119     public static XPath createXPath(String xpathExpression)
120             throws InvalidXPathException {
121         return getDocumentFactory().createXPath(xpathExpression);
122     }
123 
124     /***
125      * <p>
126      * <code>createXPath</code> parses an XPath expression and creates a new
127      * XPath <code>XPath</code> instance using the singleton {@link
128      * DocumentFactory}.
129      * </p>
130      * 
131      * @param xpathExpression
132      *            is the XPath expression to create
133      * @param context
134      *            is the variable context to use when evaluating the XPath
135      * 
136      * @return a new <code>XPath</code> instance
137      * 
138      * @throws InvalidXPathException
139      *             if the XPath expression is invalid
140      */
141     public static XPath createXPath(String xpathExpression,
142             VariableContext context) throws InvalidXPathException {
143         return getDocumentFactory().createXPath(xpathExpression, context);
144     }
145 
146     /***
147      * <p>
148      * <code>createXPathFilter</code> parses a NodeFilter from the given XPath
149      * filter expression using the singleton {@link DocumentFactory}. XPath
150      * filter expressions occur within XPath expressions such as
151      * <code>self::node()[ filterExpression ]</code>
152      * </p>
153      * 
154      * @param xpathFilterExpression
155      *            is the XPath filter expression to create
156      * 
157      * @return a new <code>NodeFilter</code> instance
158      */
159     public static NodeFilter createXPathFilter(String xpathFilterExpression) {
160         return getDocumentFactory().createXPathFilter(xpathFilterExpression);
161     }
162 
163     /***
164      * <p>
165      * <code>createPattern</code> parses the given XPath expression to create
166      * an XSLT style {@link Pattern}instance which can then be used in an XSLT
167      * processing model.
168      * </p>
169      * 
170      * @param xpathPattern
171      *            is the XPath pattern expression to create
172      * 
173      * @return a new <code>Pattern</code> instance
174      */
175     public static Pattern createPattern(String xpathPattern) {
176         return getDocumentFactory().createPattern(xpathPattern);
177     }
178 
179     /***
180      * <p>
181      * <code>selectNodes</code> performs the given XPath expression on the
182      * {@link List}of {@link Node}instances appending all the results together
183      * into a single list.
184      * </p>
185      * 
186      * @param xpathFilterExpression
187      *            is the XPath filter expression to evaluate
188      * @param nodes
189      *            is the list of nodes on which to evalute the XPath
190      * 
191      * @return the results of all the XPath evaluations as a single list
192      */
193     public static List selectNodes(String xpathFilterExpression, List nodes) {
194         XPath xpath = createXPath(xpathFilterExpression);
195 
196         return xpath.selectNodes(nodes);
197     }
198 
199     /***
200      * <p>
201      * <code>selectNodes</code> performs the given XPath expression on the
202      * {@link List}of {@link Node}instances appending all the results together
203      * into a single list.
204      * </p>
205      * 
206      * @param xpathFilterExpression
207      *            is the XPath filter expression to evaluate
208      * @param node
209      *            is the Node on which to evalute the XPath
210      * 
211      * @return the results of all the XPath evaluations as a single list
212      */
213     public static List selectNodes(String xpathFilterExpression, Node node) {
214         XPath xpath = createXPath(xpathFilterExpression);
215 
216         return xpath.selectNodes(node);
217     }
218 
219     /***
220      * <p>
221      * <code>sort</code> sorts the given List of Nodes using an XPath
222      * expression as a {@link java.util.Comparator}.
223      * </p>
224      * 
225      * @param list
226      *            is the list of Nodes to sort
227      * @param xpathExpression
228      *            is the XPath expression used for comparison
229      */
230     public static void sort(List list, String xpathExpression) {
231         XPath xpath = createXPath(xpathExpression);
232         xpath.sort(list);
233     }
234 
235     /***
236      * <p>
237      * <code>sort</code> sorts the given List of Nodes using an XPath
238      * expression as a {@link java.util.Comparator}and optionally removing
239      * duplicates.
240      * </p>
241      * 
242      * @param list
243      *            is the list of Nodes to sort
244      * @param expression
245      *            is the XPath expression used for comparison
246      * @param distinct
247      *            if true then duplicate values (using the sortXPath for
248      *            comparisions) will be removed from the List
249      */
250     public static void sort(List list, String expression, boolean distinct) {
251         XPath xpath = createXPath(expression);
252         xpath.sort(list, distinct);
253     }
254 
255     /***
256      * <p>
257      * <code>parseText</code> parses the given text as an XML document and
258      * returns the newly created Document.
259      * </p>
260      * 
261      * @param text
262      *            the XML text to be parsed
263      * 
264      * @return a newly parsed Document
265      * 
266      * @throws DocumentException
267      *             if the document could not be parsed
268      */
269     public static Document parseText(String text) throws DocumentException {
270         Document result = null;
271 
272         SAXReader reader = new SAXReader();
273         String encoding = getEncoding(text);
274 
275         InputSource source = new InputSource(new StringReader(text));
276         source.setEncoding(encoding);
277 
278         result = reader.read(source);
279 
280         
281         
282         if (result.getXMLEncoding() == null) {
283             result.setXMLEncoding(encoding);
284         }
285 
286         return result;
287     }
288 
289     private static String getEncoding(String text) {
290         String result = null;
291 
292         String xml = text.trim();
293 
294         if (xml.startsWith("<?xml")) {
295             int end = xml.indexOf("?>");
296             String sub = xml.substring(0, end);
297             StringTokenizer tokens = new StringTokenizer(sub, " =\"\'");
298 
299             while (tokens.hasMoreTokens()) {
300                 String token = tokens.nextToken();
301 
302                 if ("encoding".equals(token)) {
303                     if (tokens.hasMoreTokens()) {
304                         result = tokens.nextToken();
305                     }
306 
307                     break;
308                 }
309             }
310         }
311 
312         return result;
313     }
314 
315     /***
316      * <p>
317      * makeElement
318      * </p>
319      * a helper method which navigates from the given Document or Element node
320      * to some Element using the path expression, creating any necessary
321      * elements along the way. For example the path <code>a/b/c</code> would
322      * get the first child <a> element, which would be created if it did
323      * not exist, then the next child <b> and so on until finally a
324      * <c> element is returned.
325      * 
326      * @param source
327      *            is the Element or Document to start navigating from
328      * @param path
329      *            is a simple path expression, seperated by '/' which denotes
330      *            the path from the source to the resulting element such as
331      *            a/b/c
332      * 
333      * @return the first Element on the given path which either already existed
334      *         on the path or were created by this method.
335      */
336     public static Element makeElement(Branch source, String path) {
337         StringTokenizer tokens = new StringTokenizer(path, "/");
338         Element parent;
339 
340         if (source instanceof Document) {
341             Document document = (Document) source;
342             parent = document.getRootElement();
343 
344             
345             
346             String name = tokens.nextToken();
347 
348             if (parent == null) {
349                 parent = document.addElement(name);
350             }
351         } else {
352             parent = (Element) source;
353         }
354 
355         Element element = null;
356 
357         while (tokens.hasMoreTokens()) {
358             String name = tokens.nextToken();
359 
360             if (name.indexOf(':') > 0) {
361                 element = parent.element(parent.getQName(name));
362             } else {
363                 element = parent.element(name);
364             }
365 
366             if (element == null) {
367                 element = parent.addElement(name);
368             }
369 
370             parent = element;
371         }
372 
373         return element;
374     }
375 }
376 
377 
378 
379 
380 
381 
382 
383 
384 
385 
386 
387 
388 
389 
390 
391 
392 
393 
394 
395 
396 
397 
398 
399 
400 
401 
402 
403 
404 
405 
406 
407 
408 
409 
410 
411 
412