Exemplo n.º 1
0
        /*
         * 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));
                }
            }
        }