use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class XPathPathExpr method getReference.
/**
* translate an xpath path reference into a TreeReference
* TreeReferences only support a subset of true xpath paths; restrictions are:
* simple child name tests 'child::name', '.', and '..' allowed only
* no predicates
* all '..' steps must come before anything else
*/
public TreeReference getReference(boolean allowPredicates) throws XPathUnsupportedException {
TreeReference ref = new TreeReference();
boolean parentsAllowed;
switch(init_context) {
case XPathPathExpr.INIT_CONTEXT_ROOT:
ref.setRefLevel(TreeReference.REF_ABSOLUTE);
parentsAllowed = false;
break;
case XPathPathExpr.INIT_CONTEXT_RELATIVE:
ref.setRefLevel(0);
parentsAllowed = true;
break;
case XPathPathExpr.INIT_CONTEXT_EXPR:
if (this.filtExpr.x != null && this.filtExpr.x instanceof XPathFuncExpr) {
XPathFuncExpr func = (XPathFuncExpr) (this.filtExpr.x);
if (func.id.toString().equals("instance")) {
// i assume when refering the non main instance you have to be absolute
ref.setRefLevel(TreeReference.REF_ABSOLUTE);
parentsAllowed = false;
if (func.args.length != 1) {
throw new XPathUnsupportedException("instance() function used with " + func.args.length + " arguements. Expecting 1 arguement");
}
if (!(func.args[0] instanceof XPathStringLiteral)) {
throw new XPathUnsupportedException("instance() function expecting 1 string literal arguement arguement");
}
XPathStringLiteral strLit = (XPathStringLiteral) (func.args[0]);
// we've got a non-standard instance in play, watch out
if (strLit.s == null) {
// absolute reference to the main instance
ref.setContext(TreeReference.CONTEXT_ABSOLUTE);
ref.setInstanceName(null);
} else {
ref.setContext(TreeReference.CONTEXT_INSTANCE);
ref.setInstanceName(strLit.s);
}
} else if (func.id.toString().equals("current")) {
parentsAllowed = true;
ref.setContext(TreeReference.CONTEXT_ORIGINAL);
} else {
// We only support expression root contexts for instance refs, everything else is an illegal filter
throw new XPathUnsupportedException("filter expression");
}
} else {
// We only support expression root contexts for instance refs, everything else is an illegal filter
throw new XPathUnsupportedException("filter expression");
}
break;
default:
throw new XPathUnsupportedException("filter expression");
}
for (int i = 0; i < steps.length; i++) {
XPathStep step = steps[i];
if (step.axis == XPathStep.AXIS_SELF) {
if (step.test != XPathStep.TEST_TYPE_NODE) {
throw new XPathUnsupportedException("step other than 'child::name', '.', '..'");
}
} else if (step.axis == XPathStep.AXIS_PARENT) {
if (!parentsAllowed || step.test != XPathStep.TEST_TYPE_NODE) {
throw new XPathUnsupportedException("step other than 'child::name', '.', '..'");
} else {
ref.incrementRefLevel();
}
} else if (step.axis == XPathStep.AXIS_ATTRIBUTE) {
if (step.test == XPathStep.TEST_NAME) {
ref.add(step.name.toString(), TreeReference.INDEX_ATTRIBUTE);
parentsAllowed = false;
// TODO: Can you step back from an attribute, or should this always be
// the last step?
} else {
throw new XPathUnsupportedException("attribute step other than 'attribute::name");
}
} else if (step.axis == XPathStep.AXIS_CHILD) {
if (step.test == XPathStep.TEST_NAME) {
ref.add(step.name.toString(), TreeReference.INDEX_UNBOUND);
parentsAllowed = true;
} else if (step.test == XPathStep.TEST_NAME_WILDCARD) {
ref.add(TreeReference.NAME_WILDCARD, TreeReference.INDEX_UNBOUND);
parentsAllowed = true;
} else {
throw new XPathUnsupportedException("step other than 'child::name', '.', '..'");
}
} else {
throw new XPathUnsupportedException("step other than 'child::name', '.', '..'");
}
if (step.predicates.length > 0) {
int refLevel = ref.getRefLevel();
List<XPathExpression> v = new ArrayList<XPathExpression>(step.predicates.length);
for (int j = 0; j < step.predicates.length; j++) {
v.add(step.predicates[j]);
}
ref.addPredicate(i, v);
}
}
return ref;
}
use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class Fast2014DagImpl method copyItemsetAnswer.
@Override
public void copyItemsetAnswer(FormInstance mainInstance, EvaluationContext evalContext, TreeReference copyRef, TreeElement copyToElement, boolean midSurvey) {
TreeReference targetRef = copyToElement.getRef();
Set<QuickTriggerable> qtSet1 = triggerTriggerables(mainInstance, evalContext, copyRef, midSurvey, // trigger conditions that
new HashSet<QuickTriggerable>(0));
// depend on the creation of
// these new nodes
publishSummary("Copied itemset answer (phase 1)", targetRef, qtSet1);
Set<QuickTriggerable> qtSet2 = initializeTriggerables(mainInstance, evalContext, copyRef, midSurvey, // initialize conditions for
new HashSet<QuickTriggerable>(0));
// the node (and sub-nodes)
publishSummary("Copied itemset answer (phase 2)", targetRef, qtSet2);
// not 100% sure this will work since destRef is ambiguous as the last
// step, but i think it's supposed to work
}
use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class Fast2014DagImpl method finalizeTriggerables.
/**
* Finalize the DAG associated with the form's triggered conditions. This
* will create the appropriate ordering and dependencies to ensure the
* conditions will be evaluated in the appropriate orders.
*
* @throws IllegalStateException
* - If the trigger ordering contains an illegal cycle and the
* triggers can't be laid out appropriately
*/
@Override
public void finalizeTriggerables(FormInstance mainInstance, EvaluationContext evalContext) throws IllegalStateException {
//
// DAGify the triggerables based on dependencies and sort them so that
// triggerables come only after the triggerables they depend on
//
ArrayList<QuickTriggerable> vertices = new ArrayList<QuickTriggerable>(unorderedTriggerables);
triggerablesDAG.clear();
ArrayList<QuickTriggerable[]> partialOrdering = new ArrayList<QuickTriggerable[]>();
HashSet<QuickTriggerable> deps = new HashSet<QuickTriggerable>();
HashSet<QuickTriggerable> newDestinationSet = new HashSet<QuickTriggerable>();
for (QuickTriggerable qt : vertices) {
deps.clear();
newDestinationSet.clear();
fillTriggeredElements(mainInstance, evalContext, qt, deps, newDestinationSet, true);
// remove any self-reference if we have one...
deps.remove(qt);
for (QuickTriggerable qu : deps) {
QuickTriggerable[] edge = { qt, qu };
partialOrdering.add(edge);
}
// save for aggressive 2014 behavior
qt.t.setImmediateCascades(deps);
}
ArrayList<QuickTriggerable> orderedRoots = new ArrayList<QuickTriggerable>();
HashSet<QuickTriggerable> roots = new HashSet<QuickTriggerable>(vertices.size());
int waveCount = -1;
while (vertices.size() > 0) {
++waveCount;
// determine root nodes
roots.clear();
roots.addAll(vertices);
for (int i = 0; i < partialOrdering.size(); i++) {
QuickTriggerable[] edge = partialOrdering.get(i);
roots.remove(edge[1]);
}
// if no root nodes while graph still has nodes, graph has cycles
if (roots.size() == 0) {
String hints = "";
for (QuickTriggerable qt : vertices) {
for (TreeReference r : qt.t.getTargets()) {
hints += "\n" + r.toString(true);
}
}
String message = "Cycle detected in form's relevant and calculation logic!";
if (!hints.equals("")) {
message += "\nThe following nodes are likely involved in the loop:" + hints;
}
throw new IllegalStateException(message);
}
// order the root nodes - mainly for clean textual diffs when
// printing
// When this code is rewritten to use HashSet, this will become
// important.
orderedRoots.clear();
orderedRoots.addAll(roots);
Collections.sort(orderedRoots, QuickTriggerable.quickTriggerablesRootOrdering);
// add them to the triggerablesDAG.
for (int i = 0; i < orderedRoots.size(); i++) {
QuickTriggerable root = orderedRoots.get(i);
root.t.setWaveCount(waveCount);
triggerablesDAG.add(root);
vertices.remove(root);
}
for (int i = partialOrdering.size() - 1; i >= 0; i--) {
QuickTriggerable[] edge = partialOrdering.get(i);
if (roots.contains(edge[0]))
partialOrdering.remove(i);
}
}
//
// build the condition index for repeatable nodes
//
conditionRepeatTargetIndex.clear();
for (QuickTriggerable qt : triggerablesDAG) {
if (qt.t instanceof Condition) {
List<TreeReference> targets = qt.t.getTargets();
for (TreeReference target : targets) {
if (mainInstance.getTemplate(target) != null) {
conditionRepeatTargetIndex.put(target, qt);
}
}
}
}
// printTriggerables();
}
use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class Fast2014DagImpl method initializeTriggerables.
private Set<QuickTriggerable> initializeTriggerables(FormInstance mainInstance, EvaluationContext evalContext, TreeReference rootRef, boolean midSurvey, Set<QuickTriggerable> alreadyEvaluated) {
TreeReference genericRoot = rootRef.genericize();
Set<QuickTriggerable> applicable = new HashSet<QuickTriggerable>();
for (int i = 0; i < triggerablesDAG.size(); i++) {
QuickTriggerable qt = triggerablesDAG.get(i);
for (int j = 0; j < qt.t.getTargets().size(); j++) {
TreeReference target = qt.t.getTargets().get(j);
if (genericRoot.isParentOf(target, false)) {
applicable.add(qt);
break;
}
}
}
return evaluateTriggerables(mainInstance, evalContext, applicable, rootRef, midSurvey, alreadyEvaluated);
}
use of org.javarosa.core.model.instance.TreeReference in project javarosa by opendatakit.
the class Fast2014DagImpl method addChildrenOfReference.
/**
* This is a utility method to get all of the references of a node. It can
* be replaced when we support dependent XPath Steps (IE: /path/to//)
*/
public void addChildrenOfReference(FormInstance mainInstance, EvaluationContext evalContext, TreeReference original, Set<TreeReference> toAdd, boolean expandRepeatables) {
// original has already been added to the 'toAdd' list.
TreeElement repeatTemplate = expandRepeatables ? mainInstance.getTemplatePath(original) : null;
if (repeatTemplate != null) {
for (int i = 0; i < repeatTemplate.getNumChildren(); ++i) {
TreeElement child = repeatTemplate.getChildAt(i);
toAdd.add(child.getRef().genericize());
addChildrenOfElement(mainInstance, evalContext, child, toAdd, expandRepeatables);
}
} else {
List<TreeReference> refSet = evalContext.expandReference(original);
for (TreeReference ref : refSet) {
addChildrenOfElement(mainInstance, evalContext, evalContext.resolveReference(ref), toAdd, expandRepeatables);
}
}
}
Aggregations