命名空间为的元素的Xpath
本文关键字:Xpath 元素 命名空间 | 更新日期: 2023-09-27 17:59:47
我需要知道XDocument中XElement的xpath,并使用我需要的名称空间来稍后在XDocument进行查找。
我目前正在使用GettheXPath to a 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);
这条路应该是怎样的?我手动尝试了"/rd:Report",但它仍然无法选择元素。
延伸,在另一个主题中找到:
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.");
}
}
首先,/: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']
的步骤。对于XPath1.0,我将采用这种方式来生成前缀,并且它们与命名空间URI的绑定取决于您使用的特定XPathneneneba API,而另一种方法将适用于任何XPathnenenebb API。