我需要知道XDocument中XElement的xpath,使用命名空间,因为我需要它来在XDocument中进行稍后的查找。
我目前正在使用Get the XPath to an XElement?中的示例,它适用于没有命名空间的文档。但是没有带有命名空间的xml文档,并且支持它的工具不能给我正确的路径。
示例我有xml文档
<?xml version="1.0" encoding="utf-8"?>
<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition">
<AutoRefresh>0</AutoRefresh>
<DataSources>
以下代码会在/:Report
XPathSelectElement
和崩溃的路径
var x = XDocument.Load(@"file.xml");
var path = x.Elements().First().GetAbsoluteXPath();
var element = x.XPathSelectElement(path);
路径假设如何?我已经手动试过&#34; / rd:Report&#34;它仍然很难选择元素。
扩展,在另一个主题中找到:
public static class XExtensions
{
/// <summary>
/// Get the absolute XPath to a given XElement, including the namespace.
/// (e.g. "/a:people/b:person[6]/c:name[1]/d:last[1]").
/// </summary>
public static string GetAbsoluteXPath(this XElement element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
Func<XElement, string> relativeXPath = e =>
{
int index = e.IndexPosition();
var currentNamespace = e.Name.Namespace;
string name;
if (currentNamespace == null)
{
name = e.Name.LocalName;
}
else
{
string namespacePrefix = e.GetPrefixOfNamespace(currentNamespace);
name = namespacePrefix + ":" + e.Name.LocalName;
}
// If the element is the root, no index is required
return (index == -1) ? "/" + name : string.Format
(
"/{0}[{1}]",
name,
index.ToString()
);
};
var ancestors = from e in element.Ancestors()
select relativeXPath(e);
return string.Concat(ancestors.Reverse().ToArray()) +
relativeXPath(element);
}
/// <summary>
/// Get the index of the given XElement relative to its
/// siblings with identical names. If the given element is
/// the root, -1 is returned.
/// </summary>
/// <param name="element">
/// The element to get the index of.
/// </param>
public static int IndexPosition(this XElement element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
if (element.Parent == null)
{
return -1;
}
int i = 1; // Indexes for nodes start at 1, not 0
foreach (var sibling in element.Parent.Elements(element.Name))
{
if (sibling == element)
{
return i;
}
i++;
}
throw new InvalidOperationException
("element has been removed from its parent.");
}
}
答案 0 :(得分:2)
好吧,首先/:Report
不是有效的XPath表达式,如果您使用的函数创建了该路径,那么在XML文档具有默认命名空间(如xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition"
的情况下,它不会输出有效的XPath) 。事实上,在输入中给出这样的默认命名空间声明,任何创建路径的函数都需要生成一个前缀(并且通常为不同的命名空间生成多个)并将其绑定到默认的命名空间URI。或者您需要采用不同的方法并生成*[local-name() = 'Report' and namespace-uri() = 'http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition']
形式的步骤。使用XPath 1.0,这是我作为前缀生成的方式,它们与命名空间URI的绑定取决于您使用的特定XPath API,而另一种方法适用于任何XPath API。