Changeset 1520
- Timestamp:
- 12/04/08 14:14:54 (5 weeks ago)
- Location:
- branches/dev-repeat/javarosa
- Files:
-
- 2 modified
Legend:
- Unmodified
- Added
- Removed
-
branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/DataModelTree.java
r1519 r1520 57 57 public void setRoot(TreeElement topLevel) { 58 58 root = new QuestionDataGroup(null, 0); 59 ((QuestionDataGroup)root).addChild(topLevel); 59 if (topLevel != null) 60 ((QuestionDataGroup)root).addChild(topLevel); 60 61 } 61 62 … … 64 65 */ 65 66 public TreeElement getRoot() { 66 return root == null ? null : (TreeElement)((QuestionDataGroup)root).getChildren().elementAt(0); 67 if (root == null) 68 return null; 69 else if (((QuestionDataGroup)root).children.size() == 0) 70 return null; 71 else 72 return (TreeElement)((QuestionDataGroup)root).getChildren().elementAt(0); 67 73 } 68 74 … … 75 81 public static TreeReference unpackReference (IDataReference ref) { 76 82 return (TreeReference)ref.getReference(); 77 } 78 79 //IS THIS FUNCTION NEEDED? 80 //create the specified node in the tree, creating all intermediary nodes 81 //terminal = true: create element, false: create group (albeit empty) 82 //at each step, if multiplicity = 83 // ALL or count: always create a new node at the step 84 // [0,count): use that specific node 85 //return a reference that unambiguously refers to the newly created node 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 // } 123 //think this works 83 } 124 84 125 85 public boolean deleteNode (IDataReference ref) { … … 161 121 } 162 122 } 163 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 178 //return a vector of TreeReferences that refer to all nodes in the instance (one ref per node) that match 179 //the passed-in TreeReference, accounting for all repeats. 180 //the returned refs will each unambiguously refer to a single node (i.e., no multiplicities will be 'ALL') 123 124 //take a ref that unambiguously refers to a single node and return that node 125 //return null if ref is ambiguous, node does not exist, ref is relative, or ref is '/' 126 //can be used to retrieve template nodes 127 public TreeElement resolveReference (TreeReference ref) { 128 if (!ref.isAbsolute()) 129 return null; 130 131 TreeElement node = root; 132 for (int i = 0; i < ref.size(); i++) { 133 if (!(node instanceof QuestionDataGroup)) { 134 node = null; 135 break; 136 } 137 QuestionDataGroup group = (QuestionDataGroup)node; 138 139 String name = (String)ref.names.elementAt(i); 140 int mult = ((Integer)ref.multiplicity.elementAt(i)).intValue(); 141 if (mult == TreeReference.INDEX_UNBOUND) { 142 if (group.children.size() == 1) { 143 mult = 0; 144 } else { 145 //reference is not unambiguous 146 node = null; 147 break; 148 } 149 } 150 151 node = group.getChild(name, mult); 152 if (node == null) 153 break; 154 } 155 return (node == root ? null : node); //never return a reference to '/' 156 } 157 158 //same as resolveReference but return a vector containing all interstitial nodes: top-level instance data node first, and target node last 159 //returns null in all the same situations as resolveReference EXCEPT ref '/' will return empty vector 160 public Vector explodeReference (TreeReference ref) { 161 if (!ref.isAbsolute()) 162 return null; 163 164 Vector nodes = new Vector(); 165 TreeElement cur = root; 166 for (int i = 0; i < ref.size(); i++) { 167 if (!(cur instanceof QuestionDataGroup)) { 168 return null; 169 } 170 QuestionDataGroup group = (QuestionDataGroup)cur; 171 172 String name = (String)ref.names.elementAt(i); 173 int mult = ((Integer)ref.multiplicity.elementAt(i)).intValue(); 174 if (mult == TreeReference.INDEX_UNBOUND) { 175 if (group.children.size() == 1) { 176 mult = 0; 177 } else { 178 //reference is not unambiguous 179 return null; 180 } 181 } 182 183 if (cur != root) { 184 nodes.addElement(cur); 185 } 186 187 cur = group.getChild(name, mult); 188 if (cur == null) { 189 return null; 190 } 191 } 192 return nodes; 193 } 194 195 //take in a potentially-ambiguous ref, and return a vector of refs for all nodes that match the passed-in ref 196 //meaning, search out all repeated nodes that match the pattern of the passed-in ref 197 //every ref in the returned vector will be unambiguous (no index will ever be INDEX_UNBOUND) 198 //does not return template nodes when matching INDEX_UNBOUND, but will match templates when INDEX_TEMPLATE is explicitly set 199 //return null if ref is relative, otherwise return vector of refs (but vector will be empty is no refs match) 200 //'/' returns {'/'} 201 //can handle sub-repetitions (e.g., {/a[1]/b[1], /a[1]/b[2], /a[2]/b[1]}) 181 202 public Vector expandReference (TreeReference ref) { 182 203 if (!ref.isAbsolute()) … … 188 209 } 189 210 190 // helper function for expandReference(ref)211 //recursive helper function for expandReference 191 212 //sourceRef: original path we're matching against 192 213 //node: current node that has matched the sourceRef thus far … … 231 252 } 232 253 233 public TreeElement resolveReference (TreeReference ref) { 234 if (!ref.isAbsolute()) 235 return null; 236 237 TreeElement node = root; 238 for (int i = 0; i < ref.size(); i++) { 239 if (!(node instanceof QuestionDataGroup)) { 240 node = null; 241 break; 242 } 243 QuestionDataGroup group = (QuestionDataGroup)node; 244 245 String name = (String)ref.names.elementAt(i); 246 int mult = ((Integer)ref.multiplicity.elementAt(i)).intValue(); 247 if (mult == TreeReference.INDEX_UNBOUND) { 248 if (group.children.size() == 1) { 249 mult = 0; 250 } else { 251 //reference is not unambiguous 252 node = null; 253 break; 254 } 255 } 256 257 node = group.getChild(name, mult); 258 if (node == null) 259 break; 260 } 261 return (node == root ? null : node); //never return a reference to '/' 254 //THIS WILL NOT WORK 255 //retrieve the template node corresponding to a given repeated node, if one exists 256 public TreeElement getTemplate (TreeReference ref) { 257 TreeReference tref = ref.clone(); 258 for (int i = 0; i < tref.size(); i++) { 259 tref.multiplicity.setElementAt(new Integer(0), i); 260 } 261 262 Vector nodes = explodeReference(ref); 263 if (nodes == null) 264 return null; 265 266 for (int i = 0; i < nodes.size(); i++) { 267 TreeElement node = (TreeElement)nodes.elementAt(i); 268 if (node.repeatable) 269 tref.multiplicity.setElementAt(new Integer(TreeReference.INDEX_TEMPLATE), i); 270 } 271 return resolveReference(tref); 262 272 } 263 273 … … 271 281 public TreeElement resolveReference(IDataReference binding) { 272 282 return resolveReference(unpackReference(binding)); 273 }274 275 //same as resolve reference but returns a vector containing all interstitial nodes276 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 unambiguous295 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 283 } 311 284 … … 414 387 } 415 388 } 389 390 391 //IS THIS FUNCTION NEEDED? 392 //create the specified node in the tree, creating all intermediary nodes 393 //terminal = true: create element, false: create group (albeit empty) 394 //at each step, if multiplicity = 395 // ALL or count: always create a new node at the step 396 // [0,count): use that specific node 397 //return a reference that unambiguously refers to the newly created node 398 //public TreeReference createNode (IDataReference ref, boolean terminal) { 399 // QuestionDataGroup node = (QuestionDataGroup)root; 400 // TreeReference tref = unpackReference(ref); 401 // 402 // for (int k = 0; k < tref.size(); k++) { 403 // String name = (String)tref.names.elementAt(k); 404 // int count = node.getMultiplicity(name); 405 // int mult = ((Integer)tref.multiplicity.elementAt(k)).intValue(); 406 // 407 // TreeElement child; 408 // if (mult < count) { 409 // //fetch existing 410 // child = node.getChild(name, mult); 411 // if (child == null) 412 // return null; //something wrong 413 // } else if (mult == TreeReference.INDEX_UNBOUND || mult == count) { 414 // //create new 415 // if (k == tref.size() - 1 && terminal) { 416 // child = new QuestionDataElement(name, count, null); 417 // } else { 418 // child = new QuestionDataGroup(name, count); 419 // } 420 // node.addChild(child); 421 // tref.multiplicity.setElementAt(new Integer(count), k); 422 // } else { 423 // return null; 424 // } 425 // 426 // if (k < tref.size() - 1) { 427 // if (child instanceof QuestionDataElement) { 428 // throw new IllegalArgumentException(); 429 // } 430 // 431 // node = (QuestionDataGroup)child; 432 // } 433 // } 434 //} 435 //think this works -
branches/dev-repeat/javarosa/org.javarosa.xform/src/org/javarosa/xform/parse/XFormParser.java
r1519 r1520 247 247 248 248 private static void parseTitle (FormDef f, Element e) { 249 //Removed a line here about the form title not being null. Couldn't possibly think250 //of why that would make sense. CTS - 7/21/2008251 249 f.setName(getXMLText(e, true)); 252 250 } … … 835 833 //evaluate binds and apply properties 836 834 //load data based on data type 837 835 //verify bindings (also detect bindings too high; repeats too high already checked) 836 838 837 //parse instance hierarchy and turn into a skeleton model; ignoring data content, but respecting repeated nodes and 'template' flags 839 838 private static TreeElement buildInstanceStructure (Element node, QuestionDataGroup parent) { … … 906 905 } 907 906 907 //pre-process and clean up instance regarding repeats; in particular: 908 // 1) catalog which repeat template nodes are explicitly defined, and note which repeats bindings lack templates 909 // 2) remove template nodes that are not valid for a repeat binding 910 // 3) catch repeat bindings that are too high ('/' or '/data') 911 // #4) generate template nodes for repeat bindings that do not have one defined explicitly 912 // 5) give a stern warning for any repeated instance nodes that do not correspond to a repeat binding 913 // #6) verify that all sets of repeated nodes are homogeneous 914 // 7) flag all repeat-related nodes as repeatable 908 915 private static void processRepeats (DataModelTree instance) { 909 Vector missingTemplates = new Vector();910 911 //flag all nodes identified by 'repeat' refs as repeatable916 processTemplates(instance); 917 918 //flag all nodes identified by repeat bindings as repeatable (template nodes already taken care of) 912 919 for (int i = 0; i < repeats.size(); i++) { 913 920 TreeReference ref = (TreeReference)repeats.elementAt(i); … … 920 927 } 921 928 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); 929 checkDuplicateNodesAreRepeatable(instance.getRoot()); 930 931 //check repeat sets for homogeneity 932 } 933 934 private static void processTemplates (DataModelTree instance) { 935 DataModelTree repeatTree = buildRepeatTree(repeats, instance.getRoot().getName()); 936 937 Vector missingTemplates = new Vector(); //Vector<TreeReference> 938 checkRepeatsForTemplate(instance, repeatTree, missingTemplates); 939 940 removeInvalidTemplates(instance, repeatTree); 941 942 943 //if repeatables have no template node, duplicate first as template 944 945 } 946 947 //build a pseudo-data model tree that describes the repeat structure of the instance 948 //result is a DataModelTree collapsed where all indexes are 0, and repeatable nodes are flagged as such 949 //return null if no repeats 950 //raises exception for repeats bound too highly 951 //ignores (invalid) repeats that bind outside the top-level instance data node 952 private static DataModelTree buildRepeatTree (Vector repeatRefs, String topLevelName) { 953 QuestionDataGroup root = new QuestionDataGroup(null, 0); 954 955 for (int i = 0; i < repeatRefs.size(); i++) { 956 TreeReference repeatRef = (TreeReference)repeatRefs.elementAt(i); 957 if (repeatRef.size() <= 1) { 958 throw new XFormParseException("Cannot repeat root instance node or top-level instance data node"); 959 } 960 961 QuestionDataGroup cur = root; 962 for (int j = 0; j < repeatRef.size(); j++) { 963 String name = (String)repeatRef.names.elementAt(j); 964 QuestionDataGroup child = (QuestionDataGroup)cur.getChild(name, 0); 965 if (child == null) { 966 child = new QuestionDataGroup(name, 0); 967 cur.addChild(child); 968 } 969 970 cur = child; 971 if (j == repeatRef.size() - 1) { 972 cur.repeatable = true; 973 } 974 } 975 } 976 977 if (root.getChildren().size() == 0) 978 return null; 979 else 980 return new DataModelTree(root.getChild(topLevelName, 0)); 981 } 982 983 //checks which repeat bindings have explicit template nodes; returns a vector of the bindings that do not 984 //for those that exist, flag them as repeatable 985 private static void checkRepeatsForTemplate (DataModelTree instance, DataModelTree instanceTree, Vector missingTemplates) { 986 checkRepeatsForTemplate((QuestionDataGroup)instanceTree.getRoot(), TreeReference.rootRef(), instance, missingTemplates); 987 } 988 989 //helper function for checkRepeatsForTemplate 990 private static void checkRepeatsForTemplate (QuestionDataGroup repeatTreeNode, TreeReference ref, DataModelTree instance, Vector missing) { 991 String name = repeatTreeNode.getName(); 992 int mult = (repeatTreeNode.repeatable ? TreeReference.INDEX_TEMPLATE : 0); 993 ref = ref.clone(); 994 ref.add(name, mult); 995 996 if (repeatTreeNode.repeatable) { 997 TreeElement template = instance.resolveReference(ref); 926 998 if (template == null) { 927 missing Templates.addElement(ref);999 missing.addElement(ref); 928 1000 } else { 929 1001 template.repeatable = true; 930 1002 } 931 1003 } 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 1004 1005 for (int i = 0; i < repeatTreeNode.getChildren().size(); i++) { 1006 checkRepeatsForTemplate((QuestionDataGroup)repeatTreeNode.getChildren().elementAt(i), ref, instance, missing); 1007 } 1008 } 1009 1010 //iterates through instance and removes template nodes that are not valid. a template is invalid if: 1011 // it is declared for a node that is not repeatable 1012 // it is for a repeat that is a child of another repeat and is not located within the parent's template node 1013 private static void removeInvalidTemplates (DataModelTree instance, DataModelTree repeatTree) { 1014 removeInvalidTemplates(instance.getRoot(), (QuestionDataGroup)repeatTree.getRoot(), true); 1015 } 1016 1017 //helper function for removeInvalidTemplates 1018 private static boolean removeInvalidTemplates (TreeElement instanceNode, QuestionDataGroup repeatTreeNode, boolean templateAllowed) { 1019 int mult = instanceNode.getMult(); 1020 boolean repeatable = (repeatTreeNode == null ? false : repeatTreeNode.repeatable); 1021 1022 if (mult == TreeReference.INDEX_TEMPLATE) { 1023 if (!templateAllowed) { 1024 System.out.println("Warning: template nodes for sub-repeats must be located within the template nodes for all ancestor repeats; ignoring template..."); 1025 return true; 1026 } else if (!repeatable) { 1027 System.out.println("Warning: template node found for ref that is not repeatable; ignoring..."); 1028 return true; 1029 } 1030 } 1031 1032 if (repeatable && mult != TreeReference.INDEX_TEMPLATE) 1033 templateAllowed = false; 1034 1035 if (instanceNode instanceof QuestionDataGroup) { 1036 QuestionDataGroup group = (QuestionDataGroup)instanceNode; 1037 for (int i = 0; i < group.getChildren().size(); i++) { 1038 TreeElement child = (TreeElement)group.getChildren().elementAt(i); 1039 QuestionDataGroup rchild = (repeatTreeNode == null ? null : (QuestionDataGroup)repeatTreeNode.getChild(instanceNode.getName(), 0)); 1040 1041 if (removeInvalidTemplates(child, rchild, templateAllowed)) { 1042 group.getChildren().removeElementAt(i); 1043 i--; 1044 } 1045 } 1046 1047 } 1048 return false; 1049 } 1050 1051 private static void checkDuplicateNodesAreRepeatable (TreeElement node) { 1052 int mult = node.getMult(); 1053 if (mult > 0) { //repeated node 1054 if (!node.repeatable) { 1055 System.out.println("Warning: repeated nodes detected that have no repeat binding in the form; DO NOT bind questions to these nodes!"); 1056 //we could do a more comprehensive safety check in the future 1057 } 1058 } 1059 1060 if (node instanceof QuestionDataGroup) { 1061 QuestionDataGroup group = (QuestionDataGroup)node; 1062 for (int i = 0; i < group.getChildren().size(); i++) { 1063 checkDuplicateNodesAreRepeatable((TreeElement)group.getChildren().elementAt(i)); 1064 } 1065 } 938 1066 } 939 1067
