/* * useCurrentInstanceVariable is probably always false in the current version of the algorithm. */ public XPathExpr GetRelativeXPath(PSMComponent node, bool useCurrentInstanceVariable, string currentInstanceVariableName = XDocumentXsltExtensions.ParamCurrentInstance) { PSMComponent closestExistingCurrentNode = CurrentNode.GetFirstAncestorOrSelfExistingInVersion(OldVersion).GetInVersion(OldVersion); PSMComponent closestExistingTargetNode = node.GetFirstAncestorOrSelfExistingInVersion(OldVersion).GetInVersion(OldVersion); if (closestExistingTargetNode == null) { throw new InvalidOperationException(); } if (closestExistingCurrentNode == null) { return(new XPathExpr(closestExistingTargetNode.XPath)); } XPathExpr currentNodeAbsoluteXPath = new XPathExpr(closestExistingCurrentNode.GetInVersion(OldVersion).XPath); // /A/R XPathExpr targetNodeAbsoluteXPath = new XPathExpr(closestExistingTargetNode.GetInVersion(OldVersion).XPath); // /A/R/B/z if (targetNodeAbsoluteXPath.HasPrefix(currentNodeAbsoluteXPath) && targetNodeAbsoluteXPath != currentNodeAbsoluteXPath) { string withoutPrefix = targetNodeAbsoluteXPath.ToString().Substring(currentNodeAbsoluteXPath.ToString().Length); while (withoutPrefix[0].IsAmong('/', '@')) { withoutPrefix = withoutPrefix.Substring(1); } string nextStep; if (withoutPrefix.IndexOf('/') == -1) { nextStep = withoutPrefix.Substring(0, withoutPrefix.Length); } else { nextStep = withoutPrefix.Substring(0, withoutPrefix.IndexOf('/')); } string afterNextStep = withoutPrefix.Substring(nextStep.Length); XPathExpr result; if (useCurrentInstanceVariable) { result = new XPathExpr(string.Format("${3}[name() = '{0}']{1}{2}", nextStep, string.IsNullOrEmpty(afterNextStep) ? string.Empty : "/", afterNextStep, currentInstanceVariableName)); } else { result = new XPathExpr(string.Format("{0}{1}{2}", nextStep, string.IsNullOrEmpty(afterNextStep) ? string.Empty : "/", afterNextStep)); } return(result); } else if (targetNodeAbsoluteXPath == currentNodeAbsoluteXPath) { return(new XPathExpr(".")); } else { // find the uppermost common node PSMAssociationMember nearestCommonAncestor = closestExistingCurrentNode.GetNearestCommonAncestor(closestExistingTargetNode); if (nearestCommonAncestor != null) { string commonPath = nearestCommonAncestor.XPath; Debug.Assert(targetNodeAbsoluteXPath.HasPrefix(new XPathExpr(commonPath))); Debug.Assert(currentNodeAbsoluteXPath.HasPrefix(new XPathExpr(commonPath))); string fromCommonToTarget = targetNodeAbsoluteXPath.ToString().Replace(commonPath, string.Empty); string fromCommonToCurrent = currentNodeAbsoluteXPath.ToString().Replace(commonPath, string.Empty); string stepsUp = string.Empty; foreach (char c in fromCommonToCurrent) { if (c == '/') { stepsUp += "../"; } } if (fromCommonToTarget.StartsWith("/")) { fromCommonToTarget = fromCommonToTarget.Substring(1); } string joined = string.Format("{0}{1}", stepsUp, fromCommonToTarget); if (joined.EndsWith("/")) { joined = joined.Substring(0, joined.Length - 1); } return(new XPathExpr(joined)); } else { return(new XPathExpr(closestExistingTargetNode.XPath)); } } }