//very similar to parent(), but assumes contextRef refers to a singular, existing node in the model //this means we can do '/a/b/c + ../../d/e/f = /a/d/e/f', which we couldn't do in parent() //return null if context ref is not absolute, or we parent up past the root node //NOTE: this function still works even when contextRef contains INDEX_UNBOUND multiplicites... conditions depend on this behavior, // even though it's slightly icky public TreeReference anchor(TreeReference contextRef) { if (isAbsolute()) { return(this.clone()); } else if (!contextRef.isAbsolute()) { return(null); } else { TreeReference newRef = contextRef.clone(); int contextSize = contextRef.size(); if (refLevel > contextSize) { return(null); //tried to do '/..' } else { for (int i = 0; i < refLevel; i++) { newRef.removeLastLevel(); } for (int i = 0; i < size(); i++) { newRef.add(this.getName(i), this.getMultiplicity(i)); } return(newRef); } } }
/// <summary>Intersect this tree reference with another, returning a new tree reference /// which contains all of the common elements, starting with the root element. /// /// Note that relative references by their nature can't share steps, so intersecting /// any (or by any) relative ref will result in the root ref. Additionally, if the /// two references don't share any steps, the intersection will consist of the root /// reference. /// /// </summary> /// <param name="b">The tree reference to intersect /// </param> /// <returns> The tree reference containing the common basis of this ref and b /// </returns> public virtual TreeReference intersect(TreeReference b) { if (!this.Absolute || !b.Absolute) { return(TreeReference.rootRef()); } if (this.Equals(b)) { return(this); } TreeReference a; //A should always be bigger if one ref is larger than the other if (this.size() < b.size()) { a = b.Clone(); b = this.Clone(); } else { a = this.Clone(); b = b.Clone(); } //Now, trim the refs to the same length. int diff = a.size() - b.size(); for (int i = 0; i < diff; ++i) { a.removeLastLevel(); } int aSize = a.size(); //easy, but requires a lot of re-evaluation. for (int i = 0; i <= aSize; ++i) { if (a.Equals(b)) { return(a); } else if (a.size() == 0) { return(TreeReference.rootRef()); } else { if (!a.removeLastLevel() || !b.removeLastLevel()) { //I don't think it should be possible for us to get here, so flip if we do throw new System.SystemException("Dug too deply into TreeReference during intersection"); } } } //The only way to get here is if a's size is -1 throw new System.SystemException("Impossible state"); }
public TreeReference getParentRef() { //TODO: level TreeReference ref_ = this.clone(); if (ref_.removeLastLevel()) { return(ref_); } else { return(null); } }
//very similar to parent(), but assumes contextRef refers to a singular, existing node in the model //this means we can do '/a/b/c + ../../d/e/f = /a/d/e/f', which we couldn't do in parent() //return null if context ref is not absolute, or we parent up past the root node //NOTE: this function still works even when contextRef contains INDEX_UNBOUND multiplicites... conditions depend on this behavior, // even though it's slightly icky public virtual TreeReference anchor(TreeReference contextRef) { //TODO: Technically we should possibly be modifying context stuff here //instead of in the xpath stuff; if (Absolute) { return(this.Clone()); } else if (!contextRef.Absolute) { throw new XPathException("Could not resolve " + this.toString(true)); } else { TreeReference newRef = contextRef.Clone(); int contextSize = contextRef.size(); if (refLevel > contextSize) { //tried to do '/..' throw new XPathException("Could not resolve " + this.toString(true)); } else { for (int i = 0; i < refLevel; i++) { newRef.removeLastLevel(); } for (int i = 0; i < size(); i++) { newRef.add(data.elementAt(i).shallowCopy()); } return(newRef); } } }