// If the content type of the context item is known, see whether the node test can select anything
if (contextItemType instanceof DocumentNodeTest && axis == Axis.CHILD && kind == Type.ELEMENT) {
NodeTest elementTest = ((DocumentNodeTest)contextItemType).getElementTest();
IntHashSet requiredNames = elementTest.getRequiredNodeNames();
if (requiredNames != null) {
// check that the name appearing in the step is one of the names allowed by the nodetest
IntHashSet selected = test.getRequiredNodeNames();
if (selected != null && selected.intersect(requiredNames).isEmpty()) {
env.issueWarning("Starting at a document node, the step is selecting an element whose name " +
"is not among the names of child elements permitted for this document node type", this);
return Literal.makeEmptySequence();
}
}
itemType = elementTest;
return this;
}
SchemaType contentType = ((NodeTest)contextItemType).getContentType();
if (contentType == AnyType.getInstance()) {
// fast exit in non-schema-aware case
return this;
}
int targetfp = test.getFingerprint();
if (contentType.isSimpleType()) {
if ((axis == Axis.CHILD || axis==Axis.ATTRIBUTE || axis==Axis.DESCENDANT || axis==Axis.DESCENDANT_OR_SELF) &&
(kind==Type.ELEMENT || kind==Type.ATTRIBUTE || kind==Type.DOCUMENT)) {
env.issueWarning("The " + Axis.axisName[axis] + " axis will never select any " +
NodeKindTest.nodeKindName(kind) +
" nodes when starting at a node with simple type " +
contentType.getDescription(), this);
}
else if (axis == Axis.CHILD && kind == Type.TEXT &&
(visitor.getParentExpression() instanceof Atomizer)) {
env.issueWarning("Selecting the text nodes of an element with simple content may give the " +
"wrong answer in the presence of comments or processing instructions. It is usually " +
"better to omit the '/text()' step", this);
}
} else if (((ComplexType)contentType).isSimpleContent() &&
(axis==Axis.CHILD || axis==Axis.DESCENDANT || axis==Axis.DESCENDANT_OR_SELF) &&
(kind==Type.ELEMENT || kind==Type.DOCUMENT)) {
env.issueWarning("The " + Axis.axisName[axis] + " axis will never select any " +
NodeKindTest.nodeKindName(kind) +
" nodes when starting at a node with type " +
contentType.getDescription() +
", as this type requires simple content", this);
} else if (((ComplexType)contentType).isEmptyContent() &&
(axis==Axis.CHILD || axis==Axis.DESCENDANT || axis==Axis.DESCENDANT_OR_SELF)) {
for (Iterator iter=visitor.getConfiguration().getExtensionsOfType(contentType); iter.hasNext();) {
ComplexType extension = (ComplexType)iter.next();
if (!extension.isEmptyContent()) {
return this;
}
}
env.issueWarning("The " + Axis.axisName[axis] + " axis will never select any " +
" nodes when starting at a node with type " +
contentType.getDescription() +
", as this type requires empty content", this);
} else if (axis==Axis.ATTRIBUTE && targetfp != -1) {
try {
SchemaType schemaType = ((ComplexType)contentType).getAttributeUseType(targetfp);
if (schemaType == null) {
String n = env.getNamePool().getDisplayName(targetfp);
env.issueWarning("The complex type " + contentType.getDescription() +
" does not allow an attribute named " + n, this);
} else {
itemType = new CombinedNodeTest(
test,
Token.INTERSECT,
new ContentTypeTest(Type.ATTRIBUTE, schemaType, env.getConfiguration()));
}
} catch (SchemaException e) {
// ignore the exception
}
} else if (axis==Axis.CHILD && kind==Type.ELEMENT) {
try {
int childElement = targetfp;
if (targetfp == -1) {
// select="child::*"
IntHashSet children = new IntHashSet();
((ComplexType)contentType).gatherAllPermittedChildren(children);
if (children.isEmpty()) {
env.issueWarning("The complex type " + contentType.getDescription() +
" does not allow children", this);
return this;
}
if (children.contains(-1)) {
return this;
}
if (children.size() == 1) {
IntIterator iter = children.iterator();
if (iter.hasNext()) {
childElement = iter.next();
}
} else {
return this;
}
}
SchemaType schemaType = ((ComplexType)contentType).getElementParticleType(childElement);
if (schemaType == null) {
String n = env.getNamePool().getDisplayName(childElement);
env.issueWarning("The complex type " + contentType.getDescription() +
" does not allow a child element named " + n, this);
} else {
itemType = new CombinedNodeTest(
test,
Token.INTERSECT,
new ContentTypeTest(Type.ELEMENT, schemaType, env.getConfiguration()));
computedCardinality = ((ComplexType)contentType).getElementParticleCardinality(childElement);
visitor.resetStaticProperties();
if (!Cardinality.allowsMany(computedCardinality)) {
// if there can be at most one child of this name, create a FirstItemExpression
// to stop the search after the first one is found
return new FirstItemExpression(this);
}
}
} catch (SchemaException e) {
// ignore the exception
}
} else if (axis==Axis.DESCENDANT && kind==Type.ELEMENT && targetfp != -1) {
// when searching for a specific element on the descendant axis, try to produce a more
// specific path that avoids searching branches of the tree where the element cannot occur
try {
IntHashSet descendants = new IntHashSet();
((ComplexType)contentType).gatherAllPermittedDescendants(descendants);
if (descendants.contains(-1)) {
return this;
}
if (descendants.contains(targetfp)) {
IntHashSet children = new IntHashSet();
((ComplexType)contentType).gatherAllPermittedChildren(children);
IntHashSet usefulChildren = new IntHashSet();
boolean considerSelf = false;
boolean considerDescendants = false;
for (IntIterator child = children.iterator(); child.hasNext();) {
int c = child.next();
if (c == targetfp) {
usefulChildren.add(c);
considerSelf = true;
}
SchemaType st = ((ComplexType)contentType).getElementParticleType(c);
if (st == null) {
throw new AssertionError("Can't find type for element " + c);
}
if (st instanceof ComplexType) {
IntHashSet subDescendants = new IntHashSet();
((ComplexType)st).gatherAllPermittedDescendants(subDescendants);
if (subDescendants.contains(targetfp)) {
usefulChildren.add(c);
considerDescendants = true;
}
}
}