1 package net.sf.saxon.style; 2 import net.sf.saxon.expr.*; 3 import net.sf.saxon.instruct.*; 4 import net.sf.saxon.om.AttributeCollection; 5 import net.sf.saxon.om.Axis; 6 import net.sf.saxon.om.NamespaceException; 7 import net.sf.saxon.pattern.NoNodeTest; 8 import net.sf.saxon.pattern.Pattern; 9 import net.sf.saxon.trans.Mode; 10 import net.sf.saxon.trans.RuleManager; 11 import net.sf.saxon.trans.XPathException; 12 import net.sf.saxon.type.ItemType; 13 import net.sf.saxon.type.Type; 14 import net.sf.saxon.value.EmptySequence; 15 import net.sf.saxon.value.SequenceType; 16 17 import javax.xml.transform.TransformerException ; 18 import java.math.BigDecimal ; 19 import java.util.StringTokenizer ; 20 21 24 25 public final class XSLTemplate extends StyleElement implements StylesheetProcedure { 26 27 private String matchAtt = null; 28 private String modeAtt = null; 29 private String nameAtt = null; 30 private String priorityAtt = null; 31 private String asAtt = null; 32 33 private int[] modeNameCodes; 34 private String diagnosticId; 35 private Pattern match; 36 private boolean prioritySpecified; 37 private double priority; 38 private SlotManager stackFrameMap; 39 private Template compiledTemplate = new Template(); 40 private SequenceType requiredType = null; 41 42 46 47 public boolean mayContainSequenceConstructor() { 48 return true; 49 } 50 51 54 55 protected boolean isPermittedChild(StyleElement child) { 56 return (child instanceof XSLParam); 57 } 58 59 63 64 public int getTemplateFingerprint() { 65 66 68 try { 69 if (getObjectFingerprint()==-1) { 70 String nameAtt = getAttributeValue(StandardNames.NAME); 72 if (nameAtt!=null) { 73 setObjectNameCode(makeNameCode(nameAtt.trim())); 74 } 75 } 76 return getObjectFingerprint(); 77 } catch (NamespaceException err) { 78 return -1; } catch (XPathException err) { 80 return -1; 81 } 82 } 83 84 88 89 protected ItemType getReturnedItemType() { 90 if (requiredType==null) { 91 return getCommonChildItemType(); 92 } else { 93 return requiredType.getPrimaryType(); 94 } 95 } 96 97 private int getMinImportPrecedence() { 98 return getContainingStylesheet().getMinImportPrecedence(); 99 } 100 101 public void prepareAttributes() throws XPathException { 102 103 AttributeCollection atts = getAttributeList(); 104 105 for (int a=0; a<atts.getLength(); a++) { 106 int nc = atts.getNameCode(a); 107 String f = getNamePool().getClarkName(nc); 108 if (f==StandardNames.MODE) { 109 modeAtt = atts.getValue(a).trim(); 110 } else if (f==StandardNames.NAME) { 111 nameAtt = atts.getValue(a).trim(); 112 } else if (f==StandardNames.MATCH) { 113 matchAtt = atts.getValue(a); 114 } else if (f==StandardNames.PRIORITY) { 115 priorityAtt = atts.getValue(a).trim(); 116 } else if (f==StandardNames.AS) { 117 asAtt = atts.getValue(a); 118 } else { 119 checkUnknownAttribute(nc); 120 } 121 } 122 try { 123 if (modeAtt==null) { 124 modeNameCodes = new int[1]; 125 modeNameCodes[0] = -1; 126 } else { 127 if (matchAtt==null) { 128 compileError("The mode attribute must be absent if the match attribute is absent", "XTSE0500"); 129 } 130 132 int count = 0; 133 boolean allModes = false; 134 StringTokenizer st = new StringTokenizer (modeAtt); 135 while (st.hasMoreTokens()) { 136 st.nextToken(); 137 count++; 138 } 139 140 if (count==0) { 141 compileError("The mode attribute must not be empty", "XTSE0550"); 142 } 143 144 modeNameCodes = new int[count]; 145 count = 0; 146 st = new StringTokenizer (modeAtt); 147 while (st.hasMoreTokens()) { 148 String s = st.nextToken(); 149 int code; 150 if ("#default".equals(s)) { 151 code = Mode.DEFAULT_MODE; 152 } else if ("#all".equals(s)) { 153 allModes = true; 154 code = Mode.ALL_MODES; 155 } else { 156 code = makeNameCode(s); 157 } 158 for (int e=0; e < count; e++) { 159 if (modeNameCodes[e] == code) { 160 compileError("In the list of modes, the value " + s + " is duplicated", "XTSE0550"); 161 } 162 } 163 modeNameCodes[count++] = code; 164 } 165 if (allModes && (count>1)) { 166 compileError("mode='#all' cannot be combined with other modes", "XTSE0550"); 167 } 168 } 169 170 if (nameAtt!=null) { 171 setObjectNameCode(makeNameCode(nameAtt.trim())); 172 diagnosticId = nameAtt; 173 } 174 } catch (NamespaceException err) { 175 compileError(err.getMessage(), "XTSE0280"); 176 } catch (XPathException err) { 177 compileError(err.getMessage(), "XTSE0280"); 178 } 179 180 prioritySpecified = (priorityAtt != null); 181 if (prioritySpecified) { 182 if (matchAtt==null) { 183 compileError("The priority attribute must be absent if the match attribute is absent", "XTSE0500"); 184 } 185 try { 186 new BigDecimal (priorityAtt.trim()); 188 priority = Double.parseDouble(priorityAtt.trim()); 189 } catch (NumberFormatException err) { 190 compileError("Invalid numeric value for priority (" + priority + ')', "XTSE0530"); 191 } 192 } 193 194 if (matchAtt != null) { 195 match = makePattern(matchAtt); 196 if (diagnosticId == null) { 197 diagnosticId = "match=\"" + matchAtt + '\"'; 198 } 199 } 200 201 if (match==null && nameAtt==null) 202 compileError("xsl:template must have a name or match attribute (or both)", "XTSE0010"); 203 204 if (asAtt != null) { 205 requiredType = makeSequenceType(asAtt); 206 } 207 208 } 209 210 public void validate() throws XPathException { 211 stackFrameMap = getConfiguration().makeSlotManager(); 212 checkTopLevel(null); 213 214 if (match != null) { 216 typeCheck("match", match); 217 if (match.getNodeTest() instanceof NoNodeTest) { 218 try { 219 getConfiguration().getErrorListener().warning( 220 new TransformerException ("Match pattern cannot match any nodes", this)); 221 } catch (TransformerException e) { 222 compileError(e); 223 } 224 } 225 } 226 markTailCalls(); 227 } 228 229 232 233 public void markTailCalls() { 234 if (requiredType == null) { 235 StyleElement last = getLastChildInstruction(); 237 if (last != null) { 238 last.markTailCalls(); 239 } 240 } 241 } 242 243 247 248 public Expression compile(Executable exec) throws XPathException { 249 250 Expression block = compileSequenceConstructor(exec, iterateAxis(Axis.CHILD), true); 251 if (block == null) { 252 block = EmptySequence.getInstance(); 253 } 254 compiledTemplate.setBody(block); 255 compiledTemplate.setStackFrameMap(stackFrameMap); 256 compiledTemplate.setExecutable(getExecutable()); 257 compiledTemplate.setSystemId(getSystemId()); 258 compiledTemplate.setLineNumber(getLineNumber()); 259 260 Expression exp = null; 261 try { 262 exp = block.simplify(getStaticContext()); 263 } catch (XPathException e) { 264 compileError(e); 265 } 266 267 try { 268 if (requiredType != null) { 269 RoleLocator role = 270 new RoleLocator(RoleLocator.TEMPLATE_RESULT, diagnosticId, 0, null); 271 role.setSourceLocator(new ExpressionLocation(this)); 272 exp = TypeChecker.staticTypeCheck(exp, requiredType, false, role, getStaticContext()); 273 } 274 } catch (XPathException err) { 275 compileError(err); 276 } 277 278 compiledTemplate.setBody(exp); 279 compiledTemplate.init ( getObjectFingerprint(), 280 getPrecedence(), 281 getMinImportPrecedence()); 282 283 if (getConfiguration().getTraceListener() != null) { 284 TraceWrapper trace = new TraceInstruction(exp, this); 285 trace.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); 286 trace.setParentExpression(compiledTemplate); 287 exp = trace; 288 compiledTemplate.setBody(exp); 289 } 290 291 292 293 294 ItemType contextItemType = Type.ITEM_TYPE; 295 if (getObjectFingerprint() == -1) { 296 contextItemType = match.getNodeTest(); 298 } 299 300 301 try { 302 Expression exp2 = exp.typeCheck(staticContext, contextItemType); 305 exp2 = exp2.optimize(getConfiguration().getOptimizer(), staticContext, contextItemType); 306 if (exp != exp2) { 307 compiledTemplate.setBody(exp2); 308 exp = exp2; 309 } 310 } catch (XPathException e) { 311 compileError(e); 312 } 313 super.allocateSlots(exp); 314 if (match!=null) { 315 RuleManager mgr = getPrincipalStylesheet().getRuleManager(); 316 for (int i=0; i<modeNameCodes.length; i++) { 317 int nc = modeNameCodes[i]; 318 Mode mode = mgr.getMode(nc); 319 if (prioritySpecified) { 320 mgr.setHandler(match, compiledTemplate, mode, getPrecedence(), priority); 321 } else { 322 mgr.setHandler(match, compiledTemplate, mode, getPrecedence()); 323 } 324 } 325 } 326 327 if (isExplaining()) { 328 System.err.println("Optimized expression tree for template at line " + 329 getLineNumber() + " in " + getSystemId() + ":"); 330 exp.display(10, getNamePool(), System.err); 331 } 332 333 return null; 334 } 335 336 337 340 341 public SlotManager getSlotManager() { 342 return stackFrameMap; 343 } 344 345 355 356 public void allocateSlots(Expression exp) { 357 int highWater = ExpressionTool.allocateSlots(exp, 0, null); 358 getContainingStylesheet().allocatePatternSlots(highWater); 359 } 360 363 364 public Template getCompiledTemplate() { 365 return compiledTemplate; 366 } 367 368 372 373 public int getConstructType() { 374 return StandardNames.XSL_TEMPLATE; 375 } 376 377 378 } 379 380 | Popular Tags |