001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: LoadDocument.java 1225369 2011-12-28 22:54:01Z mrglavas $
020 */
021
022 package org.apache.xalan.xsltc.dom;
023
024 import java.io.FileNotFoundException;
025
026 import javax.xml.transform.stream.StreamSource;
027
028 import org.apache.xalan.xsltc.DOM;
029 import org.apache.xalan.xsltc.DOMCache;
030 import org.apache.xalan.xsltc.DOMEnhancedForDTM;
031 import org.apache.xalan.xsltc.TransletException;
032 import org.apache.xalan.xsltc.runtime.AbstractTranslet;
033 import org.apache.xalan.xsltc.trax.TemplatesImpl;
034 import org.apache.xml.dtm.DTM;
035 import org.apache.xml.dtm.DTMAxisIterator;
036 import org.apache.xml.dtm.DTMManager;
037 import org.apache.xml.dtm.ref.EmptyIterator;
038 import org.apache.xml.utils.SystemIDResolver;
039
040 /**
041 * @author Morten Jorgensen
042 */
043 public final class LoadDocument {
044
045 private static final String NAMESPACE_FEATURE =
046 "http://xml.org/sax/features/namespaces";
047
048 /**
049 * Interprets the arguments passed from the document() function (see
050 * org/apache/xalan/xsltc/compiler/DocumentCall.java) and returns an
051 * iterator containing the requested nodes. Builds a union-iterator if
052 * several documents are requested.
053 * 2 arguments arg1 and arg2. document(Obj, node-set) call
054 */
055 public static DTMAxisIterator documentF(Object arg1, DTMAxisIterator arg2,
056 String xslURI, AbstractTranslet translet, DOM dom)
057 throws TransletException {
058 String baseURI = null;
059 final int arg2FirstNode = arg2.next();
060 if (arg2FirstNode == DTMAxisIterator.END) {
061 // the second argument node-set is empty
062 return EmptyIterator.getInstance();
063 } else {
064 //System.err.println("arg2FirstNode name: "
065 // + dom.getNodeName(arg2FirstNode )+"["
066 // +Integer.toHexString(arg2FirstNode )+"]");
067 baseURI = dom.getDocumentURI(arg2FirstNode);
068 if (!SystemIDResolver.isAbsoluteURI(baseURI))
069 baseURI = SystemIDResolver.getAbsoluteURIFromRelative(baseURI);
070 }
071
072 try {
073 if (arg1 instanceof String) {
074 if (((String)arg1).length() == 0) {
075 return document(xslURI, "", translet, dom);
076 } else {
077 return document((String)arg1, baseURI, translet, dom);
078 }
079 } else if (arg1 instanceof DTMAxisIterator) {
080 return document((DTMAxisIterator)arg1, baseURI, translet, dom);
081 } else {
082 final String err = "document("+arg1.toString()+")";
083 throw new IllegalArgumentException(err);
084 }
085 } catch (Exception e) {
086 throw new TransletException(e);
087 }
088 }
089 /**
090 * Interprets the arguments passed from the document() function (see
091 * org/apache/xalan/xsltc/compiler/DocumentCall.java) and returns an
092 * iterator containing the requested nodes. Builds a union-iterator if
093 * several documents are requested.
094 * 1 arguments arg. document(Obj) call
095 */
096 public static DTMAxisIterator documentF(Object arg, String xslURI,
097 AbstractTranslet translet, DOM dom)
098 throws TransletException {
099 try {
100 if (arg instanceof String) {
101 if (xslURI == null )
102 xslURI = "";
103
104 String baseURI = xslURI;
105 if (!SystemIDResolver.isAbsoluteURI(xslURI))
106 baseURI = SystemIDResolver.getAbsoluteURIFromRelative(xslURI);
107
108 String href = (String)arg;
109 if (href.length() == 0) {
110 href = "";
111 // %OPT% Optimization to cache the stylesheet DOM.
112 // The stylesheet DOM is built once and cached
113 // in the Templates object.
114 TemplatesImpl templates = (TemplatesImpl)translet.getTemplates();
115 DOM sdom = null;
116 if (templates != null) {
117 sdom = templates.getStylesheetDOM();
118 }
119
120 // If the cached dom exists, we need to migrate it
121 // to the new DTMManager and create a DTMAxisIterator
122 // for the document.
123 if (sdom != null) {
124 return document(sdom, translet, dom);
125 }
126 else {
127 return document(href, baseURI, translet, dom, true);
128 }
129 }
130 else {
131 return document(href, baseURI, translet, dom);
132 }
133 } else if (arg instanceof DTMAxisIterator) {
134 return document((DTMAxisIterator)arg, null, translet, dom);
135 } else {
136 final String err = "document("+arg.toString()+")";
137 throw new IllegalArgumentException(err);
138 }
139 } catch (Exception e) {
140 throw new TransletException(e);
141 }
142 }
143
144 private static DTMAxisIterator document(String uri, String base,
145 AbstractTranslet translet, DOM dom)
146 throws Exception
147 {
148 return document(uri, base, translet, dom, false);
149 }
150
151 private static DTMAxisIterator document(String uri, String base,
152 AbstractTranslet translet, DOM dom,
153 boolean cacheDOM)
154 throws Exception
155 {
156 try {
157 final String originalUri = uri;
158 MultiDOM multiplexer = (MultiDOM)dom;
159
160 // Prepend URI base to URI (from context)
161 if (base != null && base.length() != 0) {
162 uri = SystemIDResolver.getAbsoluteURI(uri, base);
163 }
164
165 // Return an empty iterator if the URI is clearly invalid
166 // (to prevent some unncessary MalformedURL exceptions).
167 if (uri == null || uri.length() == 0) {
168 return(EmptyIterator.getInstance());
169 }
170
171 // Check if this DOM has already been added to the multiplexer
172 int mask = multiplexer.getDocumentMask(uri);
173 if (mask != -1) {
174 DOM newDom = ((DOMAdapter)multiplexer.getDOMAdapter(uri))
175 .getDOMImpl();
176 if (newDom instanceof DOMEnhancedForDTM) {
177 return new SingletonIterator(((DOMEnhancedForDTM)newDom)
178 .getDocument(),
179 true);
180 }
181 }
182
183 // Check if we can get the DOM from a DOMCache
184 DOMCache cache = translet.getDOMCache();
185 DOM newdom;
186
187 mask = multiplexer.nextMask(); // peek
188
189 if (cache != null) {
190 newdom = cache.retrieveDocument(base, originalUri, translet);
191 if (newdom == null) {
192 final Exception e = new FileNotFoundException(originalUri);
193 throw new TransletException(e);
194 }
195 } else {
196 // Parse the input document and construct DOM object
197 // Trust the DTMManager to pick the right parser and
198 // set up the DOM correctly.
199 XSLTCDTMManager dtmManager = (XSLTCDTMManager)multiplexer
200 .getDTMManager();
201 DOMEnhancedForDTM enhancedDOM =
202 (DOMEnhancedForDTM) dtmManager.getDTM(new StreamSource(uri),
203 false, null, true, false,
204 translet.hasIdCall(), cacheDOM);
205 newdom = enhancedDOM;
206
207 // Cache the stylesheet DOM in the Templates object
208 if (cacheDOM) {
209 TemplatesImpl templates = (TemplatesImpl)translet.getTemplates();
210 if (templates != null) {
211 templates.setStylesheetDOM(enhancedDOM);
212 }
213 }
214
215 translet.prepassDocument(enhancedDOM);
216 enhancedDOM.setDocumentURI(uri);
217 }
218
219 // Wrap the DOM object in a DOM adapter and add to multiplexer
220 final DOMAdapter domAdapter = translet.makeDOMAdapter(newdom);
221 multiplexer.addDOMAdapter(domAdapter);
222
223 // Create index for any key elements
224 translet.buildKeys(domAdapter, null, null, newdom.getDocument());
225
226 // Return a singleton iterator containing the root node
227 return new SingletonIterator(newdom.getDocument(), true);
228 } catch (Exception e) {
229 throw e;
230 }
231 }
232
233
234 private static DTMAxisIterator document(DTMAxisIterator arg1,
235 String baseURI,
236 AbstractTranslet translet, DOM dom)
237 throws Exception
238 {
239 UnionIterator union = new UnionIterator(dom);
240 int node = DTM.NULL;
241
242 while ((node = arg1.next()) != DTM.NULL) {
243 String uri = dom.getStringValueX(node);
244 //document(node-set) if true; document(node-set,node-set) if false
245 if (baseURI == null) {
246 baseURI = dom.getDocumentURI(node);
247 if (!SystemIDResolver.isAbsoluteURI(baseURI))
248 baseURI = SystemIDResolver.getAbsoluteURIFromRelative(baseURI);
249 }
250 union.addIterator(document(uri, baseURI, translet, dom));
251 }
252 return(union);
253 }
254
255 /**
256 * Create a DTMAxisIterator for the newdom. This is currently only
257 * used to create an iterator for the cached stylesheet DOM.
258 *
259 * @param newdom the cached stylesheet DOM
260 * @param translet the translet
261 * @param the main dom (should be a MultiDOM)
262 * @return a DTMAxisIterator from the document root
263 */
264 private static DTMAxisIterator document(DOM newdom,
265 AbstractTranslet translet,
266 DOM dom)
267 throws Exception
268 {
269 DTMManager dtmManager = ((MultiDOM)dom).getDTMManager();
270 // Need to migrate the cached DTM to the new DTMManager
271 if (dtmManager != null && newdom instanceof DTM) {
272 ((DTM)newdom).migrateTo(dtmManager);
273 }
274
275 translet.prepassDocument(newdom);
276
277 // Wrap the DOM object in a DOM adapter and add to multiplexer
278 final DOMAdapter domAdapter = translet.makeDOMAdapter(newdom);
279 ((MultiDOM)dom).addDOMAdapter(domAdapter);
280
281 // Create index for any key elements
282 translet.buildKeys(domAdapter, null, null,
283 newdom.getDocument());
284
285 // Return a singleton iterator containing the root node
286 return new SingletonIterator(newdom.getDocument(), true);
287 }
288
289 }