You need at least XPath 2.0 to solve it with a single, pure XPath expression: for $current in . return ../Bar[Ref=$current]/Elem.
Microsoft does not have XPath 2.0 support but there are third party XPath 2 implementations that plug into the existing .NET architecture and provide extension methods on e.g. XmlNode (needs using Wmhelp.XPath2; and the NuGet package https://www.nuget.org/packages/XPath2/1.0.2/):
string xml = @"<Root> <Foo> <Bar><Elem>X</Elem><Ref>1</Ref></Bar> <Bar><Elem>Y</Elem><Ref>2</Ref></Bar> <Ref>2</Ref> </Foo> </Root>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); XmlNode refEl = doc.SelectSingleNode("/Root/Foo/Ref"); XmlNode elem = refEl.XPath2SelectSingleNode("for $current in . return ../Bar[Ref=$current]/Elem"); Console.WriteLine(elem.OuterXml);
Or you can do it with XPath 3.0 or later with a single, pure XPath expression using let to bind a variable: let $c := . return ../Bar[Ref=$c]/Elem.
If you want to use that on System.Xml in the .NET framework then you can for instance install and use XmlPrime, it offers extension methods (http://www.xmlprime.com/xmlprime/doc/4.0/using-xpath.htm#extension):
string xml = @"<Root> <Foo> <Bar><Elem>X</Elem><Ref>1</Ref></Bar> <Bar><Elem>Y</Elem><Ref>2</Ref></Bar> <Ref>2</Ref> </Foo> </Root>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); XmlNode refEl = doc.SelectSingleNode("/Root/Foo/Ref"); XmlNode elem = refEl.XPathSelectSingleNode("let $c := . return ../Bar[Ref=$c]/Elem"); Console.WriteLine(elem.OuterXml);
outputs <Elem>Y</Elem>.
If you want to have variable resolution within the .NET framework XPath APIs then the second argument to SelectSingleNode/SelectNodes is an XmlNamespaceManager which is a base class of XsltContext which has a method ResolveVariable https://msdn.microsoft.com/en-us/library/system.xml.xsl.xsltcontext.resolvevariable(v=vs.110).aspx. There is project on Codeplex that implements that XsltContext for variable resolution in the public class DynamicContext : XsltContext so you could use that:
XmlDocument doc = new XmlDocument(); doc.LoadXml(@"<Root> <Foo> <Bar><Elem>X</Elem><Ref>1</Ref></Bar> <Bar><Elem>Y</Elem><Ref>2</Ref></Bar> <Ref>2</Ref> </Foo> </Root>"); XmlNode refEl = doc.SelectSingleNode("Root/Foo/Ref"); DynamicContext context = new DynamicContext(); context.AddVariable("current", refEl); XmlNode elem = refEl.SelectSingleNode("../Bar[Ref = $current]/Elem", context); Console.WriteLine(elem.OuterXml);
See the documentation in https://weblogs.asp.net/cazzu/30888.