【问题标题】:Getting an XElement with a namespace via XPathSelectElements通过 XPathSelectElements 获取具有命名空间的 XElement
【发布时间】:2013-11-08 18:56:39
【问题描述】:

我有一个 XML,例如

    <?xml version="1.0" encoding="utf-8"?>
    <A1>
       <B2>
          <C3 id="1">
             <D7>
                <E5 id="abc" />
             </D7>
             <D4 id="1">
                <E5 id="abc" />
             </D4>
             <D4 id="2">
                <E5 id="abc" />
             </D4>
          </C3>
       </B2>
    </A1>

这是可能的示例代码:

    var xDoc = XDocument.Load("Test.xml");
    string xPath = "//B2/C3/D4";
    //or string xPath = "//B2/C3/D4[@id='1']";

    var eleList = xDoc.XPathSelectElements(xPath).ToList();
    foreach (var xElement in eleList)
    {
        Console.WriteLine(xElement);
    }

它运行良好,但是如果我向根节点 A1 添加命名空间,则此代码不起作用。 在搜索解决方案时,我找到了this one,但它使用 Descendants() 方法来查询 XML。据我了解,如果我搜索 ,此解决方案将失败,因为 、 和

存在相同的标签

我的要求是搜索某个节点是否存在于特定的 XPath 中。如果有使用 Descendants 的方法,我会很高兴使用它。如果没有,请指导我如何使用名称空间进行搜索。

如果这是重复的,我深表歉意。

【问题讨论】:

    标签: c# xml xpath linq-to-xml


    【解决方案1】:

    要继续使用 XPath,您可以使用以下链接:

    var xDoc = XDocument.Parse(@"<?xml version='1.0' encoding='utf-8'?>
        <A1 xmlns='urn:sample'>
            <B2>
                <C3 id='1'>
                    <D7><E5 id='abc' /></D7>
                    <D4 id='1'><E5 id='abc' /></D4>
                    <D4 id='2'><E5 id='abc' /></D4>
                </C3>
            </B2>
        </A1>");
    
    // Notice this
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
    nsmgr.AddNamespace("sample", "urn:sample");
    
    string xPath = "//sample:B2/sample:C3/sample:D4";
    
    var eleList = xDoc.XPathSelectElements(xPath, nsmgr).ToList();
    foreach (var xElement in eleList)
    {
        Console.WriteLine(xElement);
    }
    

    【讨论】:

    • 我试过了,谢谢,很管用。这是最好的方法吗?我只是问,因为我的函数将整个 XPath 作为字符串传递,并且它没有 xPath 变量中显示的名称空间。我可以通过字符串替换添加它,但只是想知道是否还有其他方法可以做到这一点?
    • 命名空间 prefix 并不重要,只是 value 部分;所以,如果你将前缀从 sample 重命名为 whatever 就可以了。
    • 可能我在这里遗漏了一些东西,我的意思是您在 xPath 变量中的每个元素名称之前都有前缀。我在问这个的替代方案。即“//sample:B2/sample:C3/sample:D4”
    • @Charlie,如果您的 XML 文档有命名空间而您的 XPath 表达式没有,则需要更改其中之一。
    【解决方案2】:

    但它使用 Descendants() 方法来查询 XML。据我了解,如果我正在搜索,此解决方案将失败,因为 , 和

    存在相同的标签

    我很确定您不太了解它是如何工作的。来自MSDN documentation:

    按文档顺序返回此文档或元素的后代元素的过滤集合。集合中仅包含具有匹配 XName 的元素。

    所以在你的情况下,只需这样做:

    xDoc.RootNode
        .Descendants("E5")
        .Where(n => n.Parent.Name.LocalName == "B4");
    

    【讨论】:

    • 是的,但是我怎么知道它是否属于我的 XPath。如您所见,同一个 E5 节点出现在多条路径上。
    • @Charlie,看看我的编辑。我利用Parent 属性来确保它是B4 元素的一部分。
    • 这很接近,但我的 XPath 作为字符串传递,我无法动态检查每个父节点直到根节点。我的 XML 有很深的层次结构。
    【解决方案3】:

    试试这个

    var xDoc = XDocument.Parse("<A1><B2><C3 id=\"1\"><D7><E5 id=\"abc\" /></D7><D4 id=\"1\"><E5 id=\"abc\" /></D4><D4 id=\"2\"><E5 id=\"abc\" /></D4></C3></B2></A1>");
            foreach (XElement item in xDoc.Element("A1").Elements("B2").Elements("C3").Elements("D4"))
            {
                Console.WriteLine(item.Element("E5").Value);//to get the value of E5
                Console.WriteLine(item.Element("E5").Attribute("id").Value);//to get the value of attribute
            }
    

    【讨论】:

    • 我不能这样做,我将 XPath 作为一个字符串,我如何将它实现为你拥有的 foreach 循环?此外,XPath 可以是 n 级深度。有办法处理吗?
    猜你喜欢
    • 2021-10-19
    • 2018-12-19
    • 1970-01-01
    • 2016-03-05
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 2013-02-18
    • 1970-01-01
    相关资源
    最近更新 更多