Search in sources :

Example 56 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class XFormParser method loadXmlInstance.

/**
 * Loads a compatible xml instance into FormDef f
 *
 * call before f.initialize()!
 */
private static void loadXmlInstance(FormDef f, Document xmlInst) {
    TreeElement savedRoot = XFormParser.restoreDataModel(xmlInst, null).getRoot();
    TreeElement templateRoot = f.getMainInstance().getRoot().deepCopy(true);
    // TODO: should check that namespaces match?
    if (!savedRoot.getName().equals(templateRoot.getName()) || savedRoot.getMult() != 0) {
        throw new RuntimeException("Saved form instance does not match template form definition");
    }
    // populate the data model
    TreeReference tr = TreeReference.rootRef();
    tr.add(templateRoot.getName(), TreeReference.INDEX_UNBOUND);
    templateRoot.populate(savedRoot, f);
    // populated model to current form
    f.getMainInstance().setRoot(templateRoot);
// if the new instance is inserted into the formdef before f.initialize() is called, this
// locale refresh is unnecessary
// Localizer loc = f.getLocalizer();
// if (loc != null) {
// f.localeChanged(loc.getLocale(), loc);
// }
}
Also used : TreeReference(org.javarosa.core.model.instance.TreeReference) TreeElement(org.javarosa.core.model.instance.TreeElement) AbstractTreeElement(org.javarosa.core.model.instance.AbstractTreeElement)

Example 57 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class XFormParser method buildInstanceStructure.

/**
 * Parses instance hierarchy and turns into a skeleton model; ignoring data content,
 * but respecting repeated nodes and 'template' flags
 *
 * @param node                   the input node
 * @param parent                 the parent
 * @param instanceName           the name of the instance
 * @param docnamespace
 * @param namespacePrefixesByUri namespace prefixes, by URI
 * @param multiplicityFromGroup  if not null, the multiplicity to use. If present, a potentially
 *                               expensive search can be avoided.
 * @return a new TreeElement
 */
public static TreeElement buildInstanceStructure(Element node, TreeElement parent, String instanceName, String docnamespace, Map<String, String> namespacePrefixesByUri, Integer multiplicityFromGroup) {
    TreeElement element;
    // catch when text content is mixed with children
    int numChildren = node.getChildCount();
    boolean hasText = false;
    boolean hasElements = false;
    for (int i = 0; i < numChildren; i++) {
        switch(node.getType(i)) {
            case Node.ELEMENT:
                hasElements = true;
                break;
            case Node.TEXT:
                if (node.getText(i).trim().length() > 0)
                    hasText = true;
                break;
        }
    }
    if (hasElements && hasText) {
        Std.out.println("Warning: instance node '" + node.getName() + "' contains both elements and text as children; text ignored");
    }
    // check for repeat templating
    final String name = node.getName();
    final int multiplicity;
    if (isTemplate(node)) {
        multiplicity = TreeReference.INDEX_TEMPLATE;
        if (parent != null && parent.getChild(name, TreeReference.INDEX_TEMPLATE) != null) {
            throw new XFormParseException("More than one node declared as the template for the same repeated set [" + name + "]", node);
        }
    } else {
        multiplicity = multiplicityFromGroup != null ? multiplicityFromGroup : (parent == null ? 0 : parent.getChildMultiplicity(name));
    }
    String modelType = node.getAttributeValue(NAMESPACE_JAVAROSA, "modeltype");
    // create node; handle children
    if (modelType == null) {
        element = new TreeElement(name, multiplicity);
        element.setInstanceName(instanceName);
    } else {
        if (typeMappings.get(modelType) == null) {
            throw new XFormParseException("ModelType " + modelType + " is not recognized.", node);
        }
        element = (TreeElement) modelPrototypes.getNewInstance(typeMappings.get(modelType).toString());
        if (element == null) {
            element = new TreeElement(name, multiplicity);
            Std.out.println("No model type prototype available for " + modelType);
        } else {
            element.setName(name);
            element.setMult(multiplicity);
        }
    }
    if (node.getNamespace() != null) {
        if (!node.getNamespace().equals(docnamespace)) {
            element.setNamespace(node.getNamespace());
        }
        if (namespacePrefixesByUri.containsKey(node.getNamespace())) {
            element.setNamespacePrefix(namespacePrefixesByUri.get(node.getNamespace()));
        }
    }
    if (hasElements) {
        Integer newMultiplicityFromGroup = childOptimizationsOk(node) ? 0 : null;
        for (int i = 0; i < numChildren; i++) {
            if (node.getType(i) == Node.ELEMENT) {
                TreeElement newChild = buildInstanceStructure(node.getElement(i), element, instanceName, docnamespace, namespacePrefixesByUri, newMultiplicityFromGroup);
                element.addChild(newChild);
                if (newMultiplicityFromGroup != null) {
                    newMultiplicityFromGroup++;
                }
            }
        }
    }
    // handle attributes
    if (node.getAttributeCount() > 0) {
        for (int i = 0; i < node.getAttributeCount(); i++) {
            String attrNamespace = node.getAttributeNamespace(i);
            String attrName = node.getAttributeName(i);
            if (attrNamespace.equals(NAMESPACE_JAVAROSA) && attrName.equals("template")) {
                continue;
            }
            if (attrNamespace.equals(NAMESPACE_JAVAROSA) && attrName.equals("recordset")) {
                continue;
            }
            element.setAttribute(attrNamespace, attrName, node.getAttributeValue(i));
        }
    }
    return element;
}
Also used : TreeElement(org.javarosa.core.model.instance.TreeElement) AbstractTreeElement(org.javarosa.core.model.instance.AbstractTreeElement)

Example 58 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class FormInstanceParser method checkRepeatsForTemplate.

/**
 * Helper function for checkRepeatsForTemplate
 */
private static void checkRepeatsForTemplate(TreeElement repeatTreeNode, TreeReference ref, FormInstance instance, List<TreeReference> missing) {
    String name = repeatTreeNode.getName();
    int mult = (repeatTreeNode.isRepeatable() ? TreeReference.INDEX_TEMPLATE : 0);
    ref = ref.extendRef(name, mult);
    if (repeatTreeNode.isRepeatable()) {
        TreeElement template = instance.resolveReference(ref);
        if (template == null) {
            missing.add(ref);
        }
    }
    for (int i = 0; i < repeatTreeNode.getNumChildren(); i++) {
        checkRepeatsForTemplate(repeatTreeNode.getChildAt(i), ref, instance, missing);
    }
}
Also used : Constraint(org.javarosa.core.model.condition.Constraint) TreeElement(org.javarosa.core.model.instance.TreeElement)

Example 59 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class FormInstanceParser method removeInvalidTemplates.

// helper function for removeInvalidTemplates
private boolean removeInvalidTemplates(TreeElement instanceNode, TreeElement repeatTreeNode, boolean templateAllowed) {
    int mult = instanceNode.getMult();
    boolean repeatable = repeatTreeNode != null && repeatTreeNode.isRepeatable();
    if (mult == TreeReference.INDEX_TEMPLATE) {
        if (!templateAllowed) {
            reporter.warning(XFormParserReporter.TYPE_INVALID_STRUCTURE, "Template nodes for sub-repeats must be located within the template node of the parent repeat; ignoring template... [" + instanceNode.getName() + "]", null);
            return true;
        } else if (!repeatable) {
            reporter.warning(XFormParserReporter.TYPE_INVALID_STRUCTURE, "Warning: template node found for ref that is not repeatable; ignoring... [" + instanceNode.getName() + "]", null);
            return true;
        }
    }
    if (repeatable && mult != TreeReference.INDEX_TEMPLATE)
        templateAllowed = false;
    for (int i = 0; i < instanceNode.getNumChildren(); i++) {
        TreeElement child = instanceNode.getChildAt(i);
        TreeElement rchild = (repeatTreeNode == null ? null : repeatTreeNode.getChild(child.getName(), 0));
        if (removeInvalidTemplates(child, rchild, templateAllowed)) {
            instanceNode.removeChildAt(i);
            i--;
        }
    }
    return false;
}
Also used : Constraint(org.javarosa.core.model.condition.Constraint) TreeElement(org.javarosa.core.model.instance.TreeElement)

Example 60 with TreeElement

use of org.javarosa.core.model.instance.TreeElement in project javarosa by opendatakit.

the class FormInstanceParser method parseInstance.

FormInstance parseInstance(Element e, boolean isMainInstance, String name, Map<String, String> namespacePrefixesByUri) {
    TreeElement root = buildInstanceStructure(e, null, !isMainInstance ? name : null, e.getNamespace(), namespacePrefixesByUri, null);
    FormInstance instanceModel = new FormInstance(root);
    instanceModel.setName(isMainInstance ? formDef.getTitle() : name);
    final List<String> usedAtts = Collections.unmodifiableList(Arrays.asList("id", "version", "uiVersion", "name"));
    String schema = e.getNamespace();
    if (schema != null && schema.length() > 0 && !schema.equals(defaultNamespace)) {
        instanceModel.schema = schema;
    }
    instanceModel.formVersion = e.getAttributeValue(null, "version");
    instanceModel.uiVersion = e.getAttributeValue(null, "uiVersion");
    XFormParser.loadNamespaces(e, instanceModel);
    if (isMainInstance) {
        // the initialization of the references is done twice.
        // The first time is here because they are needed before these
        // validation steps can be performed.
        // It is then done again during the call to _f.setInstance().
        FormDef.updateItemsetReferences(formDef.getChildren());
        processRepeats(instanceModel);
        verifyBindings(instanceModel, e.getName());
        verifyActions(instanceModel);
    }
    applyInstanceProperties(instanceModel);
    // print unused attribute warning message for parent element
    if (XFormUtils.showUnusedAttributeWarning(e, usedAtts)) {
        reporter.warning(XFormParserReporter.TYPE_UNKNOWN_MARKUP, XFormUtils.unusedAttWarning(e, usedAtts), getVagueLocation(e));
    }
    return instanceModel;
}
Also used : FormInstance(org.javarosa.core.model.instance.FormInstance) TreeElement(org.javarosa.core.model.instance.TreeElement)

Aggregations

TreeElement (org.javarosa.core.model.instance.TreeElement)86 AbstractTreeElement (org.javarosa.core.model.instance.AbstractTreeElement)33 TreeReference (org.javarosa.core.model.instance.TreeReference)28 FormInstance (org.javarosa.core.model.instance.FormInstance)16 ArrayList (java.util.ArrayList)15 Constraint (org.javarosa.core.model.condition.Constraint)11 Test (org.junit.Test)10 Element (org.kxml2.kdom.Element)9 EvaluationContext (org.javarosa.core.model.condition.EvaluationContext)8 FormDef (org.javarosa.core.model.FormDef)7 InstanceInitializationFactory (org.javarosa.core.model.instance.InstanceInitializationFactory)7 IOException (java.io.IOException)6 IFormElement (org.javarosa.core.model.IFormElement)6 StringData (org.javarosa.core.model.data.StringData)6 HashMap (java.util.HashMap)5 IAnswerData (org.javarosa.core.model.data.IAnswerData)4 File (java.io.File)3 GroupDef (org.javarosa.core.model.GroupDef)3 IDataReference (org.javarosa.core.model.IDataReference)3 QuestionDef (org.javarosa.core.model.QuestionDef)3