Changeset 1519

Show
Ignore:
Timestamp:
12/03/08 23:23:40 (5 weeks ago)
Author:
droos
Message:

more repeat instance validation and path API stuff

Location:
branches/dev-repeat/javarosa
Files:
6 modified

Legend:

Unmodified
Added
Removed
  • branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/DataModelTree.java

    r1516 r1519  
    2020import org.javarosa.core.util.externalizable.ExtWrapTagged; 
    2121import org.javarosa.core.util.externalizable.PrototypeFactory; 
    22 import org.javarosa.model.xform.XPathReference; 
    23  
    24 /** 
    25  * DataModelTree is an implementation of IFormDataModel 
    26  * that contains a Data Model which stores Question Answers 
    27  * in an XML-style hierarchical tree, with no repeated 
    28  * tree elements. 
    29  *   
    30  * @author Clayton Sims 
    31  * 
    32  */ 
     22 
    3323public class DataModelTree implements IFormDataModel, IDRecordable { 
    3424 
    3525        /** The root of this tree */ 
    3626        private TreeElement root; 
     27        //represents '/'; always has one and only one child -- the top-level instance data node 
     28        //this node is never returned or manipulated directly 
    3729         
    3830        /** The name for this data model */ 
     
    4335         
    4436        /** The ID of the form that this is a model for */ 
    45         private int formIdReference; 
     37        private int formId; 
    4638         
    4739        /** The date that this model was taken and recorded */ 
    4840        private Date dateSaved; 
    4941         
    50         public DataModelTree() {  
    51         } 
     42        public DataModelTree() { } 
    5243         
    5344        /** 
     
    5748         */ 
    5849        public DataModelTree(TreeElement root) { 
    59                 this.root = root; 
     50                setRoot(root); 
    6051        } 
    6152         
     
    6455         * @param root The root of the tree for this data model. 
    6556         */ 
    66         public void setRootElement(TreeElement root) { 
    67                 this.root = root; 
     57        public void setRoot(TreeElement topLevel) { 
     58                root = new QuestionDataGroup(null, 0); 
     59                ((QuestionDataGroup)root).addChild(topLevel); 
    6860        } 
    6961         
     
    7163         * @return This model's root tree element 
    7264         */ 
    73         public TreeElement getRootElement() { 
    74                 return root; 
     65        public TreeElement getRoot() { 
     66                return root == null ? null : (TreeElement)((QuestionDataGroup)root).getChildren().elementAt(0); 
    7567        } 
    7668 
     
    8577        } 
    8678         
     79        //IS THIS FUNCTION NEEDED? 
    8780        //create the specified node in the tree, creating all intermediary nodes 
    8881        //terminal = true: create element, false: create group (albeit empty) 
     
    9184        //  [0,count): use that specific node 
    9285        //return a reference that unambiguously refers to the newly created node 
    93         public TreeReference createNode (IDataReference ref, boolean terminal) { 
    94                 QuestionDataGroup node = (QuestionDataGroup)root; 
    95                 TreeReference tref = unpackReference(ref); 
    96                  
    97                 for (int k = 0; k < tref.size(); k++) { 
    98                         String name = (String)tref.names.elementAt(k); 
    99                         int count = node.getMultiplicity(name); 
    100                         int mult = ((Integer)tref.multiplicity.elementAt(k)).intValue(); 
    101                          
    102                         TreeElement child; 
    103                         if (mult < count) { 
    104                                 //fetch existing 
    105                                 child = node.getChild(name, mult); 
    106                                 if (child == null) 
    107                                         return null; //something wrong 
    108                         } else if (mult == TreeReference.INDEX_UNBOUND || mult == count) { 
    109                                 //create new 
    110                                 if (k == tref.size() - 1 && terminal) { 
    111                                         child = new QuestionDataElement(name, count, null); 
    112                                 } else { 
    113                                         child = new QuestionDataGroup(name, count); 
    114                                 } 
    115                                 node.addChild(child); 
    116                                 tref.multiplicity.setElementAt(new Integer(count), k); 
    117                         } else { 
    118                                 return null; 
    119                         } 
    120                          
    121                         if (k < tref.size() - 1) { 
    122                                 if (child instanceof QuestionDataElement) { 
    123                                         throw new IllegalArgumentException(); 
    124                                 }        
    125  
    126                                 node = (QuestionDataGroup)child; 
    127                         } 
    128                 } 
    129         } 
     86//      public TreeReference createNode (IDataReference ref, boolean terminal) { 
     87//              QuestionDataGroup node = (QuestionDataGroup)root; 
     88//              TreeReference tref = unpackReference(ref); 
     89//               
     90//              for (int k = 0; k < tref.size(); k++) { 
     91//                      String name = (String)tref.names.elementAt(k); 
     92//                      int count = node.getMultiplicity(name); 
     93//                      int mult = ((Integer)tref.multiplicity.elementAt(k)).intValue(); 
     94//                       
     95//                      TreeElement child; 
     96//                      if (mult < count) { 
     97//                              //fetch existing 
     98//                              child = node.getChild(name, mult); 
     99//                              if (child == null) 
     100//                                      return null; //something wrong 
     101//                      } else if (mult == TreeReference.INDEX_UNBOUND || mult == count) { 
     102//                              //create new 
     103//                              if (k == tref.size() - 1 && terminal) { 
     104//                                      child = new QuestionDataElement(name, count, null); 
     105//                              } else { 
     106//                                      child = new QuestionDataGroup(name, count); 
     107//                              } 
     108//                              node.addChild(child); 
     109//                              tref.multiplicity.setElementAt(new Integer(count), k); 
     110//                      } else { 
     111//                              return null; 
     112//                      } 
     113//                       
     114//                      if (k < tref.size() - 1) { 
     115//                              if (child instanceof QuestionDataElement) { 
     116//                                      throw new IllegalArgumentException(); 
     117//                              }        
     118// 
     119//                              node = (QuestionDataGroup)child; 
     120//                      } 
     121//              } 
     122//      } 
    130123        //think this works 
    131124         
     
    169162        } 
    170163         
     164        public TreeElement getTemplate (TreeReference ref) { 
     165                TreeReference tref = ref.clone(); //need to set all indexes to 0 first? 
     166                Vector nodes = explodeReference(ref); 
     167                if (nodes == null) 
     168                        return null; 
     169                 
     170                for (int i = 0; i < nodes.size(); i++) { 
     171                        TreeElement node = (TreeElement)nodes.elementAt(i); 
     172                        if (node.repeatable) 
     173                                tref.multiplicity.setElementAt(new Integer(TreeReference.INDEX_TEMPLATE), i); 
     174                } 
     175                return resolveReference(tref); 
     176        } 
     177         
    171178        //return a vector of TreeReferences that refer to all nodes in the instance (one ref per node) that match 
    172179        //the passed-in TreeReference, accounting for all repeats. 
    173180        //the returned refs will each unambiguously refer to a single node (i.e., no multiplicities will be 'ALL') 
    174181        public Vector expandReference (TreeReference ref) { 
    175                 if (!ref.absolute) 
     182                if (!ref.isAbsolute()) 
    176183                        return null; 
    177184                 
     
    197204 
    198205                        Vector children = new Vector(); 
    199                         if (mult == TreeReference.INDEX_ALL) { 
     206                        if (mult == TreeReference.INDEX_UNBOUND) { 
    200207                                int count = group.getMultiplicity(name); 
    201208                                for (int i = 0; i < count; i++) { 
     
    225232         
    226233        public TreeElement resolveReference (TreeReference ref) { 
    227                 if (!ref.absolute) 
     234                if (!ref.isAbsolute()) 
    228235                        return null; 
    229236                 
     
    238245                        String name = (String)ref.names.elementAt(i); 
    239246                        int mult = ((Integer)ref.multiplicity.elementAt(i)).intValue(); 
    240                         if (mult == TreeReference.INDEX_ALL) { 
     247                        if (mult == TreeReference.INDEX_UNBOUND) { 
    241248                                if (group.children.size() == 1) { 
    242249                                        mult = 0; 
     
    252259                                break; 
    253260                } 
    254                 return node; 
     261                return (node == root ? null : node); //never return a reference to '/' 
    255262        } 
    256263         
     
    266273        } 
    267274         
     275        //same as resolve reference but returns a vector containing all interstitial nodes 
     276        public Vector explodeReference (TreeReference ref) { 
     277                if (!ref.isAbsolute()) 
     278                        return null; 
     279                 
     280                Vector nodes = new Vector(); 
     281                TreeElement cur = root; 
     282                for (int i = 0; i < ref.size(); i++) { 
     283                        if (!(cur instanceof QuestionDataGroup)) { 
     284                                return null; 
     285                        } 
     286                        QuestionDataGroup group = (QuestionDataGroup)cur; 
     287                         
     288                        String name = (String)ref.names.elementAt(i); 
     289                        int mult = ((Integer)ref.multiplicity.elementAt(i)).intValue(); 
     290                        if (mult == TreeReference.INDEX_UNBOUND) { 
     291                                if (group.children.size() == 1) { 
     292                                        mult = 0; 
     293                                } else { 
     294                                        //reference is not unambiguous 
     295                                        return null; 
     296                                } 
     297                        } 
     298                         
     299                        if (cur != root) { 
     300                                nodes.addElement(cur); 
     301                        } 
     302                         
     303                        cur = group.getChild(name, mult); 
     304                        if (cur == null) { 
     305                                return null; 
     306                        } 
     307                } 
     308                return nodes; 
     309                 
     310        } 
     311         
    268312        /** 
    269313         * Identifies whether the tree for this DataModel contains the given element. 
     
    289333        } 
    290334         
    291         public void setFormReferenceId(int formIdReference) { 
    292                 this.formIdReference = formIdReference; 
     335        public void setFormId(int formId) { 
     336                this.formId = formId; 
    293337        } 
    294338         
     
    303347         * @see org.javarosa.core.model.IFormDataModel#getFormReferenceId() 
    304348         */ 
    305         public int getFormReferenceId() { 
    306                 return this.formIdReference; 
     349        public int getFormId() { 
     350                return this.formId; 
    307351        } 
    308352 
  • branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/QuestionDataElement.java

    r1518 r1519  
    3030 */ 
    3131public class QuestionDataElement extends TreeElement { 
    32  
     32        boolean isAttribute = false; 
     33         
    3334        /** The actual question data value */ 
    3435        private IAnswerData value; 
  • branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/QuestionDataGroup.java

    r1518 r1519  
    7979                for (int i = 0; i < children.size(); i++) { 
    8080                        TreeElement child = (TreeElement)children.elementAt(i); 
    81                         if (child.getName().equals(name)) 
     81                        if (child.getName().equals(name) && child.getMult() != TreeReference.INDEX_TEMPLATE) 
    8282                                count++; 
    8383                } 
  • branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/TreeElement.java

    r1516 r1519  
    3131    protected Vector attributes; 
    3232 
     33    public boolean repeatable = false; 
     34     
    3335        /** 
    3436         * @return True if the element can contain subelements. False otherwise 
  • branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/TreeReference.java

    r1518 r1519  
    4343                names.addElement(name); 
    4444                multiplicity.addElement(new Integer(index)); 
     45        } 
     46         
     47        public boolean isAbsolute () { 
     48                return refLevel == REF_ABSOLUTE; 
    4549        } 
    4650         
  • branches/dev-repeat/javarosa/org.javarosa.xform/src/org/javarosa/xform/parse/XFormParser.java

    r1518 r1519  
    818818        //e is the top-level _data_ node of the instance (immediate (and only) child of <instance>) 
    819819        private static void parseInstance (FormDef f, Element e) { 
    820                 TreeElement root = buildInstanceStructure(e, null, TreeReference.rootRef()); 
     820                TreeElement root = buildInstanceStructure(e, null); 
     821                DataModelTree instanceModel = new DataModelTree(root); 
     822                instanceModel.setName(f.getName()); 
     823                 
     824                processRepeats(instanceModel); 
    821825                applyInstanceProperties(root); 
    822826                loadInstanceData(e, root); 
    823827                 
    824828                //TreeElement root = parseInstanceNodes(e, TreeReference.rootRef()).getRoot(); 
    825                 DataModelTree instanceModel = new DataModelTree(root); 
    826                 instanceModel.setName(f.getName()); 
     829 
    827830                f.setDataModel(instanceModel); 
    828831        } 
    829832 
    830833        //create node structure 
     834        //flag repeats and process templating 
    831835        //evaluate binds and apply properties 
    832836        //load data based on data type 
    833837 
    834         private static TreeElement buildInstanceStructure (Element node, QuestionDataGroup parent, TreeReference ref) { 
     838        //parse instance hierarchy and turn into a skeleton model; ignoring data content, but respecting repeated nodes and 'template' flags 
     839        private static TreeElement buildInstanceStructure (Element node, QuestionDataGroup parent) { 
    835840                TreeElement element = null; 
    836841                boolean isGroup; 
     
    839844                boolean hasElements = false; 
    840845                 
     846                //examine children 
    841847                int numChildren = node.getChildCount();          
    842848                for (int i = 0; i < numChildren; i++) { 
     
    847853                } 
    848854                 
     855                //determine whether node is leaf or group 
    849856                if (hasElements) { 
    850857                        isGroup = true; 
     
    856863                } 
    857864 
     865                //check for repeat templating 
    858866                String name = node.getName(); 
    859                 int multiplicity = (parent == null ? 0 : parent.getMultiplicity(name)); 
    860                  
     867                int multiplicity; 
     868                if (node.getAttributeValue(NAMESPACE_JAVAROSA, "template") != null) { 
     869                        multiplicity = TreeReference.INDEX_TEMPLATE; 
     870                        if (parent != null && parent.getChild(name, TreeReference.INDEX_TEMPLATE) != null) { 
     871                                throw new XFormParseException("More than one node declared as the template for the same repeated set"); 
     872                        } 
     873                } else { 
     874                        multiplicity = (parent == null ? 0 : parent.getMultiplicity(name)); 
     875                } 
     876                         
     877                //create node; handle children 
    861878                if (isGroup) { 
    862879                        element = new QuestionDataGroup(name, multiplicity); 
     
    874891                if (node.getAttributeCount() > 0) { 
    875892                        for (int i = 0; i < node.getAttributeCount(); i++) { 
    876                                 element.setAttribute(node.getAttributeNamespace(i), node.getAttributeName(i), node.getAttributeValue(i)); 
     893                                String attrNamespace = node.getAttributeNamespace(i); 
     894                                String attrName = node.getAttributeName(i); 
     895                                if (attrNamespace.equals(NAMESPACE_JAVAROSA) && attrName.equals("template")) 
     896                                        continue; 
     897                                 
     898                                element.setAttribute(attrNamespace, attrName, node.getAttributeValue(i)); 
    877899                                //#if debug.output==verbose 
    878900                                System.out.println(element.getName()+ " has added attr: "+element.getAttributeName(i)+"="+element.getAttributeValue(i)); 
     
    882904                 
    883905                return element; 
     906        } 
     907         
     908        private static void processRepeats (DataModelTree instance) { 
     909                Vector missingTemplates = new Vector(); 
     910                 
     911                //flag all nodes identified by 'repeat' refs as repeatable 
     912                for (int i = 0; i < repeats.size(); i++) { 
     913                        TreeReference ref = (TreeReference)repeats.elementAt(i); 
     914                        Vector nodes = instance.expandReference(ref); 
     915                        for (int j = 0; j < nodes.size(); j++) { 
     916                                TreeReference nref = (TreeReference)nodes.elementAt(j); 
     917                                TreeElement node = instance.resolveReference(nref); 
     918                                node.repeatable = true; 
     919                        } 
     920                } 
     921                 
     922                //locate all valid template nodes and flag them as repeatable as well 
     923                for (int i = 0; i < repeats.size(); i++) { 
     924                        TreeReference ref = (TreeReference)repeats.elementAt(i); 
     925                        TreeElement template = instance.getTemplate(ref); 
     926                        if (template == null) { 
     927                                missingTemplates.addElement(ref); 
     928                        } else { 
     929                                template.repeatable = true; 
     930                        } 
     931                } 
     932                 
     933                //warn of any 'template' nodes that aren't repeatable 
     934                //warn of any delete incorrect sub-templates 
     935                //error for any repeated nodes that aren't repeatable 
     936                //if repeatables have no template node, duplicate first as template 
     937                //check repeat sets for homogeneity 
    884938        } 
    885939