// determine if nodes are homogeneous, meaning their descendant structure is 'identical' for repeat purposes // identical means all children match, and the children's children match, and so on // repeatable children are ignored; as they do not have to exist in the same quantity for nodes to be homogeneous // however, the child repeatable nodes MUST be verified amongst themselves for homogeneity later // this function ignores the names of the two nodes public static Boolean isHomogeneous(TreeElement a, TreeElement b) { if (a.isLeaf() && b.isLeaf()) { return(true); } else if (a.isChildable() && b.isChildable()) { // verify that every (non-repeatable) node in a exists in b and vice // versa for (int k = 0; k < 2; k++) { TreeElement n1 = (k == 0 ? a : b); TreeElement n2 = (k == 0 ? b : a); for (int i = 0; i < n1.getNumChildren(); i++) { TreeElement child1 = n1.getChildAt(i); if (child1.repeatable) { continue; } TreeElement child2 = n2.getChild(child1.getName(), 0); if (child2 == null) { return(false); } if (child2.repeatable) { throw new SystemException("shouldn't happen"); } } } // compare children for (int i = 0; i < a.getNumChildren(); i++) { TreeElement childA = a.getChildAt(i); if (childA.repeatable) { continue; } TreeElement childB = b.getChild(childA.getName(), 0); if (!isHomogeneous(childA, childB)) { return(false); } } return(true); } else { return(false); } }
// for making new repeat instances; 'from' and 'to' must be unambiguous // references EXCEPT 'to' may be ambiguous at its final step // return true is successfully copied, false otherwise public TreeElement copyNode(TreeElement src, TreeReference to) { if (!to.isAbsolute()) { throw new InvalidReferenceException("Destination reference must be absolute for copying", to); } // strip out dest node info and get dest parent String dstName = to.getNameLast(); int dstMult = to.getMultLast(); TreeReference toParent = to.getParentRef(); TreeElement parent = resolveReference(toParent); if (parent == null) { throw new InvalidReferenceException("Null parent reference whle attempting to copy", toParent); } if (!parent.isChildable()) { throw new InvalidReferenceException("Invalid Parent Node: cannot accept children.", toParent); } if (dstMult == TreeReference.INDEX_UNBOUND) { dstMult = parent.getChildMultiplicity(dstName); } else if (parent.getChild(dstName, dstMult) != null) { throw new InvalidReferenceException("Destination already exists!", to); } TreeElement dest = src.deepCopy(false); dest.setName(dstName); dest.multiplicity = dstMult; parent.addChild(dest); return(dest); }
/* * create the specified node in the tree, creating all intermediary nodes at * each step, if necessary. if specified node already exists, return null * * creating a duplicate node is only allowed at the final step. it will be * done if the multiplicity of the last step is ALL or equal to the count of * nodes already there * * at intermediate steps, the specified existing node is used; if * multiplicity is ALL: if no nodes exist, a new one is created; if one node * exists, it is used; if multiple nodes exist, it's an error * * return the newly-created node; modify ref so that it's an unambiguous ref * to the node */ private TreeElement createNode(TreeReference ref_) { TreeElement node = root; for (int k = 0; k < ref_.size(); k++) { String name = ref_.getName(k); int count = node.getChildMultiplicity(name); int mult = ref_.getMultiplicity(k); TreeElement child; if (k < ref_.size() - 1) { if (mult == TreeReference.INDEX_UNBOUND) { if (count > 1) { return(null); // don't know which node to use } else { // will use existing (if one and only one) or create new mult = 0; ref_.setMultiplicity(k, 0); } } // fetch child = node.getChild(name, mult); if (child == null) { if (mult == 0) { // create child = new TreeElement(name, count); node.addChild(child); ref_.setMultiplicity(k, count); } else { return(null); // intermediate node does not exist } } } else { if (mult == TreeReference.INDEX_UNBOUND || mult == count) { if (k == 0 && root.getNumChildren() != 0) { return(null); // can only be one top-level node, and it // already exists } if (!node.isChildable()) { return(null); // current node can't have children } // create new child = new TreeElement(name, count); node.addChild(child); ref_.setMultiplicity(k, count); } else { return(null); // final node must be a newly-created node } } node = child; } return(node); }