Search in sources :

Example 16 with FormInstance

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);
}
Also used : ByteArrayPayload(org.javarosa.core.services.transport.payload.ByteArrayPayload) XFormSerializingVisitor(org.javarosa.model.xform.XFormSerializingVisitor) FormInstance(org.javarosa.core.model.instance.FormInstance)

Example 17 with FormInstance

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);
            }
        }
    }
}
Also used : XPathExpression(org.javarosa.xpath.expr.XPathExpression) Serializable(java.io.Serializable) XPathPathExpr(org.javarosa.xpath.expr.XPathPathExpr) Cursor(android.database.Cursor) ExternalParamsException(org.odk.collect.android.exception.ExternalParamsException) ExternalParamsException(org.odk.collect.android.exception.ExternalParamsException) InstancesDao(org.odk.collect.android.dao.InstancesDao) FormDef(org.javarosa.core.model.FormDef) XPathNodeset(org.javarosa.xpath.XPathNodeset) EvaluationContext(org.javarosa.core.model.condition.EvaluationContext) FormInstance(org.javarosa.core.model.instance.FormInstance) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 18 with FormInstance

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);
    }
}
Also used : SelectChoice(org.javarosa.core.model.SelectChoice) ArrayList(java.util.ArrayList) ExternalDataException(org.odk.collect.android.exception.ExternalDataException) ExternalDataHandlerSearch(org.odk.collect.android.external.handler.ExternalDataHandlerSearch) XPathSyntaxException(org.javarosa.xpath.parser.XPathSyntaxException) ExternalDataException(org.odk.collect.android.exception.ExternalDataException) EvaluationContext(org.javarosa.core.model.condition.EvaluationContext) FormInstance(org.javarosa.core.model.instance.FormInstance)

Example 19 with FormInstance

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;
    }
}
Also used : FormDef(org.javarosa.core.model.FormDef) IDataReference(org.javarosa.core.model.IDataReference) ODKIncompleteSubmissionData(org.opendatakit.aggregate.exception.ODKIncompleteSubmissionData) SubmissionProfile(org.javarosa.core.model.SubmissionProfile) FormInstance(org.javarosa.core.model.instance.FormInstance)

Example 20 with FormInstance

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;
}
Also used : TreeElement(org.javarosa.core.model.instance.TreeElement) AbstractTreeElement(org.javarosa.core.model.instance.AbstractTreeElement) Element(org.kxml2.kdom.Element) IFormElement(org.javarosa.core.model.IFormElement) FormInstance(org.javarosa.core.model.instance.FormInstance) Restorable(org.javarosa.core.model.util.restorable.Restorable) TreeElement(org.javarosa.core.model.instance.TreeElement) AbstractTreeElement(org.javarosa.core.model.instance.AbstractTreeElement)

Aggregations

FormInstance (org.javarosa.core.model.instance.FormInstance)32 TreeElement (org.javarosa.core.model.instance.TreeElement)16 TreeReference (org.javarosa.core.model.instance.TreeReference)8 Test (org.junit.Test)7 InstanceInitializationFactory (org.javarosa.core.model.instance.InstanceInitializationFactory)6 FormDef (org.javarosa.core.model.FormDef)5 AbstractTreeElement (org.javarosa.core.model.instance.AbstractTreeElement)5 IOException (java.io.IOException)4 EvaluationContext (org.javarosa.core.model.condition.EvaluationContext)3 StringData (org.javarosa.core.model.data.StringData)3 ByteArrayPayload (org.javarosa.core.services.transport.payload.ByteArrayPayload)3 XFormSerializingVisitor (org.javarosa.model.xform.XFormSerializingVisitor)3 XPathNodeset (org.javarosa.xpath.XPathNodeset)3 ArrayList (java.util.ArrayList)2 Date (java.util.Date)2 IFormElement (org.javarosa.core.model.IFormElement)2 ITreeVisitor (org.javarosa.core.model.instance.utils.ITreeVisitor)2 XPathTypeMismatchException (org.javarosa.xpath.XPathTypeMismatchException)2 XPathUnhandledException (org.javarosa.xpath.XPathUnhandledException)2 Cursor (android.database.Cursor)1