KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > templates > FuncDocument


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: FuncDocument.java,v 1.35 2004/02/16 20:32:32 minchau Exp $
18  */

19 package org.apache.xalan.templates;
20
21 import java.io.IOException JavaDoc;
22 import java.io.PrintWriter JavaDoc;
23 import java.io.StringWriter JavaDoc;
24
25 import javax.xml.transform.ErrorListener JavaDoc;
26 import javax.xml.transform.Source JavaDoc;
27 import javax.xml.transform.SourceLocator JavaDoc;
28 import javax.xml.transform.TransformerException JavaDoc;
29
30 import org.apache.xalan.res.XSLMessages;
31 import org.apache.xalan.res.XSLTErrorResources;
32 import org.apache.xml.dtm.DTM;
33 import org.apache.xml.dtm.DTMIterator;
34 import org.apache.xml.utils.XMLString;
35 import org.apache.xpath.Expression;
36 import org.apache.xpath.NodeSetDTM;
37 import org.apache.xpath.SourceTreeManager;
38 import org.apache.xpath.XPathContext;
39 import org.apache.xpath.functions.Function2Args;
40 import org.apache.xpath.functions.WrongNumberArgsException;
41 import org.apache.xpath.objects.XNodeSet;
42 import org.apache.xpath.objects.XObject;
43
44 /**
45  * Execute the Doc() function.
46  *
47  * When the document function has exactly one argument and the argument
48  * is a node-set, then the result is the union, for each node in the
49  * argument node-set, of the result of calling the document function with
50  * the first argument being the string-value of the node, and the second
51  * argument being a node-set with the node as its only member. When the
52  * document function has two arguments and the first argument is a node-set,
53  * then the result is the union, for each node in the argument node-set,
54  * of the result of calling the document function with the first argument
55  * being the string-value of the node, and with the second argument being
56  * the second argument passed to the document function.
57  * @xsl.usage advanced
58  */

59 public class FuncDocument extends Function2Args
60 {
61
62   /**
63    * Execute the function. The function must return
64    * a valid object.
65    * @param xctxt The current execution context.
66    * @return A valid XObject.
67    *
68    * @throws javax.xml.transform.TransformerException
69    */

70   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException JavaDoc
71   {
72     int context = xctxt.getCurrentNode();
73     DTM dtm = xctxt.getDTM(context);
74     
75     int docContext = dtm.getDocumentRoot(context);
76     XObject arg = (XObject) this.getArg0().execute(xctxt);
77
78     String JavaDoc base = "";
79     Expression arg1Expr = this.getArg1();
80
81     if (null != arg1Expr)
82     {
83
84       // The URI reference may be relative. The base URI (see [3.2 Base URI])
85
// of the node in the second argument node-set that is first in document
86
// order is used as the base URI for resolving the
87
// relative URI into an absolute URI.
88
XObject arg2 = arg1Expr.execute(xctxt);
89
90       if (XObject.CLASS_NODESET == arg2.getType())
91       {
92         int baseNode = arg2.iter().nextNode();
93
94         if (baseNode == DTM.NULL)
95         {
96             // See http://www.w3.org/1999/11/REC-xslt-19991116-errata#E14.
97
// If the second argument is an empty nodeset, this is an error.
98
// The processor can recover by returning an empty nodeset.
99
warn(xctxt, XSLTErrorResources.WG_EMPTY_SECOND_ARG, null);
100             XNodeSet nodes = new XNodeSet(xctxt.getDTMManager());
101             return nodes;
102         } else{
103             DTM baseDTM = xctxt.getDTM(baseNode);
104             base = baseDTM.getDocumentBaseURI();
105         }
106         // %REVIEW% This doesn't seem to be a problem with the conformance
107
// suite, but maybe it's just not doing a good test?
108
// int baseDoc = baseDTM.getDocument();
109
//
110
// if (baseDoc == DTM.NULL /* || baseDoc instanceof Stylesheet -->What to do?? */)
111
// {
112
//
113
// // base = ((Stylesheet)baseDoc).getBaseIdentifier();
114
// base = xctxt.getNamespaceContext().getBaseIdentifier();
115
// }
116
// else
117
// base = xctxt.getSourceTreeManager().findURIFromDoc(baseDoc);
118
}
119       else
120       {
121         //Can not convert other type to a node-set!;
122
arg2.iter();
123       }
124     }
125     else
126     {
127
128       // If the second argument is omitted, then it defaults to
129
// the node in the stylesheet that contains the expression that
130
// includes the call to the document function. Note that a
131
// zero-length URI reference is a reference to the document
132
// relative to which the URI reference is being resolved; thus
133
// document("") refers to the root node of the stylesheet;
134
// the tree representation of the stylesheet is exactly
135
// the same as if the XML document containing the stylesheet
136
// was the initial source document.
137
assertion(null != xctxt.getNamespaceContext(), "Namespace context can not be null!");
138       base = xctxt.getNamespaceContext().getBaseIdentifier();
139     }
140
141     XNodeSet nodes = new XNodeSet(xctxt.getDTMManager());
142     NodeSetDTM mnl = nodes.mutableNodeset();
143     DTMIterator iterator = (XObject.CLASS_NODESET == arg.getType())
144                             ? arg.iter() : null;
145     int pos = DTM.NULL;
146
147     while ((null == iterator) || (DTM.NULL != (pos = iterator.nextNode())))
148     {
149       XMLString ref = (null != iterator)
150                    ? xctxt.getDTM(pos).getStringValue(pos) : arg.xstr();
151       
152       // The first and only argument was a nodeset, the base in that
153
// case is the base URI of the node from the first argument nodeset.
154
// Remember, when the document function has exactly one argument and
155
// the argument is a node-set, then the result is the union, for each
156
// node in the argument node-set, of the result of calling the document
157
// function with the first argument being the string-value of the node,
158
// and the second argument being a node-set with the node as its only
159
// member.
160
if (null == arg1Expr && DTM.NULL != pos)
161       {
162         DTM baseDTM = xctxt.getDTM(pos);
163         base = baseDTM.getDocumentBaseURI();
164       }
165
166       if (null == ref)
167         continue;
168
169       if (DTM.NULL == docContext)
170       {
171         error(xctxt, XSLTErrorResources.ER_NO_CONTEXT_OWNERDOC, null); //"context does not have an owner document!");
172
}
173
174       // From http://www.ics.uci.edu/pub/ietf/uri/rfc1630.txt
175
// A partial form can be distinguished from an absolute form in that the
176
// latter must have a colon and that colon must occur before any slash
177
// characters. Systems not requiring partial forms should not use any
178
// unencoded slashes in their naming schemes. If they do, absolute URIs
179
// will still work, but confusion may result.
180
int indexOfColon = ref.indexOf(':');
181       int indexOfSlash = ref.indexOf('/');
182
183       if ((indexOfColon != -1) && (indexOfSlash != -1)
184               && (indexOfColon < indexOfSlash))
185       {
186
187         // The url (or filename, for that matter) is absolute.
188
base = null;
189       }
190
191       int newDoc = getDoc(xctxt, context, ref.toString(), base);
192
193       // nodes.mutableNodeset().addNode(newDoc);
194
if (DTM.NULL != newDoc)
195       {
196         // TODO: mnl.addNodeInDocOrder(newDoc, true, xctxt); ??
197
if (!mnl.contains(newDoc))
198         {
199           mnl.addElement(newDoc);
200         }
201       }
202
203       if (null == iterator || newDoc == DTM.NULL)
204         break;
205     }
206
207     return nodes;
208   }
209
210   /**
211    * Get the document from the given URI and base
212    *
213    * @param xctxt The XPath runtime state.
214    * @param context The current context node
215    * @param uri Relative(?) URI of the document
216    * @param base Base to resolve relative URI from.
217    *
218    * @return The document Node pointing to the document at the given URI
219    * or null
220    *
221    * @throws javax.xml.transform.TransformerException
222    */

223   int getDoc(XPathContext xctxt, int context, String JavaDoc uri, String JavaDoc base)
224           throws javax.xml.transform.TransformerException JavaDoc
225   {
226
227     // System.out.println("base: "+base+", uri: "+uri);
228
SourceTreeManager treeMgr = xctxt.getSourceTreeManager();
229     Source JavaDoc source;
230    
231     int newDoc;
232     try
233     {
234       source = treeMgr.resolveURI(base, uri, xctxt.getSAXLocator());
235       newDoc = treeMgr.getNode(source);
236     }
237     catch (IOException JavaDoc ioe)
238     {
239       throw new TransformerException JavaDoc(ioe.getMessage(),
240         (SourceLocator JavaDoc)xctxt.getSAXLocator(), ioe);
241     }
242     catch(TransformerException JavaDoc te)
243     {
244       throw new TransformerException JavaDoc(te);
245     }
246
247     if (DTM.NULL != newDoc)
248       return newDoc;
249
250     // If the uri length is zero, get the uri of the stylesheet.
251
if (uri.length() == 0)
252     {
253       // Hmmm... this seems pretty bogus to me... -sb
254
uri = xctxt.getNamespaceContext().getBaseIdentifier();
255       try
256       {
257         source = treeMgr.resolveURI(base, uri, xctxt.getSAXLocator());
258       }
259       catch (IOException JavaDoc ioe)
260       {
261         throw new TransformerException JavaDoc(ioe.getMessage(),
262           (SourceLocator JavaDoc)xctxt.getSAXLocator(), ioe);
263       }
264     }
265
266     String JavaDoc diagnosticsString = null;
267
268     try
269     {
270       if ((null != uri) && (uri.toString().length() > 0))
271       {
272         newDoc = treeMgr.getSourceTree(source, xctxt.getSAXLocator(), xctxt);
273
274         // System.out.println("newDoc: "+((Document)newDoc).getDocumentElement().getNodeName());
275
}
276       else
277         warn(xctxt, XSLTErrorResources.WG_CANNOT_MAKE_URL_FROM,
278              new Object JavaDoc[]{ ((base == null) ? "" : base) + uri }); //"Can not make URL from: "+((base == null) ? "" : base )+uri);
279
}
280     catch (Throwable JavaDoc throwable)
281     {
282
283       // throwable.printStackTrace();
284
newDoc = DTM.NULL;
285
286       // path.warn(XSLTErrorResources.WG_ENCODING_NOT_SUPPORTED_USING_JAVA, new Object[]{((base == null) ? "" : base )+uri}); //"Can not load requested doc: "+((base == null) ? "" : base )+uri);
287
while (throwable
288              instanceof org.apache.xml.utils.WrappedRuntimeException)
289       {
290         throwable =
291           ((org.apache.xml.utils.WrappedRuntimeException) throwable).getException();
292       }
293
294       if ((throwable instanceof NullPointerException JavaDoc)
295               || (throwable instanceof ClassCastException JavaDoc))
296       {
297         throw new org.apache.xml.utils.WrappedRuntimeException(
298           (Exception JavaDoc) throwable);
299       }
300
301       StringWriter JavaDoc sw = new StringWriter JavaDoc();
302       PrintWriter JavaDoc diagnosticsWriter = new PrintWriter JavaDoc(sw);
303
304       if (throwable instanceof TransformerException JavaDoc)
305       {
306         TransformerException JavaDoc spe = (TransformerException JavaDoc) throwable;
307
308         {
309           Throwable JavaDoc e = spe;
310
311           while (null != e)
312           {
313             if (null != e.getMessage())
314             {
315               diagnosticsWriter.println(" (" + e.getClass().getName() + "): "
316                                         + e.getMessage());
317             }
318
319             if (e instanceof TransformerException JavaDoc)
320             {
321               TransformerException JavaDoc spe2 = (TransformerException JavaDoc) e;
322
323               SourceLocator JavaDoc locator = spe2.getLocator();
324               if ((null != locator) && (null != locator.getSystemId()))
325                 diagnosticsWriter.println(" ID: " + locator.getSystemId()
326                                           + " Line #" + locator.getLineNumber()
327                                           + " Column #"
328                                           + locator.getColumnNumber());
329
330               e = spe2.getException();
331
332               if (e instanceof org.apache.xml.utils.WrappedRuntimeException)
333                 e = ((org.apache.xml.utils.WrappedRuntimeException) e).getException();
334             }
335             else
336               e = null;
337           }
338         }
339       }
340       else
341       {
342         diagnosticsWriter.println(" (" + throwable.getClass().getName()
343                                   + "): " + throwable.getMessage());
344       }
345
346       diagnosticsString = throwable.getMessage(); //sw.toString();
347
}
348
349     if (DTM.NULL == newDoc)
350     {
351
352       // System.out.println("what?: "+base+", uri: "+uri);
353
if (null != diagnosticsString)
354       {
355         warn(xctxt, XSLTErrorResources.WG_CANNOT_LOAD_REQUESTED_DOC,
356              new Object JavaDoc[]{ diagnosticsString }); //"Can not load requested doc: "+((base == null) ? "" : base )+uri);
357
}
358       else
359         warn(xctxt, XSLTErrorResources.WG_CANNOT_LOAD_REQUESTED_DOC,
360              new Object JavaDoc[]{
361                uri == null
362                ? ((base == null) ? "" : base) + uri : uri.toString() }); //"Can not load requested doc: "+((base == null) ? "" : base )+uri);
363
}
364     else
365     {
366       // %REVIEW%
367
// TBD: What to do about XLocator?
368
// xctxt.getSourceTreeManager().associateXLocatorToNode(newDoc, url, null);
369
}
370
371     return newDoc;
372   }
373
374   /**
375    * Tell the user of an error, and probably throw an
376    * exception.
377    *
378    * @param xctxt The XPath runtime state.
379    * @param msg The error message key
380    * @param args Arguments to be used in the error message
381    * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide
382    * the error condition is severe enough to halt processing.
383    *
384    * @throws javax.xml.transform.TransformerException
385    */

386   public void error(XPathContext xctxt, String JavaDoc msg, Object JavaDoc args[])
387           throws javax.xml.transform.TransformerException JavaDoc
388   {
389
390     String JavaDoc formattedMsg = XSLMessages.createMessage(msg, args);
391     ErrorListener JavaDoc errHandler = xctxt.getErrorListener();
392     TransformerException JavaDoc spe = new TransformerException JavaDoc(formattedMsg,
393                               (SourceLocator JavaDoc)xctxt.getSAXLocator());
394
395     if (null != errHandler)
396       errHandler.error(spe);
397     else
398       System.out.println(formattedMsg);
399   }
400
401   /**
402    * Warn the user of a problem.
403    *
404    * @param xctxt The XPath runtime state.
405    * @param msg Warning message key
406    * @param args Arguments to be used in the warning message
407    * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide
408    * the error condition is severe enough to halt processing.
409    *
410    * @throws javax.xml.transform.TransformerException
411    */

412   public void warn(XPathContext xctxt, String JavaDoc msg, Object JavaDoc args[])
413           throws javax.xml.transform.TransformerException JavaDoc
414   {
415
416     String JavaDoc formattedMsg = XSLMessages.createWarning(msg, args);
417     ErrorListener JavaDoc errHandler = xctxt.getErrorListener();
418     TransformerException JavaDoc spe = new TransformerException JavaDoc(formattedMsg,
419                               (SourceLocator JavaDoc)xctxt.getSAXLocator());
420
421     if (null != errHandler)
422       errHandler.warning(spe);
423     else
424       System.out.println(formattedMsg);
425   }
426
427  /**
428    * Overide the superclass method to allow one or two arguments.
429    *
430    *
431    * @param argNum Number of arguments passed in to this function
432    *
433    * @throws WrongNumberArgsException
434    */

435   public void checkNumberArgs(int argNum) throws WrongNumberArgsException
436   {
437     if ((argNum < 1) || (argNum > 2))
438       reportWrongNumberArgs();
439   }
440   
441   /**
442    * Constructs and throws a WrongNumberArgException with the appropriate
443    * message for this function object.
444    *
445    * @throws WrongNumberArgsException
446    */

447   protected void reportWrongNumberArgs() throws WrongNumberArgsException {
448       throw new WrongNumberArgsException(XSLMessages.createMessage(XSLTErrorResources.ER_ONE_OR_TWO, null)); //"1 or 2");
449
}
450   
451   /**
452    * Tell if the expression is a nodeset expression.
453    * @return true if the expression can be represented as a nodeset.
454    */

455   public boolean isNodesetExpr()
456   {
457     return true;
458   }
459
460 }
461
Popular Tags