命名空间为的元素的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.");
    }
}

命名空间为的元素的Xpath

首先,/: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。