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 }