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