author | joehw |
Wed, 18 Oct 2017 13:25:49 -0700 | |
changeset 47359 | e1a6c0168741 |
parent 47216 | 71c04702a3d5 |
child 48409 | 5ab69533994b |
permissions | -rw-r--r-- |
12005 | 1 |
/* |
47359
e1a6c0168741
8181150: Fix lint warnings in JAXP repo: rawtypes and unchecked
joehw
parents:
47216
diff
changeset
|
2 |
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. |
e1a6c0168741
8181150: Fix lint warnings in JAXP repo: rawtypes and unchecked
joehw
parents:
47216
diff
changeset
|
3 |
* @LastModified: Oct 2017 |
12005 | 4 |
*/ |
5 |
/* |
|
33349 | 6 |
* Licensed to the Apache Software Foundation (ASF) under one or more |
7 |
* contributor license agreements. See the NOTICE file distributed with |
|
8 |
* this work for additional information regarding copyright ownership. |
|
9 |
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
10 |
* (the "License"); you may not use this file except in compliance with |
|
11 |
* the License. You may obtain a copy of the License at |
|
12005 | 12 |
* |
39909
00e4298ae168
8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace
clanger
parents:
35336
diff
changeset
|
13 |
* http://www.apache.org/licenses/LICENSE-2.0 |
12005 | 14 |
* |
15 |
* Unless required by applicable law or agreed to in writing, software |
|
16 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
17 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
18 |
* See the License for the specific language governing permissions and |
|
19 |
* limitations under the License. |
|
20 |
*/ |
|
21 |
||
22 |
package com.sun.org.apache.xalan.internal.xsltc.compiler; |
|
23 |
||
24 |
import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; |
|
25 |
import com.sun.org.apache.bcel.internal.generic.InstructionList; |
|
26 |
import com.sun.org.apache.bcel.internal.generic.PUSH; |
|
27 |
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; |
|
28 |
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; |
|
29 |
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; |
|
30 |
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; |
|
31 |
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; |
|
32 |
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; |
|
33 |
import com.sun.org.apache.xml.internal.serializer.ElemDesc; |
|
34 |
import com.sun.org.apache.xml.internal.serializer.ToHTMLStream; |
|
33349 | 35 |
import java.util.ArrayList; |
36 |
import java.util.HashMap; |
|
35336
c22ade6e6c86
8134650: Xsl transformation gives different results in 8u66
aefimov
parents:
33349
diff
changeset
|
37 |
import java.util.Hashtable; |
33349 | 38 |
import java.util.List; |
39 |
import java.util.Map; |
|
40 |
import java.util.Set; |
|
12005 | 41 |
|
42 |
/** |
|
43 |
* @author Jacek Ambroziak |
|
44 |
* @author Santiago Pericas-Geertsen |
|
45 |
* @author Morten Jorgensen |
|
46 |
*/ |
|
47 |
final class LiteralElement extends Instruction { |
|
48 |
||
49 |
private String _name; |
|
50 |
private LiteralElement _literalElemParent = null; |
|
33349 | 51 |
private List<SyntaxTreeNode> _attributeElements = null; |
52 |
private Map<String, String> _accessedPrefixes = null; |
|
12005 | 53 |
|
54 |
// True if all attributes of this LRE are unique, i.e. they all have |
|
55 |
// different names. This flag is set to false if some attribute |
|
56 |
// names are not known at compile time. |
|
57 |
private boolean _allAttributesUnique = false; |
|
58 |
||
59 |
/** |
|
60 |
* Returns the QName for this literal element |
|
61 |
*/ |
|
62 |
public QName getName() { |
|
63 |
return _qname; |
|
64 |
} |
|
65 |
||
66 |
/** |
|
67 |
* Displays the contents of this literal element |
|
68 |
*/ |
|
69 |
public void display(int indent) { |
|
70 |
indent(indent); |
|
71 |
Util.println("LiteralElement name = " + _name); |
|
72 |
displayContents(indent + IndentIncrement); |
|
73 |
} |
|
74 |
||
75 |
/** |
|
76 |
* Returns the namespace URI for which a prefix is pointing to |
|
77 |
*/ |
|
78 |
private String accessedNamespace(String prefix) { |
|
79 |
if (_literalElemParent != null) { |
|
80 |
String result = _literalElemParent.accessedNamespace(prefix); |
|
81 |
if (result != null) { |
|
82 |
return result; |
|
83 |
} |
|
84 |
} |
|
33349 | 85 |
return _accessedPrefixes != null ? _accessedPrefixes.get(prefix) : null; |
12005 | 86 |
} |
87 |
||
88 |
/** |
|
89 |
* Method used to keep track of what namespaces that are references by |
|
90 |
* this literal element and its attributes. The output must contain a |
|
33349 | 91 |
* definition for each namespace, so we stuff them in a map. |
12005 | 92 |
*/ |
93 |
public void registerNamespace(String prefix, String uri, |
|
94 |
SymbolTable stable, boolean declared) { |
|
95 |
||
96 |
// Check if the parent has a declaration for this namespace |
|
97 |
if (_literalElemParent != null) { |
|
98 |
final String parentUri = _literalElemParent.accessedNamespace(prefix); |
|
99 |
if (parentUri != null && parentUri.equals(uri)) { |
|
100 |
return; |
|
101 |
} |
|
102 |
} |
|
103 |
||
35336
c22ade6e6c86
8134650: Xsl transformation gives different results in 8u66
aefimov
parents:
33349
diff
changeset
|
104 |
// Check if we have any declared namespaces |
12005 | 105 |
if (_accessedPrefixes == null) { |
47359
e1a6c0168741
8181150: Fix lint warnings in JAXP repo: rawtypes and unchecked
joehw
parents:
47216
diff
changeset
|
106 |
// use Hashtable for behavior compatibility |
35336
c22ade6e6c86
8134650: Xsl transformation gives different results in 8u66
aefimov
parents:
33349
diff
changeset
|
107 |
_accessedPrefixes = new Hashtable<>(); |
12005 | 108 |
} |
109 |
else { |
|
110 |
if (!declared) { |
|
111 |
// Check if this node has a declaration for this namespace |
|
33349 | 112 |
final String old = _accessedPrefixes.get(prefix); |
12005 | 113 |
if (old != null) { |
114 |
if (old.equals(uri)) |
|
115 |
return; |
|
116 |
else |
|
117 |
prefix = stable.generateNamespacePrefix(); |
|
118 |
} |
|
119 |
} |
|
120 |
} |
|
121 |
||
122 |
if (!prefix.equals("xml")) { |
|
123 |
_accessedPrefixes.put(prefix,uri); |
|
124 |
} |
|
125 |
} |
|
126 |
||
127 |
/** |
|
128 |
* Translates the prefix of a QName according to the rules set in |
|
129 |
* the attributes of xsl:stylesheet. Also registers a QName to assure |
|
130 |
* that the output element contains the necessary namespace declarations. |
|
131 |
*/ |
|
132 |
private String translateQName(QName qname, SymbolTable stable) { |
|
133 |
// Break up the QName and get prefix:localname strings |
|
134 |
String localname = qname.getLocalPart(); |
|
135 |
String prefix = qname.getPrefix(); |
|
136 |
||
137 |
// Treat default namespace as "" and not null |
|
138 |
if (prefix == null) |
|
139 |
prefix = Constants.EMPTYSTRING; |
|
39909
00e4298ae168
8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace
clanger
parents:
35336
diff
changeset
|
140 |
else if (prefix.equals(XMLNS_PREFIX)) |
00e4298ae168
8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace
clanger
parents:
35336
diff
changeset
|
141 |
return(XMLNS_PREFIX); |
12005 | 142 |
|
143 |
// Check if we must translate the prefix |
|
144 |
final String alternative = stable.lookupPrefixAlias(prefix); |
|
145 |
if (alternative != null) { |
|
146 |
stable.excludeNamespaces(prefix); |
|
147 |
prefix = alternative; |
|
148 |
} |
|
149 |
||
150 |
// Get the namespace this prefix refers to |
|
151 |
String uri = lookupNamespace(prefix); |
|
152 |
if (uri == null) return(localname); |
|
153 |
||
154 |
// Register the namespace as accessed |
|
155 |
registerNamespace(prefix, uri, stable, false); |
|
156 |
||
157 |
// Construct the new name for the element (may be unchanged) |
|
158 |
if (prefix != Constants.EMPTYSTRING) |
|
159 |
return(prefix+":"+localname); |
|
160 |
else |
|
161 |
return(localname); |
|
162 |
} |
|
163 |
||
164 |
/** |
|
165 |
* Add an attribute to this element |
|
166 |
*/ |
|
167 |
public void addAttribute(SyntaxTreeNode attribute) { |
|
168 |
if (_attributeElements == null) { |
|
33349 | 169 |
_attributeElements = new ArrayList<>(2); |
12005 | 170 |
} |
171 |
_attributeElements.add(attribute); |
|
172 |
} |
|
173 |
||
174 |
/** |
|
175 |
* Set the first attribute of this element |
|
176 |
*/ |
|
177 |
public void setFirstAttribute(SyntaxTreeNode attribute) { |
|
178 |
if (_attributeElements == null) { |
|
33349 | 179 |
_attributeElements = new ArrayList<>(2); |
12005 | 180 |
} |
33349 | 181 |
_attributeElements.add(0, attribute); |
12005 | 182 |
} |
183 |
||
184 |
/** |
|
185 |
* Type-check the contents of this element. The element itself does not |
|
186 |
* need any type checking as it leaves nothign on the JVM's stack. |
|
187 |
*/ |
|
188 |
public Type typeCheck(SymbolTable stable) throws TypeCheckError { |
|
189 |
// Type-check all attributes |
|
190 |
if (_attributeElements != null) { |
|
33349 | 191 |
for (SyntaxTreeNode node : _attributeElements) { |
12005 | 192 |
node.typeCheck(stable); |
193 |
} |
|
194 |
} |
|
195 |
typeCheckContents(stable); |
|
196 |
return Type.Void; |
|
197 |
} |
|
198 |
||
199 |
/** |
|
200 |
* This method starts at a given node, traverses all namespace mappings, |
|
201 |
* and assembles a list of all prefixes that (for the given node) maps |
|
202 |
* to _ANY_ namespace URI. Used by literal result elements to determine |
|
203 |
*/ |
|
33349 | 204 |
public Set<Map.Entry<String, String>> getNamespaceScope(SyntaxTreeNode node) { |
205 |
Map<String, String> all = new HashMap<>(); |
|
12005 | 206 |
|
207 |
while (node != null) { |
|
33349 | 208 |
Map<String, String> mapping = node.getPrefixMapping(); |
12005 | 209 |
if (mapping != null) { |
33349 | 210 |
mapping.entrySet().stream().forEach((entry) -> { |
211 |
all.putIfAbsent(entry.getKey(), entry.getValue()); |
|
212 |
}); |
|
12005 | 213 |
} |
214 |
node = node.getParent(); |
|
215 |
} |
|
33349 | 216 |
return all.entrySet(); |
12005 | 217 |
} |
218 |
||
219 |
/** |
|
220 |
* Determines the final QName for the element and its attributes. |
|
221 |
* Registers all namespaces that are used by the element/attributes |
|
222 |
*/ |
|
223 |
public void parseContents(Parser parser) { |
|
224 |
final SymbolTable stable = parser.getSymbolTable(); |
|
225 |
stable.setCurrentNode(this); |
|
226 |
||
227 |
// Check if in a literal element context |
|
228 |
SyntaxTreeNode parent = getParent(); |
|
229 |
if (parent != null && parent instanceof LiteralElement) { |
|
230 |
_literalElemParent = (LiteralElement) parent; |
|
231 |
} |
|
232 |
||
233 |
_name = translateQName(_qname, stable); |
|
234 |
||
235 |
// Process all attributes and register all namespaces they use |
|
236 |
final int count = _attributes.getLength(); |
|
237 |
for (int i = 0; i < count; i++) { |
|
238 |
final QName qname = parser.getQName(_attributes.getQName(i)); |
|
239 |
final String uri = qname.getNamespace(); |
|
240 |
final String val = _attributes.getValue(i); |
|
241 |
||
242 |
// Handle xsl:use-attribute-sets. Attribute sets are placed first |
|
243 |
// in the vector or attributes to make sure that later local |
|
244 |
// attributes can override an attributes in the set. |
|
245 |
if (qname.equals(parser.getUseAttributeSets())) { |
|
246 |
if (!Util.isValidQNames(val)) { |
|
247 |
ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, val, this); |
|
248 |
parser.reportError(Constants.ERROR, err); |
|
249 |
} |
|
250 |
setFirstAttribute(new UseAttributeSets(val, parser)); |
|
251 |
} |
|
252 |
// Handle xsl:extension-element-prefixes |
|
253 |
else if (qname.equals(parser.getExtensionElementPrefixes())) { |
|
254 |
stable.excludeNamespaces(val); |
|
255 |
} |
|
256 |
// Handle xsl:exclude-result-prefixes |
|
257 |
else if (qname.equals(parser.getExcludeResultPrefixes())) { |
|
258 |
stable.excludeNamespaces(val); |
|
259 |
} |
|
260 |
else { |
|
261 |
// Ignore special attributes (e.g. xmlns:prefix and xmlns) |
|
262 |
final String prefix = qname.getPrefix(); |
|
263 |
if (prefix != null && prefix.equals(XMLNS_PREFIX) || |
|
39909
00e4298ae168
8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace
clanger
parents:
35336
diff
changeset
|
264 |
prefix == null && qname.getLocalPart().equals(XMLNS_PREFIX) || |
12005 | 265 |
uri != null && uri.equals(XSLT_URI)) |
266 |
{ |
|
267 |
continue; |
|
268 |
} |
|
269 |
||
270 |
// Handle all other literal attributes |
|
271 |
final String name = translateQName(qname, stable); |
|
272 |
LiteralAttribute attr = new LiteralAttribute(name, val, parser, this); |
|
273 |
addAttribute(attr); |
|
274 |
attr.setParent(this); |
|
275 |
attr.parseContents(parser); |
|
276 |
} |
|
277 |
} |
|
278 |
||
279 |
// Register all namespaces that are in scope, except for those that |
|
280 |
// are listed in the xsl:stylesheet element's *-prefixes attributes |
|
33349 | 281 |
Set<Map.Entry<String, String>> include = getNamespaceScope(this); |
282 |
for (Map.Entry<String, String> entry : include) { |
|
283 |
final String prefix = entry.getKey(); |
|
12005 | 284 |
if (!prefix.equals("xml")) { |
285 |
final String uri = lookupNamespace(prefix); |
|
286 |
if (uri != null && !stable.isExcludedNamespace(uri)) { |
|
287 |
registerNamespace(prefix, uri, stable, true); |
|
288 |
} |
|
289 |
} |
|
290 |
} |
|
291 |
||
292 |
parseChildren(parser); |
|
293 |
||
294 |
// Process all attributes and register all namespaces they use |
|
295 |
for (int i = 0; i < count; i++) { |
|
296 |
final QName qname = parser.getQName(_attributes.getQName(i)); |
|
297 |
final String val = _attributes.getValue(i); |
|
298 |
||
299 |
// Handle xsl:extension-element-prefixes |
|
300 |
if (qname.equals(parser.getExtensionElementPrefixes())) { |
|
301 |
stable.unExcludeNamespaces(val); |
|
302 |
} |
|
303 |
// Handle xsl:exclude-result-prefixes |
|
304 |
else if (qname.equals(parser.getExcludeResultPrefixes())) { |
|
305 |
stable.unExcludeNamespaces(val); |
|
306 |
} |
|
307 |
} |
|
308 |
} |
|
309 |
||
310 |
protected boolean contextDependent() { |
|
311 |
return dependentContents(); |
|
312 |
} |
|
313 |
||
314 |
/** |
|
315 |
* Compiles code that emits the literal element to the output handler, |
|
316 |
* first the start tag, then namespace declaration, then attributes, |
|
317 |
* then the element contents, and then the element end tag. Since the |
|
318 |
* value of an attribute may depend on a variable, variables must be |
|
319 |
* compiled first. |
|
320 |
*/ |
|
321 |
public void translate(ClassGenerator classGen, MethodGenerator methodGen) { |
|
322 |
||
323 |
final ConstantPoolGen cpg = classGen.getConstantPool(); |
|
324 |
final InstructionList il = methodGen.getInstructionList(); |
|
325 |
||
326 |
// Check whether all attributes are unique. |
|
327 |
_allAttributesUnique = checkAttributesUnique(); |
|
328 |
||
329 |
// Compile code to emit element start tag |
|
330 |
il.append(methodGen.loadHandler()); |
|
331 |
||
332 |
il.append(new PUSH(cpg, _name)); |
|
333 |
il.append(DUP2); // duplicate these 2 args for endElement |
|
334 |
il.append(methodGen.startElement()); |
|
335 |
||
336 |
// The value of an attribute may depend on a (sibling) variable |
|
39909
00e4298ae168
8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace
clanger
parents:
35336
diff
changeset
|
337 |
int j = 0; |
12005 | 338 |
while (j < elementCount()) { |
39909
00e4298ae168
8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace
clanger
parents:
35336
diff
changeset
|
339 |
final SyntaxTreeNode item = elementAt(j); |
12005 | 340 |
if (item instanceof Variable) { |
341 |
item.translate(classGen, methodGen); |
|
342 |
} |
|
343 |
j++; |
|
344 |
} |
|
345 |
||
346 |
// Compile code to emit namespace attributes |
|
347 |
if (_accessedPrefixes != null) { |
|
33349 | 348 |
for (Map.Entry<String, String> entry : _accessedPrefixes.entrySet()) { |
349 |
final String prefix = entry.getKey(); |
|
350 |
final String uri = entry.getValue(); |
|
12005 | 351 |
il.append(methodGen.loadHandler()); |
39909
00e4298ae168
8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace
clanger
parents:
35336
diff
changeset
|
352 |
il.append(new PUSH(cpg, prefix)); |
00e4298ae168
8162598: XSLTC transformer swallows empty namespace declaration which is needed to undeclare default namespace
clanger
parents:
35336
diff
changeset
|
353 |
il.append(new PUSH(cpg, uri)); |
12005 | 354 |
il.append(methodGen.namespace()); |
355 |
} |
|
356 |
} |
|
357 |
||
358 |
// Output all attributes |
|
359 |
if (_attributeElements != null) { |
|
33349 | 360 |
for (SyntaxTreeNode node : _attributeElements) { |
12005 | 361 |
if (!(node instanceof XslAttribute)) { |
362 |
node.translate(classGen, methodGen); |
|
363 |
} |
|
364 |
} |
|
365 |
} |
|
366 |
||
367 |
// Compile code to emit attributes and child elements |
|
368 |
translateContents(classGen, methodGen); |
|
369 |
||
370 |
// Compile code to emit element end tag |
|
371 |
il.append(methodGen.endElement()); |
|
372 |
} |
|
373 |
||
374 |
/** |
|
375 |
* Return true if the output method is html. |
|
376 |
*/ |
|
377 |
private boolean isHTMLOutput() { |
|
378 |
return getStylesheet().getOutputMethod() == Stylesheet.HTML_OUTPUT; |
|
379 |
} |
|
380 |
||
381 |
/** |
|
382 |
* Return the ElemDesc object for an HTML element. |
|
383 |
* Return null if the output method is not HTML or this is not a |
|
384 |
* valid HTML element. |
|
385 |
*/ |
|
386 |
public ElemDesc getElemDesc() { |
|
387 |
if (isHTMLOutput()) { |
|
388 |
return ToHTMLStream.getElemDesc(_name); |
|
389 |
} |
|
390 |
else |
|
391 |
return null; |
|
392 |
} |
|
393 |
||
394 |
/** |
|
395 |
* Return true if all attributes of this LRE have unique names. |
|
396 |
*/ |
|
397 |
public boolean allAttributesUnique() { |
|
398 |
return _allAttributesUnique; |
|
399 |
} |
|
400 |
||
401 |
/** |
|
402 |
* Check whether all attributes are unique. |
|
403 |
*/ |
|
404 |
private boolean checkAttributesUnique() { |
|
405 |
boolean hasHiddenXslAttribute = canProduceAttributeNodes(this, true); |
|
406 |
if (hasHiddenXslAttribute) |
|
407 |
return false; |
|
408 |
||
409 |
if (_attributeElements != null) { |
|
410 |
int numAttrs = _attributeElements.size(); |
|
33349 | 411 |
Map<String, SyntaxTreeNode> attrsTable = null; |
12005 | 412 |
for (int i = 0; i < numAttrs; i++) { |
33349 | 413 |
SyntaxTreeNode node = _attributeElements.get(i); |
12005 | 414 |
|
415 |
if (node instanceof UseAttributeSets) { |
|
416 |
return false; |
|
417 |
} |
|
418 |
else if (node instanceof XslAttribute) { |
|
419 |
if (attrsTable == null) { |
|
33349 | 420 |
attrsTable = new HashMap<>(); |
12005 | 421 |
for (int k = 0; k < i; k++) { |
33349 | 422 |
SyntaxTreeNode n = _attributeElements.get(k); |
12005 | 423 |
if (n instanceof LiteralAttribute) { |
424 |
LiteralAttribute literalAttr = (LiteralAttribute)n; |
|
425 |
attrsTable.put(literalAttr.getName(), literalAttr); |
|
426 |
} |
|
427 |
} |
|
428 |
} |
|
429 |
||
430 |
XslAttribute xslAttr = (XslAttribute)node; |
|
431 |
AttributeValue attrName = xslAttr.getName(); |
|
432 |
if (attrName instanceof AttributeValueTemplate) { |
|
433 |
return false; |
|
434 |
} |
|
435 |
else if (attrName instanceof SimpleAttributeValue) { |
|
436 |
SimpleAttributeValue simpleAttr = (SimpleAttributeValue)attrName; |
|
437 |
String name = simpleAttr.toString(); |
|
438 |
if (name != null && attrsTable.get(name) != null) |
|
439 |
return false; |
|
440 |
else if (name != null) { |
|
441 |
attrsTable.put(name, xslAttr); |
|
442 |
} |
|
443 |
} |
|
444 |
} |
|
445 |
} |
|
446 |
} |
|
447 |
return true; |
|
448 |
} |
|
449 |
||
450 |
/** |
|
451 |
* Return true if the instructions under the given SyntaxTreeNode can produce attribute nodes |
|
452 |
* to an element. Only return false when we are sure that no attribute node is produced. |
|
453 |
* Return true if we are not sure. If the flag ignoreXslAttribute is true, the direct |
|
454 |
* <xsl:attribute> children of the current node are not included in the check. |
|
455 |
*/ |
|
456 |
private boolean canProduceAttributeNodes(SyntaxTreeNode node, boolean ignoreXslAttribute) { |
|
33349 | 457 |
List<SyntaxTreeNode> contents = node.getContents(); |
458 |
for (SyntaxTreeNode child : contents) { |
|
12005 | 459 |
if (child instanceof Text) { |
460 |
Text text = (Text)child; |
|
461 |
if (text.isIgnore()) |
|
462 |
continue; |
|
463 |
else |
|
464 |
return false; |
|
465 |
} |
|
466 |
// Cannot add an attribute to an element after children have been added to it. |
|
467 |
// We can safely return false when the instruction can produce an output node. |
|
468 |
else if (child instanceof LiteralElement |
|
469 |
|| child instanceof ValueOf |
|
470 |
|| child instanceof XslElement |
|
471 |
|| child instanceof Comment |
|
472 |
|| child instanceof Number |
|
473 |
|| child instanceof ProcessingInstruction) |
|
474 |
return false; |
|
475 |
else if (child instanceof XslAttribute) { |
|
476 |
if (ignoreXslAttribute) |
|
477 |
continue; |
|
478 |
else |
|
479 |
return true; |
|
480 |
} |
|
481 |
// In general, there is no way to check whether <xsl:call-template> or |
|
482 |
// <xsl:apply-templates> can produce attribute nodes. <xsl:copy> and |
|
483 |
// <xsl:copy-of> can also copy attribute nodes to an element. Return |
|
484 |
// true in those cases to be safe. |
|
485 |
else if (child instanceof CallTemplate |
|
486 |
|| child instanceof ApplyTemplates |
|
487 |
|| child instanceof Copy |
|
488 |
|| child instanceof CopyOf) |
|
489 |
return true; |
|
490 |
else if ((child instanceof If |
|
491 |
|| child instanceof ForEach) |
|
492 |
&& canProduceAttributeNodes(child, false)) { |
|
493 |
return true; |
|
494 |
} |
|
495 |
else if (child instanceof Choose) { |
|
33349 | 496 |
List<SyntaxTreeNode> chooseContents = child.getContents(); |
497 |
for (SyntaxTreeNode chooseChild : chooseContents) { |
|
12005 | 498 |
if (chooseChild instanceof When || chooseChild instanceof Otherwise) { |
499 |
if (canProduceAttributeNodes(chooseChild, false)) |
|
500 |
return true; |
|
501 |
} |
|
502 |
} |
|
503 |
} |
|
504 |
} |
|
505 |
return false; |
|
506 |
} |
|
507 |
||
508 |
} |