* <code>XPathVisitor</code>.
* @return the current <code>QueryNode</code>. Can be different from
* <code>data</code>.
*/
public Object visit(SimpleNode node, Object data) {
QueryNode queryNode = (QueryNode) data;
switch (node.getId()) {
case JJTXPATH2:
queryNode = createPathQueryNode(node);
break;
case JJTROOT:
case JJTROOTDESCENDANTS:
((PathQueryNode) queryNode).setAbsolute(true);
break;
case JJTSTEPEXPR:
if (isAttributeAxis(node)) {
if (queryNode.getType() == QueryNode.TYPE_RELATION
|| (queryNode.getType() == QueryNode.TYPE_DEREF && ((DerefQueryNode) queryNode).getRefProperty() == null)
|| queryNode.getType() == QueryNode.TYPE_ORDER
|| queryNode.getType() == QueryNode.TYPE_PATH
|| queryNode.getType() == QueryNode.TYPE_TEXTSEARCH) {
// traverse
node.childrenAccept(this, queryNode);
} else if (queryNode.getType() == QueryNode.TYPE_NOT) {
// is null expression
RelationQueryNode isNull
= new RelationQueryNode(queryNode,
RelationQueryNode.OPERATION_NULL);
node.childrenAccept(this, isNull);
NotQueryNode notNode = (NotQueryNode) queryNode;
NAryQueryNode parent = (NAryQueryNode) notNode.getParent();
parent.removeOperand(notNode);
parent.addOperand(isNull);
} else {
// not null expression
RelationQueryNode notNull
= new RelationQueryNode(queryNode,
RelationQueryNode.OPERATION_NOT_NULL);
node.childrenAccept(this, notNull);
((NAryQueryNode) queryNode).addOperand(notNull);
}
} else {
if (queryNode.getType() == QueryNode.TYPE_PATH) {
createLocationStep(node, (NAryQueryNode) queryNode);
} else if (queryNode.getType() == QueryNode.TYPE_TEXTSEARCH) {
// ignore
} else {
exceptions.add(new InvalidQueryException("Only attribute axis is allowed in predicate"));
}
}
break;
case JJTNAMETEST:
if (queryNode.getType() == QueryNode.TYPE_LOCATION
|| queryNode.getType() == QueryNode.TYPE_DEREF
|| queryNode.getType() == QueryNode.TYPE_RELATION
|| queryNode.getType() == QueryNode.TYPE_TEXTSEARCH
|| queryNode.getType() == QueryNode.TYPE_PATH) {
createNodeTest(node, queryNode);
} else if (queryNode.getType() == QueryNode.TYPE_ORDER) {
createOrderSpec(node, (OrderQueryNode) queryNode);
} else {
// traverse
node.childrenAccept(this, queryNode);
}
break;
case JJTELEMENTNAMEORWILDCARD:
if (queryNode.getType() == QueryNode.TYPE_LOCATION) {
SimpleNode child = (SimpleNode) node.jjtGetChild(0);
if (child.getId() != JJTANYNAME) {
createNodeTest(child, queryNode);
}
}
break;
case JJTTEXTTEST:
if (queryNode.getType() == QueryNode.TYPE_LOCATION) {
LocationStepQueryNode loc = (LocationStepQueryNode) queryNode;
loc.setNameTest(JCR_XMLTEXT);
}
break;
case JJTTYPENAME:
if (queryNode.getType() == QueryNode.TYPE_LOCATION) {
LocationStepQueryNode loc = (LocationStepQueryNode) queryNode;
String ntName = ((SimpleNode) node.jjtGetChild(0)).getValue();
try {
QName nt = NameFormat.parse(ntName, resolver);
NodeTypeQueryNode nodeType = new NodeTypeQueryNode(loc, nt);
loc.addPredicate(nodeType);
} catch (IllegalNameException e) {
exceptions.add(new InvalidQueryException("Not a valid name: " + ntName));
} catch (UnknownPrefixException e) {
exceptions.add(new InvalidQueryException("Unknown prefix in name: " + ntName));
}
}
break;
case JJTOREXPR:
NAryQueryNode parent = (NAryQueryNode) queryNode;
queryNode = new OrQueryNode(parent);
parent.addOperand(queryNode);
// traverse
node.childrenAccept(this, queryNode);
break;
case JJTANDEXPR:
parent = (NAryQueryNode) queryNode;
queryNode = new AndQueryNode(parent);
parent.addOperand(queryNode);
// traverse
node.childrenAccept(this, queryNode);
break;
case JJTCOMPARISONEXPR:
createExpression(node, (NAryQueryNode) queryNode);
break;
case JJTSTRINGLITERAL:
case JJTDECIMALLITERAL:
case JJTDOUBLELITERAL:
case JJTINTEGERLITERAL:
if (queryNode.getType() == QueryNode.TYPE_RELATION) {
assignValue(node, (RelationQueryNode) queryNode);
} else if (queryNode.getType() == QueryNode.TYPE_LOCATION) {
if (node.getId() == JJTINTEGERLITERAL) {
int index = Integer.parseInt(node.getValue());
((LocationStepQueryNode) queryNode).setIndex(index);
} else {
exceptions.add(new InvalidQueryException("LocationStep only allows integer literal as position index"));
}
} else {
exceptions.add(new InvalidQueryException("Parse error: data is not a RelationQueryNode"));
}
break;
case JJTUNARYMINUS:
if (queryNode.getType() == QueryNode.TYPE_RELATION) {
((RelationQueryNode) queryNode).setUnaryMinus(true);
} else {
exceptions.add(new InvalidQueryException("Parse error: data is not a RelationQueryNode"));
}
break;
case JJTFUNCTIONCALL:
queryNode = createFunction(node, queryNode);
break;
case JJTORDERBYCLAUSE:
root.setOrderNode(new OrderQueryNode(root));
queryNode = root.getOrderNode();
node.childrenAccept(this, queryNode);
break;
case JJTORDERMODIFIER:
if (node.jjtGetNumChildren() > 0
&& ((SimpleNode) node.jjtGetChild(0)).getId() == JJTDESCENDING) {
OrderQueryNode.OrderSpec[] specs = ((OrderQueryNode) queryNode).getOrderSpecs();
specs[specs.length - 1].setAscending(false);
}
break;
case JJTPREDICATELIST:
if (queryNode.getType() == QueryNode.TYPE_PATH) {
// switch to last location
QueryNode[] operands = ((PathQueryNode) queryNode).getOperands();
queryNode = operands[operands.length - 1];
}
node.childrenAccept(this, queryNode);