KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > functions > Document


1 package com.icl.saxon.functions;
2 import com.icl.saxon.*;
3 import com.icl.saxon.om.*;
4 import com.icl.saxon.expr.*;
5
6 import javax.xml.transform.URIResolver JavaDoc;
7 import javax.xml.transform.TransformerException JavaDoc;
8 import javax.xml.transform.Source JavaDoc;
9 import javax.xml.transform.sax.SAXSource JavaDoc;
10 import javax.xml.transform.dom.DOMSource JavaDoc;
11
12 import org.xml.sax.InputSource JavaDoc;
13 import org.xml.sax.XMLReader JavaDoc;
14 import org.w3c.dom.Node JavaDoc;
15 import java.net.URL JavaDoc;
16 import java.net.MalformedURLException JavaDoc;
17
18
19 public class Document extends Function {
20
21     private Controller boundController = null;
22
23     public String JavaDoc getName() {
24         return "document";
25     };
26
27     /**
28     * Determine the data type of the expression
29     * @return Value.NODESET
30     */

31
32     public int getDataType() {
33         return Value.NODESET;
34     }
35
36     /**
37     * Simplify and validate.
38     */

39
40     public Expression simplify() throws XPathException {
41         int numArgs = checkArgumentCount(1, 2);
42         argument[0] = argument[0].simplify();
43         if (numArgs==2) {
44             argument[1] = argument[1].simplify();
45         }
46
47         // in principle we could pre-evaluate any call of document() with a
48
// single string argument. But we don't, because we don't yet have access
49
// to the document pool.
50

51         return this;
52     }
53
54
55     /**
56     * evaluate() handles evaluation of the function
57     */

58
59     public Value evaluate(Context c) throws XPathException {
60         int numArgs = getNumberOfArguments();
61
62         Value arg0 = argument[0].evaluate(c);
63         NodeSetValue arg1 = null;
64         if (numArgs==2) {
65             arg1 = argument[1].evaluateAsNodeSet(c);
66         }
67
68         String JavaDoc styleSheetURI = getStaticContext().getBaseURI();
69
70         return getDocuments(arg0, arg1, styleSheetURI, c);
71     }
72
73     /**
74     * getDocuments() evaluates the function.
75     * @param arg0 The value of the first argument
76     * @param arg1 The value of the second argument, if there is one; otherwise null
77     * @param styleSheetURL The URI of the node in the stylesheet containing the expression.
78     * Needed only when the first argument is not a nodeset and the second argument is omitted.
79     * @param context The evaluation context
80     * @return a NodeSetValue containing the root nodes of the selected documents (or element
81     * nodes if the URI references contain fragment identifiers)
82     */

83
84     public NodeSetValue getDocuments(
85                                 Value arg0,
86                                 NodeSetValue arg1,
87                                 String JavaDoc styleSheetURL,
88                                 Context context) throws XPathException {
89         String JavaDoc baseURL;
90
91         if ((arg0 instanceof NodeSetValue) &&
92                 !(arg0 instanceof FragmentValue || arg0 instanceof TextFragmentValue)) {
93
94             NodeEnumeration supplied = ((NodeSetValue)arg0).enumerate();
95             NodeSetExtent nv = new NodeSetExtent(context.getController());
96
97             while (supplied.hasMoreElements()) {
98                 NodeInfo n = supplied.nextElement();
99                 if (arg1==null) {
100                     baseURL = n.getBaseURI();
101                 } else {
102                     NodeInfo first = arg1.getFirst();
103                     if (first==null) {
104                         // node set is empty; treat it as fatal error
105
throw new XPathException("Second argument to document() is empty node-set");
106                     }
107                     else {
108                         baseURL = first.getBaseURI();
109                     }
110                 }
111                 NodeInfo doc = makeDoc(n.getStringValue(), baseURL, context);
112                 if (doc!=null) {
113                     nv.append(doc);
114                 }
115             }
116             return nv;
117                 
118         } else {
119             
120             if (arg1==null) {
121                 baseURL = styleSheetURL;
122             } else {
123                 NodeInfo first = arg1.getFirst();
124                 if (first==null) {
125                     // node set is empty; this is potentially an error
126
// (see XSLT 1.0 errata)
127
baseURL = null;
128                 } else {
129                     baseURL = first.getBaseURI();
130                 }
131             }
132
133             String JavaDoc href = arg0.asString();
134             NodeInfo doc = makeDoc(href, baseURL, context);
135             return new SingletonNodeSet(doc);
136         }
137     }
138
139     /**
140     * Supporting routine to load one external document given a URI (href) and a baseURI
141     */

142
143     private NodeInfo makeDoc(String JavaDoc href, String JavaDoc baseURL, Context c) throws XPathException {
144
145         // If the href contains a fragment identifier, strip it out now
146

147         int hash = href.indexOf('#');
148
149         String JavaDoc fragmentId = null;
150         if (hash>=0) {
151             if (hash==href.length()-1) {
152                 // # sign at end - just ignore it
153
href = href.substring(0, hash);
154             } else {
155                 fragmentId = href.substring(hash+1);
156                 href = href.substring(0, hash);
157             }
158         }
159         
160         // Resolve relative URI
161

162      
163         String JavaDoc documentKey;
164         if (baseURL==null) { // no base URI available
165
try {
166                 // the href might be an absolute URL
167
documentKey = (new URL JavaDoc(href)).toString();
168             } catch (MalformedURLException JavaDoc err) {
169                 // it isn't; but the URI resolver might know how to cope
170
documentKey = baseURL + "/" + href;
171                 baseURL = "";
172             }
173         } else {
174             try {
175                 URL JavaDoc url = new URL JavaDoc(new URL JavaDoc(baseURL), href);
176                 documentKey = url.toString();
177             } catch (MalformedURLException JavaDoc err) {
178                 documentKey = baseURL + "/../" + href;
179             }
180         }
181
182         Controller controller = boundController;
183         if (controller==null) {
184             controller = c.getController();
185         }
186
187         if (controller==null) {
188             throw new XPathException("Internal error: no controller available for document() function");
189         }
190
191         // see if the document is already loaded
192

193
194         DocumentInfo doc = controller.getDocumentPool().find(documentKey);
195         if (doc!=null) return getFragment(doc, fragmentId);
196
197         try {
198             // Get a Source from the URIResolver
199

200             URIResolver JavaDoc r = controller.getURIResolver();
201             Source JavaDoc source = r.resolve(href, baseURL);
202             
203             // if a user URI resolver returns null, try the standard one
204
// (Note, the standard URI resolver never returns null)
205
if (source==null) {
206                 r = controller.getStandardURIResolver();
207                 source = r.resolve(href, baseURL);
208             }
209             
210             DocumentInfo newdoc = null;
211             if (source instanceof DocumentInfo) {
212                 newdoc = (DocumentInfo)source;
213             } else {
214                 if (source instanceof DOMSource JavaDoc) {
215                     DOMSource JavaDoc ds = (DOMSource JavaDoc)source;
216                     if (ds.getNode() instanceof DocumentInfo) {
217                         // If the URIResolver returns a DocumentInfo, it is
218
// responsible for doing any stripping of whitespace
219
newdoc = (DocumentInfo)ds.getNode();
220                     }
221                 }
222                 if (newdoc==null) {
223                     // Build a new tree
224
SAXSource JavaDoc saxSource =
225                         controller.getTransformerFactory().getSAXSource(source, false);
226                     
227                     Builder b = controller.makeBuilder();
228                     newdoc = b.build(saxSource);
229                 }
230             }
231
232             // add the document to the pool
233
controller.getDocumentPool().add(newdoc, documentKey);
234             
235             return getFragment(newdoc, fragmentId);
236             
237         } catch (TransformerException JavaDoc err) {
238             try {
239                 controller.reportRecoverableError(err);
240             } catch (TransformerException JavaDoc err2) {
241                 throw new XPathException(err);
242             }
243             return null;
244         }
245     }
246
247     /**
248     * Resolve the fragment identifier within a URI Reference.
249     * Only "bare names" XPointers are recognized, that is, a fragment identifier
250     * that matches an ID attribute value within the target document.
251     * @return the element within the supplied document that matches the
252     * given id value; or null if no such element is found.
253     */

254     
255     private NodeInfo getFragment(DocumentInfo doc, String JavaDoc fragmentId) {
256         if (fragmentId==null) {
257             return doc;
258         }
259         return doc.selectID(fragmentId);
260     }
261
262     /**
263     * Determine which aspects of the context the expression depends on. The result is
264     * a bitwise-or'ed value composed from constants such as Context.VARIABLES and
265     * Context.CURRENT_NODE
266     */

267
268     public int getDependencies() {
269         int dep = argument[0].getDependencies();
270         if (getNumberOfArguments()==2) {
271             dep |= argument[1].getDependencies();
272         }
273         if (boundController == null) {
274             return dep | Context.CONTROLLER;
275         } else {
276             return dep;
277         }
278     }
279
280     /**
281     * Remove dependencies.
282     */

283
284     public Expression reduce(int dep, Context context)
285             throws XPathException {
286
287         Document doc = new Document();
288         doc.addArgument(argument[0].reduce(dep, context));
289         if (getNumberOfArguments()==2) {
290             doc.addArgument(argument[1].reduce(dep, context));
291         }
292         doc.setStaticContext(getStaticContext());
293             
294         if ( boundController==null && ((dep & Context.CONTROLLER) != 0)) {
295             doc.boundController = context.getController();
296         }
297         
298         if (doc.getDependencies()==0) {
299             return doc.evaluate(context);
300         }
301
302         return doc;
303     }
304
305
306 }
307
308
309
310
311
312 //
313
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
314
// you may not use this file except in compliance with the License. You may obtain a copy of the
315
// License at http://www.mozilla.org/MPL/
316
//
317
// Software distributed under the License is distributed on an "AS IS" basis,
318
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
319
// See the License for the specific language governing rights and limitations under the License.
320
//
321
// The Original Code is: all this file.
322
//
323
// The Initial Developer of the Original Code is
324
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
325
//
326
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
327
//
328
// Contributor(s): none.
329
//
330
Popular Tags