KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > functions > StandardCollectionURIResolver


1 package net.sf.saxon.functions;
2
3 import net.sf.saxon.*;
4 import net.sf.saxon.event.Builder;
5 import net.sf.saxon.event.Stripper;
6 import net.sf.saxon.expr.MappingFunction;
7 import net.sf.saxon.expr.MappingIterator;
8 import net.sf.saxon.expr.XPathContext;
9 import net.sf.saxon.om.*;
10 import net.sf.saxon.pattern.NodeKindTest;
11 import net.sf.saxon.trans.DynamicError;
12 import net.sf.saxon.trans.XPathException;
13 import net.sf.saxon.value.ObjectValue;
14 import org.xml.sax.XMLReader JavaDoc;
15
16 import javax.xml.transform.Source JavaDoc;
17 import javax.xml.transform.TransformerException JavaDoc;
18 import javax.xml.transform.stream.StreamSource JavaDoc;
19 import java.io.File JavaDoc;
20 import java.io.FilenameFilter JavaDoc;
21 import java.net.URI JavaDoc;
22 import java.net.URISyntaxException JavaDoc;
23
24 /**
25  * This class implements the default collection URI Resolver.
26  * <p>
27  * This supports two implementations of collections. If the URI supplied uses the "file:/" scheme, and the
28  * file that is referenced is a directory, then the collection is the set of files in that directory. Query parameters
29  * may be included in the URI:
30  * <ul>
31  * <li>recurse=yes|no controls whether the directory is scanned recursively; </li>
32  * <li>strip=yes|no determines whether whitespace text nodes are stripped from the selected documents; </li>
33  * <li>val=strict|lax|preserve|strip determines whether schema validation is applied;</li>
34  * <li>select=pattern determines which files in the directory are selected.</li>
35  * <li>onerror=fail|warn|ignore determines the action taken if processing of a file fails</li>
36  * <li>parser=qualified.class.name selects the parser (XMLReader) to be used to read the files</li>
37  * </ul>
38  * <p>
39  * Otherwise, the resolver attempts to dereference the URI to obtain a catalog file. This is an XML file
40  * containing a list of documents, in the format: </p>
41  * <code><pre>
42  * <collection>
43  * <doc HREF="doc1.xml"/>
44  * <doc HREF="doc2.xml"/>
45  * </collection>
46  * </pre></code>
47  */

48
49 public class StandardCollectionURIResolver implements CollectionURIResolver, MappingFunction {
50
51     /**
52      * Resolve a URI.
53      *
54      * @param href The relative URI of the collection. This corresponds to the
55      * argument supplied to the collection() function. If the collection() function
56      * was called with no arguments (to get the "default collection") this argument
57      * will be null.
58      * @param base The base URI that should be used. This is the base URI of the
59      * static context in which the call to collection() was made, typically the URI
60      * of the stylesheet or query module
61      * @return an Iterator over the documents in the collection. The items returned
62      * by this iterator must implement the {@link net.sf.saxon.om.NodeInfo} interface.
63      * <p/>
64      * If the URI is not recognized, the method may either return an empty iterator,
65      * in which case no error is reported, or it may throw an exception, in which case
66      * the query or transformation fails. Returning null has the same effect as returning
67      * an empty iterator.
68      */

69
70     public SequenceIterator resolve(String JavaDoc href, String JavaDoc base, XPathContext context) throws XPathException {
71
72         if (href == null) {
73             // default collection. This returns empty, we previously threw an error.
74
return null;
75         }
76
77         if (base == null) {
78             base = StandardURIResolver.tryToExpand(base);
79             if (base == null) {
80                 DynamicError err = new DynamicError(
81                     "Cannot resolve relative URI: no base URI available");
82                 err.setXPathContext(context);
83                 throw err;
84             }
85         }
86
87         URI JavaDoc resolvedURI;
88         URIQueryParameters params = null;
89         try {
90             URI JavaDoc relative = new URI JavaDoc(href);
91             String JavaDoc query = relative.getQuery();
92             if (query != null) {
93                 params = new URIQueryParameters(query, context.getController().getConfiguration());
94                 int q = href.indexOf('?');
95                 href = href.substring(0, q);
96             }
97             resolvedURI = new URI JavaDoc(base).resolve(href);
98         } catch (URISyntaxException JavaDoc e) {
99             DynamicError err = new DynamicError(
100                     "Invalid URI " + Err.wrap(href) + " passed to collection() function");
101             err.setXPathContext(context);
102             throw err;
103         }
104
105         if ("file".equals(resolvedURI.getScheme())) {
106             File JavaDoc file = new File JavaDoc(resolvedURI);
107             if (!file.exists()) {
108                 DynamicError err = new DynamicError(
109                         "The file or directory " + resolvedURI + " does not exist");
110                 err.setXPathContext(context);
111                 throw err;
112             }
113             if (file.isDirectory()) {
114                 return directoryContents(file, params, context);
115             }
116         }
117         return catalogContents(resolvedURI, params, context);
118
119     }
120
121     private SequenceIterator directoryContents(File JavaDoc directory, URIQueryParameters params, XPathContext context) {
122
123         FilenameFilter JavaDoc filter = null;
124
125         if (params != null) {
126             FilenameFilter JavaDoc f = params.getFilenameFilter();
127             if (f != null) {
128                 filter = f;
129             }
130         }
131
132         File JavaDoc[] files;
133         if (filter == null) {
134             files = directory.listFiles();
135         } else {
136             files = directory.listFiles(filter);
137         }
138
139         ObjectValue[] fileValues = new ObjectValue[files.length];
140         for (int f=0; f<files.length; f++) {
141             fileValues[f] = new ObjectValue(files[f]);
142         }
143
144         FileExpander expander = new FileExpander(params);
145         return new MappingIterator(new ArrayIterator(fileValues), expander, context);
146     }
147
148     private SequenceIterator catalogContents(URI JavaDoc catalogFile, URIQueryParameters params, XPathContext context)
149     throws XPathException {
150
151         DocumentInfo catalog =
152                 (DocumentInfo) Document.makeDoc(catalogFile.toString(), null, context, null);
153         if (catalog==null) {
154             // we failed to read the catalogue
155
DynamicError err = new DynamicError("Failed to load collection catalogue " + catalogFile);
156             err.setXPathContext(context);
157             throw err;
158         }
159
160         // Now return an iterator over the documents that it refers to
161

162         SequenceIterator iter =
163                 catalog.iterateAxis(Axis.CHILD, NodeKindTest.ELEMENT);
164         NodeInfo top;
165         while (true) {
166             top = (NodeInfo)iter.next();
167             if (top == null) break;
168             if (!("collection".equals(top.getLocalPart()) &&
169                     top.getURI().equals("") )) {
170                 DynamicError err = new DynamicError("collection catalogue must contain top-level element <collection>");
171                 err.setXPathContext(context);
172                 throw err;
173             }
174             break;
175         }
176
177         SequenceIterator documents =
178                 top.iterateAxis(Axis.CHILD, NodeKindTest.ELEMENT);
179
180         return new MappingIterator(documents, this, context);
181     }
182
183
184
185     /**
186      * Map from doc elements in the catalogue document to nodes
187      * returned in the result
188      * @param item A doc element in the catalogue document
189      * @param context The dynamic evaluation context
190      * @return the document or element referenced by the @href attribute of the doc
191      * element in the catalogue
192      * @throws net.sf.saxon.trans.XPathException if the document cannot be retrieved or parsed, unless
193      * error recovery has been chosen.
194      */

195
196     public Object JavaDoc map(Item item, XPathContext context) throws XPathException {
197         NodeInfo element = (NodeInfo)item;
198         if (!("doc".equals(element.getLocalPart()) &&
199                 element.getURI().equals("") )) {
200             DynamicError err = new DynamicError(
201                     "children of <collection> element must be <doc> elements");
202             err.setXPathContext(context);
203             throw err;
204         }
205         String JavaDoc href = Navigator.getAttributeValue(element, "", "href");
206         if (href==null) {
207             DynamicError err = new DynamicError(
208                     "\"<doc> element in catalogue has no @href attribute\"");
209             err.setXPathContext(context);
210             throw err;
211         }
212
213         NodeInfo target = Document.makeDoc(href, element.getBaseURI(), context, null);
214         return target;
215     }
216
217     private static class FileExpander implements MappingFunction {
218
219         private URIQueryParameters params;
220         boolean recurse = false;
221         boolean strip = false;
222         int validation = Validation.STRIP;
223         XMLReader JavaDoc parser = null;
224         int onError = URIQueryParameters.ON_ERROR_FAIL;
225         FilenameFilter JavaDoc filter = null;
226
227         public FileExpander(URIQueryParameters params) {
228             this.params = params;
229             if (params != null) {
230                 FilenameFilter JavaDoc f = params.getFilenameFilter();
231                 if (f != null) {
232                     filter = f;
233                 }
234                 Boolean JavaDoc r = params.getRecurse();
235                 if (r != null) {
236                     recurse = r.booleanValue();
237                 }
238                 Integer JavaDoc v = params.getValidationMode();
239                 if (v != null) {
240                     validation = v.intValue();
241                 }
242                 Boolean JavaDoc s = params.getStripSpace();
243                 if (s != null) {
244                     strip = s.booleanValue();
245                 }
246                 Integer JavaDoc e = params.getOnError();
247                 if (e != null) {
248                     onError = e.intValue();
249                 }
250                 XMLReader JavaDoc p = params.getXMLReader();
251                 if (p != null) {
252                     parser = p;
253                 }
254             }
255
256         }
257
258         /**
259          * Map one item to a sequence.
260          *
261          * @param item The item to be mapped.
262          * If context is supplied, this must be the same as context.currentItem().
263          * @param context The processing context. Some mapping functions use this because they require
264          * context information. Some mapping functions modify the context by maintaining the context item
265          * and position. In other cases, the context may be null.
266          * @return either (a) a SequenceIterator over the sequence of items that the supplied input
267          * item maps to, or (b) an Item if it maps to a single item, or (c) null if it maps to an empty
268          * sequence.
269          */

270
271         public Object JavaDoc map(Item item, XPathContext context) throws XPathException {
272             File JavaDoc file = (File JavaDoc)((ObjectValue)item).getObject();
273             if (file.isDirectory()) {
274                 if (recurse) {
275                    File JavaDoc[] files;
276                     if (filter == null) {
277                         files = file.listFiles();
278                     } else {
279                         files = file.listFiles(filter);
280                     }
281
282                     ObjectValue[] fileValues = new ObjectValue[files.length];
283                     for (int f=0; f<files.length; f++) {
284                         fileValues[f] = new ObjectValue(files[f]);
285                     }
286
287                     FileExpander expander = new FileExpander(params);
288                     return new MappingIterator(new ArrayIterator(fileValues), expander, context);
289                 } else {
290                     return null;
291                 }
292             } else {
293                 try {
294                     Source JavaDoc source = new StreamSource JavaDoc(file.toURI().toString());
295                     if (validation != Validation.STRIP && validation != Validation.PRESERVE) {
296                         source = AugmentedSource.makeAugmentedSource(source);
297                         ((AugmentedSource)source).setSchemaValidationMode(validation);
298                     }
299                     if (parser != null) {
300                         source = AugmentedSource.makeAugmentedSource(source);
301                         ((AugmentedSource)source).setXMLReader(parser);
302                     }
303                     Stripper stripper = null;
304
305                     if (strip) {
306                         stripper = AllElementStripper.getInstance();
307                         stripper.setStripAll();
308                     }
309                     Configuration config = context.getController().getConfiguration();
310                     NodeInfo contextNode = Builder.build(source, stripper, config);
311                     return contextNode.getDocumentRoot();
312                 } catch (XPathException err) {
313                     if (onError == URIQueryParameters.ON_ERROR_IGNORE) {
314                         return null;
315                     } else if (onError == URIQueryParameters.ON_ERROR_WARNING) {
316                         try {
317                             context.getController().getErrorListener().warning(err);
318                         } catch (TransformerException JavaDoc err2) {
319                             //
320
}
321                         return null;
322                     } else {
323                         throw err;
324                     }
325                 }
326             }
327         }
328     }
329
330
331
332
333 }
334
335 //
336
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
337
// you may not use this file except in compliance with the License. You may obtain a copy of the
338
// License at http://www.mozilla.org/MPL/
339
//
340
// Software distributed under the License is distributed on an "AS IS" basis,
341
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
342
// See the License for the specific language governing rights and limitations under the License.
343
//
344
// The Original Code is: all this file.
345
//
346
// The Initial Developer of the Original Code is Michael H. Kay.
347
//
348
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
349
//
350
// Contributor(s): none.
351
//
352

353
Popular Tags