use of org.javarosa.core.model.instance.FormInstance in project collect by opendatakit.
the class FormController method getFilledInFormXml.
/**
* Constructs the XML payload for a filled-in form instance. This payload
* enables a filled-in form to be re-opened and edited.
*/
public ByteArrayPayload getFilledInFormXml() throws IOException {
// assume no binary data inside the model.
FormInstance datamodel = getInstance();
XFormSerializingVisitor serializer = new XFormSerializingVisitor();
return (ByteArrayPayload) serializer.createSerializedPayload(datamodel);
}
use of org.javarosa.core.model.instance.FormInstance in project collect by opendatakit.
the class ExternalAppsUtils method populateParameters.
public static void populateParameters(Intent intent, Map<String, String> exParams, TreeReference reference) throws ExternalParamsException {
FormDef formDef = Collect.getInstance().getFormController().getFormDef();
FormInstance formInstance = formDef.getInstance();
EvaluationContext evaluationContext = new EvaluationContext(formDef.getEvaluationContext(), reference);
if (exParams != null) {
for (Map.Entry<String, String> paramEntry : exParams.entrySet()) {
String paramEntryValue = paramEntry.getValue();
try {
Object result;
if (paramEntryValue.startsWith("'")) {
// but not require an ending quote
if (paramEntryValue.endsWith("'")) {
result = paramEntryValue.substring(1, paramEntryValue.length() - 1);
} else {
result = paramEntryValue.substring(1, paramEntryValue.length());
}
} else if (paramEntryValue.startsWith("/")) {
// treat this is an xpath
XPathPathExpr pathExpr = XPathReference.getPathExpr(paramEntryValue);
XPathNodeset xpathNodeset = pathExpr.eval(formInstance, evaluationContext);
result = XPathFuncExpr.unpack(xpathNodeset);
} else if (paramEntryValue.equals("instanceProviderID()")) {
// instanceProviderID returns -1 if the current instance has not been
// saved to disk already
String path = Collect.getInstance().getFormController().getInstanceFile().getAbsolutePath();
String instanceProviderID = "-1";
Cursor c = new InstancesDao().getInstancesCursorForFilePath(path);
if (c != null && c.getCount() > 0) {
// should only ever be one
c.moveToFirst();
instanceProviderID = c.getString(c.getColumnIndex(InstanceColumns._ID));
}
if (c != null) {
c.close();
}
result = instanceProviderID;
} else {
// treat this is a function
XPathExpression xpathExpression = XPathParseTool.parseXPath(paramEntryValue);
result = xpathExpression.eval(formInstance, evaluationContext);
}
if (result != null && result instanceof Serializable) {
intent.putExtra(paramEntry.getKey(), (Serializable) result);
}
} catch (Exception e) {
throw new ExternalParamsException("Could not evaluate '" + paramEntryValue + "'", e);
}
}
}
}
use of org.javarosa.core.model.instance.FormInstance in project collect by opendatakit.
the class ExternalDataUtil method populateExternalChoices.
public static ArrayList<SelectChoice> populateExternalChoices(FormEntryPrompt formEntryPrompt, XPathFuncExpr xpathfuncexpr) {
try {
List<SelectChoice> selectChoices = formEntryPrompt.getSelectChoices();
ArrayList<SelectChoice> returnedChoices = new ArrayList<SelectChoice>();
for (SelectChoice selectChoice : selectChoices) {
String value = selectChoice.getValue();
if (isAnInteger(value)) {
// treat this as a static choice
returnedChoices.add(selectChoice);
} else {
String displayColumns = formEntryPrompt.getSelectChoiceText(selectChoice);
String imageColumn = formEntryPrompt.getSpecialFormSelectChoiceText(selectChoice, FormEntryCaption.TEXT_FORM_IMAGE);
if (imageColumn != null && imageColumn.startsWith(JR_IMAGES_PREFIX)) {
imageColumn = imageColumn.substring(JR_IMAGES_PREFIX.length());
}
// if (displayColumns == null || displayColumns.trim().length() == 0) {
// throw new InvalidSyntaxException("The label column in the choices sheet
// appears to be empty (or has been calculated as empty).");
// }
ExternalDataManager externalDataManager = Collect.getInstance().getExternalDataManager();
FormInstance formInstance = Collect.getInstance().getFormController().getFormDef().getInstance();
EvaluationContext baseEvaluationContext = new EvaluationContext(formInstance);
EvaluationContext evaluationContext = new EvaluationContext(baseEvaluationContext, formEntryPrompt.getIndex().getReference());
// we can only add only the appropriate by querying the xPathFuncExpr.id.name
evaluationContext.addFunctionHandler(new ExternalDataHandlerSearch(externalDataManager, displayColumns, value, imageColumn));
Object eval = xpathfuncexpr.eval(formInstance, evaluationContext);
if (eval.getClass().isAssignableFrom(ArrayList.class)) {
@SuppressWarnings("unchecked") List<SelectChoice> dynamicChoices = (ArrayList<SelectChoice>) eval;
for (SelectChoice dynamicChoice : dynamicChoices) {
returnedChoices.add(dynamicChoice);
}
} else {
throw new ExternalDataException(Collect.getInstance().getString(R.string.ext_search_return_error, eval.getClass().getName()));
}
}
}
return returnedChoices;
} catch (Exception e) {
throw new ExternalDataException(e.getMessage(), e);
}
}
use of org.javarosa.core.model.instance.FormInstance in project briefcase by opendatakit.
the class BaseFormParserForJavaRosa method compareXml.
/**
* Compare two XML files to assess their level of structural difference (if
* any).
*
* @param incomingParser -- parsed version of incoming form
* @param existingXml -- the existing Xml for this form
* @return XFORMS_SHARE_INSTANCE when bodies differ but instances and bindings
* are identical; XFORMS_SHARE_SCHEMA when bodies and/or bindings
* differ, but database structure remains unchanged; XFORMS_DIFFERENT
* when forms are different enough to affect database structure and/or
* encryption.
* @throws ODKIncompleteSubmissionData
*/
public static DifferenceResult compareXml(BaseFormParserForJavaRosa incomingParser, String existingXml, String existingTitle, boolean isWithinUpdateWindow) throws ODKIncompleteSubmissionData {
if (incomingParser == null || existingXml == null) {
throw new ODKIncompleteSubmissionData(Reason.MISSING_XML);
}
// generally only the case within Briefcase
if (incomingParser.xml.equals(existingXml)) {
return DifferenceResult.XFORMS_IDENTICAL;
}
// parse XML
FormDef formDef1;
FormDef formDef2;
BaseFormParserForJavaRosa existingParser = new BaseFormParserForJavaRosa(existingXml, existingTitle, true);
formDef1 = incomingParser.rootJavaRosaFormDef;
formDef2 = existingParser.rootJavaRosaFormDef;
if (formDef1 == null || formDef2 == null) {
throw new ODKIncompleteSubmissionData("Javarosa failed to construct a FormDef. Is this an XForm definition?", Reason.BAD_JR_PARSE);
}
// check that the version is advancing from the earlier
// form upload. The comparison is string-based, not
// numeric-based (OpenRosa compliance). The recommended
// version format is: yyyymmddnn e.g., 2012060100
String ivs = incomingParser.rootElementDefn.versionString;
if (ivs == null) {
// if we are changing the file, the new file must have a version string
return DifferenceResult.XFORMS_MISSING_VERSION;
}
String evs = existingParser.rootElementDefn.versionString;
boolean modelVersionSame = (incomingParser.rootElementDefn.modelVersion == null) ? (existingParser.rootElementDefn.modelVersion == null) : incomingParser.rootElementDefn.modelVersion.equals(existingParser.rootElementDefn.modelVersion);
boolean isEarlierVersion = false;
if (!(evs == null || (modelVersionSame && ivs.length() > evs.length()) || (!modelVersionSame && ivs.compareTo(evs) > 0))) {
// disallow updates if none of the following applies:
// (1) if the existing form does not have a version (the new one does).
// (2) if the existing form and new form have the same model version
// and the new form has more leading zeros.
// (3) if the existing form and new form have different model versions
// and the new version string is lexically greater than the old one.
isEarlierVersion = true;
return DifferenceResult.XFORMS_EARLIER_VERSION;
}
/*
* Changes in encryption (either on or off, or change in key) are a major
* change. We could allow the public key to be revised, but most users won't
* understand that this is possible or know how to do it.
*
* Ignore whether a submission profile is present or absent provided it does
* not affect encryption or change the portion of the form being returned.
*/
SubmissionProfile subProfile1 = formDef1.getSubmissionProfile();
SubmissionProfile subProfile2 = formDef2.getSubmissionProfile();
if (subProfile1 != null && subProfile2 != null) {
// we have two profiles -- check that any encryption key matches...
String publicKey1 = subProfile1.getAttribute(BASE64_RSA_PUBLIC_KEY);
String publicKey2 = subProfile2.getAttribute(BASE64_RSA_PUBLIC_KEY);
if (publicKey1 != null && publicKey2 != null) {
// both have encryption
if (!publicKey1.equals(publicKey2)) {
// keys differ
return (DifferenceResult.XFORMS_DIFFERENT);
}
} else if (publicKey1 != null || publicKey2 != null) {
// one or the other has encryption (and the other doesn't)...
return (DifferenceResult.XFORMS_DIFFERENT);
}
// get the TreeElement (e1, e2) that identifies the portion of the form
// that will be submitted to Aggregate.
IDataReference r;
r = subProfile1.getRef();
AbstractTreeElement<?> e1 = (r != null) ? formDef1.getInstance().resolveReference(r) : null;
r = subProfile2.getRef();
AbstractTreeElement<?> e2 = (r != null) ? formDef2.getInstance().resolveReference(r) : null;
if (e1 != null && e2 != null) {
// Ignore all namespace differences (Aggregate ignores them)...
while (e1 != null && e2 != null) {
if (!e1.getName().equals(e2.getName())) {
return (DifferenceResult.XFORMS_DIFFERENT);
}
e1 = e1.getParent();
e2 = e2.getParent();
}
if (e1 != null || e2 != null) {
// they should both terminate at the same time...
return (DifferenceResult.XFORMS_DIFFERENT);
}
// we may still have differences, but if the overall form
// is identical, we are golden...
} else if (e1 != null || e2 != null) {
// one returns a portion of the form and the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
} else if (subProfile1 != null) {
if (subProfile1.getAttribute(BASE64_RSA_PUBLIC_KEY) != null) {
// xml1 does encryption, the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
IDataReference r = subProfile1.getRef();
if (r != null && formDef1.getInstance().resolveReference(r) != null) {
// xml1 returns a portion of the form, the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
} else if (subProfile2 != null) {
if (subProfile2.getAttribute(BASE64_RSA_PUBLIC_KEY) != null) {
// xml2 does encryption, the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
IDataReference r = subProfile2.getRef();
if (r != null && formDef2.getInstance().resolveReference(r) != null) {
// xml2 returns a portion of the form, the other doesn't
return (DifferenceResult.XFORMS_DIFFERENT);
}
}
// get data model to compare instances
FormInstance dataModel1 = formDef1.getInstance();
FormInstance dataModel2 = formDef2.getInstance();
if (dataModel1 == null || dataModel2 == null) {
throw new ODKIncompleteSubmissionData("Javarosa failed to construct a FormInstance. Is this an XForm definition?", Reason.BAD_JR_PARSE);
}
// return result of element-by-element instance/binding comparison
DifferenceResult rc = compareTreeElements(dataModel1.getRoot(), incomingParser, dataModel2.getRoot(), existingParser);
if (DifferenceResult.XFORMS_DIFFERENT == rc) {
return rc;
} else if (isEarlierVersion) {
return DifferenceResult.XFORMS_EARLIER_VERSION;
} else {
return rc;
}
}
use of org.javarosa.core.model.instance.FormInstance in project javarosa by opendatakit.
the class XFormParser method restoreDataModel.
public static FormInstance restoreDataModel(Document doc, Class restorableType) {
Restorable r = (restorableType != null ? (Restorable) PrototypeFactory.getInstance(restorableType) : null);
Element e = doc.getRootElement();
TreeElement te = buildInstanceStructure(e, null, buildNamespacesMap(e), null);
FormInstance dm = new FormInstance(te);
loadNamespaces(e, dm);
if (r != null) {
RestoreUtils.templateData(r, dm, null);
}
loadInstanceData(e, te, null);
return dm;
}
Aggregations