【问题标题】:Xpath of Element with namespace具有命名空间的元素的 Xpath
【发布时间】:2014-04-23 08:21:21
【问题描述】:

我需要知道 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);

路径应该是怎样的?我手动尝试了“/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.");
    }
}

【问题讨论】:

标签: c# xml xpath


【解决方案1】:

首先,/:Report 不是一个有效的 XPath 表达式,如果您使用的函数创建了该路径,那么它不会输出一个有效的 XPath,以防 XML 文档具有像 xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition" 这样的默认命名空间。事实上,在输入中给出这样的默认命名空间声明,任何创建路径的函数也需要生成一个前缀(通常为不同的命名空间生成多个前缀)并将其绑定到默认命名空间 URI。或者您需要采用不同的方法并生成*[local-name() = 'Report' and namespace-uri() = 'http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition'] 形式的步骤。在 XPath 1.0 中,我会采用这种方式来生成前缀并将它们绑定到命名空间 URI,这取决于您使用的特定 XPath API,而另一种方法适用于任何 XPath API。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多