什么是XPath(在C#API中XDocument.XPathSelectElements(xpath,nsman),如果重要的话)查询此文档中的所有MyNode? p>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<MyNode xmlns="lcmp" attr="true">
<subnode />
</MyNode>
</configuration>
/configuration/MyNode
这是错误的,因为它忽略了命名空间。/configuration/lcmp:MyNode
这是错误的,因为lcmp
是URI,而不是前缀。/configuration/{lcmp}MyNode
失败,因为Additional information: '/configuration/{lcmp}MyNode' has an invalid token.
编辑:我不能像一些回答者所建议的那样使用mgr.AddNamespace("df", "lcmp");
。这要求XML解析程序知道我计划提前使用的所有命名空间。由于这适用于任何源文件,我不知道手动添加前缀的命名空间。似乎{my uri}
是XPath语法,但微软并没有打算实现那个......是吗?
答案 0 :(得分:37)
configuration
元素位于未命名的命名空间中,MyNode绑定到lcmp
命名空间而没有命名空间前缀。
这个 XPATH 语句允许您在没有声明MyNode
命名空间或在XPATH中使用命名空间前缀的情况下处理lcmp
元素:
/configuration/*[namespace-uri()='lcmp' and local-name()='MyNode']
它匹配configuration
的子元素,然后使用带有namespace-uri()
和local-name()
函数的谓词文件管理器将其限制为MyNode
元素。
如果您不知道哪些名称空间-uri将用于元素,那么您可以使 XPATH 更通用,只匹配local-name()
:
/configuration/*[local-name()='MyNode']
但是,您冒着匹配碰巧使用相同名称的不同词汇表(绑定到不同名称空间 - uri)中的不同元素的风险。
答案 1 :(得分:12)
您需要使用XmlNamespaceManager,如下所示:
XDocument doc = XDocument.Load(@"..\..\XMLFile1.xml");
XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
mgr.AddNamespace("df", "lcmp");
foreach (XElement myNode in doc.XPathSelectElements("configuration/df:MyNode", mgr))
{
Console.WriteLine(myNode.Attribute("attr").Value);
}
答案 2 :(得分:7)
答案 3 :(得分:4)
这是一个如何使命名空间可用于XPath表达式的示例 XPathSelectElements扩展方法:
using System;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml;
namespace XPathExpt
{
class Program
{
static void Main(string[] args)
{
XElement cfg = XElement.Parse(
@"<configuration>
<MyNode xmlns=""lcmp"" attr=""true"">
<subnode />
</MyNode>
</configuration>");
XmlNameTable nameTable = new NameTable();
var nsMgr = new XmlNamespaceManager(nameTable);
// Tell the namespace manager about the namespace
// of interest (lcmp), and give it a prefix (pfx) that we'll
// use to refer to it in XPath expressions.
// Note that the prefix choice is pretty arbitrary at
// this point.
nsMgr.AddNamespace("pfx", "lcmp");
foreach (var el in cfg.XPathSelectElements("//pfx:MyNode", nsMgr))
{
Console.WriteLine("Found element named {0}", el.Name);
}
}
}
}
答案 4 :(得分:1)
Xpath 2.0 +库的示例:
using Wmhelp.XPath2;
doc.XPath2SelectElements("/*:configuration/*:MyNode");
见:
答案 5 :(得分:0)
我喜欢@ mads-hansen,他的答案,以及我写这些通用实用程序类成员的好:
/// <summary>
/// Gets the <see cref="XNode" /> into a <c>local-name()</c>, XPath-predicate query.
/// </summary>
/// <param name="childElementName">Name of the child element.</param>
/// <returns></returns>
public static string GetLocalNameXPathQuery(string childElementName)
{
return GetLocalNameXPathQuery(namespacePrefixOrUri: null, childElementName: childElementName, childAttributeName: null);
}
/// <summary>
/// Gets the <see cref="XNode" /> into a <c>local-name()</c>, XPath-predicate query.
/// </summary>
/// <param name="namespacePrefixOrUri">The namespace prefix or URI.</param>
/// <param name="childElementName">Name of the child element.</param>
/// <returns></returns>
public static string GetLocalNameXPathQuery(string namespacePrefixOrUri, string childElementName)
{
return GetLocalNameXPathQuery(namespacePrefixOrUri, childElementName, childAttributeName: null);
}
/// <summary>
/// Gets the <see cref="XNode" /> into a <c>local-name()</c>, XPath-predicate query.
/// </summary>
/// <param name="namespacePrefixOrUri">The namespace prefix or URI.</param>
/// <param name="childElementName">Name of the child element.</param>
/// <param name="childAttributeName">Name of the child attribute.</param>
/// <returns></returns>
/// <remarks>
/// This routine is useful when namespace-resolving is not desirable or available.
/// </remarks>
public static string GetLocalNameXPathQuery(string namespacePrefixOrUri, string childElementName, string childAttributeName)
{
if (string.IsNullOrEmpty(childElementName)) return null;
if (string.IsNullOrEmpty(childAttributeName))
{
return string.IsNullOrEmpty(namespacePrefixOrUri) ?
string.Format("./*[local-name()='{0}']", childElementName)
:
string.Format("./*[namespace-uri()='{0}' and local-name()='{1}']", namespacePrefixOrUri, childElementName);
}
else
{
return string.IsNullOrEmpty(namespacePrefixOrUri) ?
string.Format("./*[local-name()='{0}']/@{1}", childElementName, childAttributeName)
:
string.Format("./*[namespace-uri()='{0}' and local-name()='{1}']/@{2}", namespacePrefixOrUri, childElementName, childAttributeName);
}
}