.NET XPath 从特定元素开始并反向引用它 [英] .NET XPath starting from a specific element and backreferencing to it
问题描述
我有(实际上将有)一个应用程序,我需要在其中使用 XPath 查找特定的 xml 元素(称为元素 A),然后找到元素 A 引用的另一个元素(元素 B).示例:
I have (actually going to have) an app where I need to find a specific xml element (call it element A) using XPath and then find another element (element B) referenced by eleement A. Example:
public static void Main(string[] args)
{
var s = @"
<Root>
<Start refId = ""5""/>
<Start refId = ""6""/>
<Item id = ""5""/>
<Item id = ""6""/>
</Root>
";
var doc = new XmlDocument();
using (var sr = new StringReader(s))
{
doc.Load(sr);
}
XmlNode nodeA = doc.SelectNodes(@"Root/Start[1]")[0];
var selected = nodeA.SelectNodes(@"/Root/Item[@id = @refId]");
}
这里的 nodeA 是我能找到的节点 A.selected 是我找不到的节点 B 的集合.我的问题是在 [@id = @refId] 中,我想返回到我开始的 nodeA 并获取其属性refId"的值,但我找不到方法.这有可能实现吗?
Here nodeA is the node A that I can find. selected is a collection of nodes B that I can't find. My problem is in [@id = @refId] where I want to return to nodeA that I start from and get the value of its attribute "refId", but I can't find a way how. Is this possible to achieve?
推荐答案
我认为完成您在下面评论中描述的内容的唯一方法是使用 LINQ to XML、XPath 变量、或定义您自己的 current()
函数.XPath 变量和当前函数有点麻烦,因为它们需要编写您自己的类来处理它们,但是您可以使用这些相对简单的通用类:
The only way I can see accomplishing what you describe below in the comments is to use LINQ to XML, XPath variables, or define your own current()
function. XPath variables and current functions are a bit of a pain because they require writing your own classes to handle them, but you can use these relatively simple generic classes:
public class VariableContext : XsltContext
{
IXPathNavigable CurrentNode;
Dictionary<string, object> Values = new Dictionary<string, object>();
public void SetValue(string name, object value)
{
Values[name] = value;
}
public void SetCurrentNode(IXPathNavigable currentNode)
{
CurrentNode = currentNode;
}
public override int CompareDocument(string baseUri, string nextbaseUri)
{
throw new NotImplementedException();
}
public override bool PreserveWhitespace(System.Xml.XPath.XPathNavigator node)
{
return false;
}
public override IXsltContextFunction ResolveFunction(string prefix, string name, System.Xml.XPath.XPathResultType[] ArgTypes)
{
if (name.Equals("current"))
{
return new CurrentFunction(CurrentNode);
}
throw new NotImplementedException();
}
public override IXsltContextVariable ResolveVariable(string prefix, string name)
{
object value;
if (Values.TryGetValue(name, out value))
{
return new ContextVariable(name, value);
}
throw new ApplicationException("Unknown variable: " + name);
}
public override bool Whitespace
{
get { return false; }
}
}
public class ContextVariable : IXsltContextVariable
{
private string m_name;
private object m_parameter;
public ContextVariable(string name, object parameter)
{
m_name = name;
m_parameter = parameter;
IXPathNavigable navigable = m_parameter as IXPathNavigable;
if (navigable != null)
{
m_parameter = navigable.CreateNavigator().Select(".");
}
}
#region IXsltContextVariable Members
public object Evaluate(XsltContext xsltContext)
{
return m_parameter;
}
public bool IsLocal
{
get { return true; }
}
public bool IsParam
{
get { return true; }
}
public XPathResultType VariableType
{
get
{
return XPathResultType.Any;
}
}
#endregion
}
public class CurrentFunction : IXsltContextFunction
{
private XPathNodeIterator CurrentNodeIterator;
internal CurrentFunction(IXPathNavigable currentNode)
{
if (currentNode != null)
{
CurrentNodeIterator = currentNode.CreateNavigator().Select(".");
}
}
public XPathResultType[] ArgTypes
{
get { return new XPathResultType[0]; }
}
public object Invoke(XsltContext xsltContext, object[] args,
XPathNavigator docContext)
{
if (CurrentNodeIterator == null)
{
throw new ApplicationException("Current node is not set.");
}
return CurrentNodeIterator;
}
public int Maxargs
{
get { return 0; }
}
public int Minargs
{
get { return 0; }
}
public XPathResultType ReturnType
{
get { return XPathResultType.NodeSet; }
}
}
一旦你在某处定义了它,你可以执行以下操作:
Once you have that defined somewhere, you can do the following:
VariableContext vc = new VariableContext();
XmlNode nodea = doc.SelectSingleNode("Root/Start[1]");
vc.SetValue("a", nodea);
XmlNodeList selected = doc.SelectNodes("/Root/Item[@id = $a/@refId]", vc);
或者使用自定义的current()
函数:
or use a custom-defined current()
function:
VariableContext vc2 = new VariableContext();
XmlNode nodea2 = doc.SelectSingleNode("Root/Start[1]");
vc2.SetCurrentNode(nodea2);
XmlNodeList selected2 = doc.SelectNodes("/Root/Item[@id = current()/@refId]", vc2);
PrintNodeList(selected2);
工作ideone:http://ideone.com/7wsQ46
这篇关于.NET XPath 从特定元素开始并反向引用它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!