Linq-to-XML获取带有命名空间的元素

6
我正在使用LINQ to XML来搜索元素。
 var doc = XDocument.Load(reader);
                    var ns = doc.Root.Attribute("xmlns").Value;
                    var result = (from u in doc.Descendants(XName.Get("MyElement", ns))

我需要摆脱在 XML 中查找元素时使用 XName.Get。我该如何将默认命名空间设置为 XDocument,以便在搜索时不会有麻烦呢?
谢谢!
6个回答

8

如果您确实希望忽略默认命名空间,这是一种方法:

        XDocument doc;
        using (XmlTextReader xr = new XmlTextReader("input.xml"))
        {
            xr.Namespaces = false;
            doc = XDocument.Load(xr);
        }
        foreach (XElement bar in doc.Descendants("bar"))

我建议您接受XML中名称空间的存在和重要性,并使用LINQ to XML提供的XName和XNamespace对象来处理它们。


1
是的,我同意命名空间的重要性,但在我的情况下,我的 XML 文档元素属于一个我已经知道的单一命名空间。因此,在搜索元素时,我真的不需要再次传递它。 - Shoaib Shaikh

4
我需要摆脱在xml中查找元素时使用XName.Get的方法。如何为XDocument设置默认命名空间,以便在搜索时不会产生麻烦。
您不能这样做,但有另外两个选项:
  • Use the +(XNamespace, string) operator:

    doc.Descendants(ns + "MyElement")
    
  • Just create the XName values once, then refer to them in your query, e.g.

    XName myElementName = ns + "MyElement";
    ...
    doc.Descendants(myElementName);
    

理想情况下,您不会动态创建命名空间 - 您难道不知道应该查找哪个命名空间吗?如果您知道,可以创建具有适当的XName值的私有静态只读字段。


所以,无法说此节点中的所有元素都属于此命名空间,这将允许我仅按名称搜索元素,对吗? - Shoaib Shaikh
你可以在搜索中使用 element.Name.LocalName。 - Paul Williams
@ImaDirtyTroll:但是为什么不直接指定命名空间呢?(这也是我在使用MSBuild时会做的事情...)在大多数情况下,你真的不想最终得到错误命名空间中的元素,但它们恰好在文档中。 - Jon Skeet
抱歉,我是在回复Eric的评论。我也在回应你的评论“你只会通过XName搜索,而不是字符串”,这并不完全正确。(线程有点混乱。)OP似乎大多想要避免使用命名空间。 - Paul Williams
@ImaDirtyTroll:我想我应该澄清一下:“那些需要使用元素或属性名称进行查找的方法只有XName参数,而没有字符串参数。” - Jon Skeet
显示剩余2条评论

1
您还可以使用LocalName,这会使LINQ的代码变得难看,但可以完成工作。(在这种情况下是从MSBuild项目文件中获取属性)。
var imports = from i in doc.Root.Elements()
              where i.Name.LocalName == "Import"
              from p in i.Attributes()
              where p.Name.LocalName == "Project"
              select p.Value;

我喜欢这种方式的原因是它保留了XML的原始形式,同时向其他人暗示着某些有趣的事情正在发生。在LINQ表达式中放置“LocalName”有点像自我记录的hack。
如果代码被拆分,很容易忽略在XmlTextReader中关闭命名空间。

1

你不能这样做:

doc = XDocument.Load(reader);
var ns = doc.Root.Attribute("xmlns").Value;
var result = from u in doc.Descendants.Elements(ns+"MyElement").Select(c=>c.Value);

1
再次需要将ns连接起来,这会使代码变得有些晦涩。我们能不能避免使用ns? - Shoaib Shaikh
var result = from u in doc.Descendants().Elements(ns + "MyElement") select u;请将此代码翻译为中文: - Imir Hoxha

0

这是一篇旧帖子,但这是我的想法:

Elements.xml根元素包含一个命名空间属性。以下代码忽略了命名空间。

XDocument doc = XDocument.Load("Elements.xml");

            if (doc.Root != null)
                foreach (XElement xElement in doc.Root.Elements())
                {
                    Console.WriteLine(xElement);
                }

0
创建扩展方法:
        public static XElement ElementInCurrentNamespace(this XElement element, string elementName)
        {
            return element
                .Element(element.Name.Namespace.GetName(elementName));
        }

        public static IEnumerable<XElement> ElementsInCurrentNamespace(this XElement element, string elementName)
        {
            return element
                .Elements(element.Name.Namespace.GetName(elementName));
        }
  • 第一次使用名称空间访问元素时,请使用.Element.Elements方法与名称空间一起,例如element.Element(namespace.GetName("foo"))
  • 随后(只要后代元素具有相同的名称空间),请使用上述扩展方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接