/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package jlibs.xml.sax.dog.path;
import jlibs.core.lang.ArrayUtil;
import jlibs.core.lang.ImpossibleException;
import jlibs.xml.sax.dog.DataType;
import jlibs.xml.sax.dog.Scope;
import jlibs.xml.sax.dog.expr.Expression;
import jlibs.xml.sax.dog.expr.nodset.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author Santhosh Kumar T
*/
public final class LocationPath extends Predicated{
public static final LocationPath LOCAL_CONTEXT = new LocationPath(Scope.LOCAL, 0);
public static final LocationPath DOCUMENT_CONTEXT = new LocationPath(Scope.DOCUMENT, 0);
public static final LocationPath IMPOSSIBLE = new LocationPath(Scope.GLOBAL, 0);
public final int scope;
public final Step steps[];
public boolean pathExpression;
public LocationPath(int scope, int noOfSteps){
this.scope = scope;
steps = new Step[noOfSteps];
}
public final List<LocationPath> contexts = new ArrayList<LocationPath>();
public void addToContext(LocationPath path){
if(!path.pathExpression && path.contexts.size()>0)
contexts.addAll(path.contexts);
else
contexts.add(path);
if(!path.pathExpression && path.predicateSet.predicate!=null){
assert predicateSet.predicate==null;
predicateSet = path.predicateSet;
path.predicateSet = new PredicateSet();
assert hitExpression==null;
hitExpression = path.hitExpression;
path.hitExpression = null;
}
}
public PathExpression.HitExpression hitExpression;
@Override
public void addPredicate(Expression predicate){
if(hitExpression==null && !predicateSet.hasPosition){
boolean hasPosition = predicateSet.hasPosition(predicate);
if(hasPosition){
hitExpression = new PathExpression.HitExpression();
super.addPredicate(hitExpression);
}
}
super.addPredicate(predicate);
}
public Expression typeCast(DataType dataType){
LocationExpression expr = _typeCast(dataType);
if(contexts.size()>0)
return new PathExpression(this, expr, false);
else
return expr;
}
private LocationExpression _typeCast(DataType dataType){
switch(dataType){
case NODESET:
return new NodeSet(this);
case BOOLEAN:
return new Bool(this);
case STRINGS:
return new Strings(this, DataType.STRINGS, true, false);
case STRING:
return new Strings(this, DataType.STRING, false, true);
case NUMBER:
return new Strings(this, DataType.NUMBER, false, true);
case NUMBERS:
return new Strings(this, DataType.NUMBERS, true, false);
default:
throw new ImpossibleException("can't type cast locationPath to "+dataType.name());
}
}
public Expression apply(String function){
LocationExpression expr = _apply(function);
if(contexts.size()>0)
return new PathExpression(this, expr, false);
else
return expr;
}
private LocationExpression _apply(String function){
switch(function.length()){
case 3:
if(function.equals("sum"))
return new Strings(this, DataType.NUMBER, true, false);
return null;
case 4:
if(function.equals("name"))
return new QualifiedName(this);
return null;
case 5:
if(function.equals("count"))
return new Count(this);
return null;
case 6:
if(function.equals("string"))
return new Strings(this, DataType.STRING, false, true);
else if(function.equals("number"))
return new Strings(this, DataType.NUMBER, false, true);
return null;
case 7:
if(function.equals("boolean"))
return new Bool(this);
else if(function.equals("strings"))
return new Strings(this, DataType.STRINGS, true, false);
return null;
case 10:
if(function.equals("local-name"))
return new LocalName(this);
return null;
case 13:
if(function.equals("namespace-uri"))
return new NamespaceURI(this);
return null;
default:
assert !ArrayUtil.contains(new String[]{
"sum", "name", "count", "string", "number",
"boolean", "strings", "local-name", "namespace-uri"
}, function);
return null;
}
}
@Override
public String toString(){
if(steps.length==0)
return scope==Scope.DOCUMENT ? "/" : "";
else{
StringBuilder buff = new StringBuilder();
for(Step step: steps)
buff.append('/').append(step);
return buff.substring(scope==Scope.DOCUMENT ? 0 : 1);
}
}
}