Changeset 1519
- Timestamp:
- 12/03/08 23:23:40 (5 weeks ago)
- Location:
- branches/dev-repeat/javarosa
- Files:
-
- 6 modified
-
org.javarosa.core.model/src/org/javarosa/core/model/instance/DataModelTree.java (modified) (15 diffs)
-
org.javarosa.core.model/src/org/javarosa/core/model/instance/QuestionDataElement.java (modified) (1 diff)
-
org.javarosa.core.model/src/org/javarosa/core/model/instance/QuestionDataGroup.java (modified) (1 diff)
-
org.javarosa.core.model/src/org/javarosa/core/model/instance/TreeElement.java (modified) (1 diff)
-
org.javarosa.core.model/src/org/javarosa/core/model/instance/TreeReference.java (modified) (1 diff)
-
org.javarosa.xform/src/org/javarosa/xform/parse/XFormParser.java (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/DataModelTree.java
r1516 r1519 20 20 import org.javarosa.core.util.externalizable.ExtWrapTagged; 21 21 import 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 33 23 public class DataModelTree implements IFormDataModel, IDRecordable { 34 24 35 25 /** The root of this tree */ 36 26 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 37 29 38 30 /** The name for this data model */ … … 43 35 44 36 /** The ID of the form that this is a model for */ 45 private int formId Reference;37 private int formId; 46 38 47 39 /** The date that this model was taken and recorded */ 48 40 private Date dateSaved; 49 41 50 public DataModelTree() { 51 } 42 public DataModelTree() { } 52 43 53 44 /** … … 57 48 */ 58 49 public DataModelTree(TreeElement root) { 59 this.root = root;50 setRoot(root); 60 51 } 61 52 … … 64 55 * @param root The root of the tree for this data model. 65 56 */ 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); 68 60 } 69 61 … … 71 63 * @return This model's root tree element 72 64 */ 73 public TreeElement getRoot Element() {74 return root ;65 public TreeElement getRoot() { 66 return root == null ? null : (TreeElement)((QuestionDataGroup)root).getChildren().elementAt(0); 75 67 } 76 68 … … 85 77 } 86 78 79 //IS THIS FUNCTION NEEDED? 87 80 //create the specified node in the tree, creating all intermediary nodes 88 81 //terminal = true: create element, false: create group (albeit empty) … … 91 84 // [0,count): use that specific node 92 85 //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 existing105 child = node.getChild(name, mult);106 if (child == null)107 return null; //something wrong108 } else if (mult == TreeReference.INDEX_UNBOUND || mult == count) {109 //create new110 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 // } 130 123 //think this works 131 124 … … 169 162 } 170 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 171 178 //return a vector of TreeReferences that refer to all nodes in the instance (one ref per node) that match 172 179 //the passed-in TreeReference, accounting for all repeats. 173 180 //the returned refs will each unambiguously refer to a single node (i.e., no multiplicities will be 'ALL') 174 181 public Vector expandReference (TreeReference ref) { 175 if (!ref. absolute)182 if (!ref.isAbsolute()) 176 183 return null; 177 184 … … 197 204 198 205 Vector children = new Vector(); 199 if (mult == TreeReference.INDEX_ ALL) {206 if (mult == TreeReference.INDEX_UNBOUND) { 200 207 int count = group.getMultiplicity(name); 201 208 for (int i = 0; i < count; i++) { … … 225 232 226 233 public TreeElement resolveReference (TreeReference ref) { 227 if (!ref. absolute)234 if (!ref.isAbsolute()) 228 235 return null; 229 236 … … 238 245 String name = (String)ref.names.elementAt(i); 239 246 int mult = ((Integer)ref.multiplicity.elementAt(i)).intValue(); 240 if (mult == TreeReference.INDEX_ ALL) {247 if (mult == TreeReference.INDEX_UNBOUND) { 241 248 if (group.children.size() == 1) { 242 249 mult = 0; … … 252 259 break; 253 260 } 254 return node;261 return (node == root ? null : node); //never return a reference to '/' 255 262 } 256 263 … … 266 273 } 267 274 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 268 312 /** 269 313 * Identifies whether the tree for this DataModel contains the given element. … … 289 333 } 290 334 291 public void setForm ReferenceId(int formIdReference) {292 this.formId Reference = formIdReference;335 public void setFormId(int formId) { 336 this.formId = formId; 293 337 } 294 338 … … 303 347 * @see org.javarosa.core.model.IFormDataModel#getFormReferenceId() 304 348 */ 305 public int getForm ReferenceId() {306 return this.formId Reference;349 public int getFormId() { 350 return this.formId; 307 351 } 308 352 -
branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/QuestionDataElement.java
r1518 r1519 30 30 */ 31 31 public class QuestionDataElement extends TreeElement { 32 32 boolean isAttribute = false; 33 33 34 /** The actual question data value */ 34 35 private IAnswerData value; -
branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/QuestionDataGroup.java
r1518 r1519 79 79 for (int i = 0; i < children.size(); i++) { 80 80 TreeElement child = (TreeElement)children.elementAt(i); 81 if (child.getName().equals(name) )81 if (child.getName().equals(name) && child.getMult() != TreeReference.INDEX_TEMPLATE) 82 82 count++; 83 83 } -
branches/dev-repeat/javarosa/org.javarosa.core.model/src/org/javarosa/core/model/instance/TreeElement.java
r1516 r1519 31 31 protected Vector attributes; 32 32 33 public boolean repeatable = false; 34 33 35 /** 34 36 * @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 43 43 names.addElement(name); 44 44 multiplicity.addElement(new Integer(index)); 45 } 46 47 public boolean isAbsolute () { 48 return refLevel == REF_ABSOLUTE; 45 49 } 46 50 -
branches/dev-repeat/javarosa/org.javarosa.xform/src/org/javarosa/xform/parse/XFormParser.java
r1518 r1519 818 818 //e is the top-level _data_ node of the instance (immediate (and only) child of <instance>) 819 819 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); 821 825 applyInstanceProperties(root); 822 826 loadInstanceData(e, root); 823 827 824 828 //TreeElement root = parseInstanceNodes(e, TreeReference.rootRef()).getRoot(); 825 DataModelTree instanceModel = new DataModelTree(root); 826 instanceModel.setName(f.getName()); 829 827 830 f.setDataModel(instanceModel); 828 831 } 829 832 830 833 //create node structure 834 //flag repeats and process templating 831 835 //evaluate binds and apply properties 832 836 //load data based on data type 833 837 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) { 835 840 TreeElement element = null; 836 841 boolean isGroup; … … 839 844 boolean hasElements = false; 840 845 846 //examine children 841 847 int numChildren = node.getChildCount(); 842 848 for (int i = 0; i < numChildren; i++) { … … 847 853 } 848 854 855 //determine whether node is leaf or group 849 856 if (hasElements) { 850 857 isGroup = true; … … 856 863 } 857 864 865 //check for repeat templating 858 866 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 861 878 if (isGroup) { 862 879 element = new QuestionDataGroup(name, multiplicity); … … 874 891 if (node.getAttributeCount() > 0) { 875 892 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)); 877 899 //#if debug.output==verbose 878 900 System.out.println(element.getName()+ " has added attr: "+element.getAttributeName(i)+"="+element.getAttributeValue(i)); … … 882 904 883 905 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 884 938 } 885 939
