有什么方法可以从 XML 文件中去除名称空间垃圾吗?

发布于 2024-09-29 08:11:38 字数 582 浏览 6 评论 0原文

我需要从 XML 文件(来自 Silverlight XAP 文件的 AppNamespace.xaml,这并不重要)中选择一些节点,但该文件具有命名空间内容,因此 XPath 不起作用。我可能会浪费一天的大部分时间来尝试 XmlNamespaceManager 的束缚和纪律噩梦,最终得到无可救药的脆弱代码,无法容忍输入文件中最轻微的变化(在生产代码中不是一个好主意),或者我可以使用可笑的 local-name() 语法[1]。

但使用 XPath 作为人类可读的查询语言会更方便,它可用于从任意 XML 文件返回指定的节点或属性值。

那么有什么方法可以去除文件中的线条噪声吗?还是我被困住了? Linq-to-XML 的迷宫式愚蠢真的是两害相权取其轻吗?

[1]

//*[local-name() = 'Deployment']/*[local-name() = 'Deployment.Parts']/*[local-name() = 'AssemblyPart']/@*[local-name()='Name']

更新

五年后,我全身心地支持“迷宫般的愚蠢”这个词,除了少数想要使用更强大的东西的纤维。

I need to select some nodes from an XML file (AppNamespace.xaml from a Silverlight XAP file, not that it matters), but the file has namespace stuff so XPath doesn't work. I could waste most of a day trial-and-erroring the bondage-and-discipline nightmare of XmlNamespaceManager and end up with hopelessly fragile code that can't tolerate the slightest variation in the input file (not a great idea in production code), or I could use the ludicrous local-name() syntax[1].

But it would be more convenient to use XPath as a human-readable query language that can be used to return specified nodes or attribute values from arbitrary XML files.

So is there any way to strip the line-noise out of the file? Or am I stuck? Is the labyrinthine imbecility of Linq-to-XML truly the lesser evil?

[1]

//*[local-name() = 'Deployment']/*[local-name() = 'Deployment.Parts']/*[local-name() = 'AssemblyPart']/@*[local-name()='Name']

Update

Five years down the road, I stand behind the term "labyrinthine imbecility" with every fiber of my being, except for a few fibers that want to use something much stronger.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寂寞美少年 2024-10-06 08:11:38

Ed,这是一个使用 System.Xml.XPath 命名空间的示例扩展类。我已对其进行了修改以匹配您正在查看的输入:

string markup = @"
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" ...>
  <Deployment.Parts>
    <AssemblyPart x:Name="xamlName" Source="assembly" />
  </Deployment.Parts>
</Deployment>
";

XmlReader reader = XmlReader.Create(new StringReader(markup));
XElement root = XElement.Load(reader);

XmlNameTable nameTable = reader.NameTable;
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(nameTable);
nsm.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");
nsm.AddNamespace("dep", "http://schemas.microsoft.com/client/2007/deployment");

IEnumerable<XElement> elements =
   root.XPathSelectElements("//dep:Deployment/dep:Deployment.Parts/dep:AssemblyPart/@x:Name", nsm);
foreach (XElement el in elements)
    Console.WriteLine(el);

不是很复杂。显然您已经了解 XmlNamespaceManager,但我认为您对它的印象比它应得的要糟糕。

当您说“代码极其脆弱,无法容忍输入文件中最微小的变化”时,您是在指责命名空间还是 XmlNamespaceManager?我不明白其中任何一个如何使它变得脆弱......比没有命名空间的XML处理代码更不能容忍输入文档中的某些更改,但会容忍其他更改。

对业内其他聪明人抱有一点尊重,在放弃某个设计之前花一点时间了解其背后的优势,通常会发现所做的事情是有充分理由的。

XML 命名空间并不是不能改进。然而,没有人能够制定出更好的标准并被社区所接受。

Ed, here's an example of using namespaces with the System.Xml.XPath Extensions class. I've modified it to match the input you're looking at:

string markup = @"
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" ...>
  <Deployment.Parts>
    <AssemblyPart x:Name="xamlName" Source="assembly" />
  </Deployment.Parts>
</Deployment>
";

XmlReader reader = XmlReader.Create(new StringReader(markup));
XElement root = XElement.Load(reader);

XmlNameTable nameTable = reader.NameTable;
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(nameTable);
nsm.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");
nsm.AddNamespace("dep", "http://schemas.microsoft.com/client/2007/deployment");

IEnumerable<XElement> elements =
   root.XPathSelectElements("//dep:Deployment/dep:Deployment.Parts/dep:AssemblyPart/@x:Name", nsm);
foreach (XElement el in elements)
    Console.WriteLine(el);

Not very complicated. Obviously you already know about XmlNamespaceManager, but I think you got a worse impression of it than it deserves.

When you say "hopelessly fragile code that can't tolerate the slightest variation in the input file", are you blaming namespaces in general, or XmlNamespaceManager? I don't see how either one makes it fragile... any more so than XML processing code without namespaces will not tolerate certain changes in the input document, but will tolerate others.

Have a little respect for other intelligent people in the industry, take a little time to understand the advantages behind a design before you dismiss it, and you will usually find that there are good reasons for what was done.

Not that XML namespaces couldn't be improved upon. However nobody has managed to produce a better standard and get it accepted by the community.

茶花眉 2024-10-06 08:11:38

在 XPath 2.0 中,您可以使用名称空间通配符(如果您知道自己在做什么):

//*:Deployment/*:Deployment.Parts/*:AssemblyPart/@Name

顺便说一句。如果属性没有前缀,则它根本不位于命名空间中。由于这是最常见的情况,我猜您不需要 local-name() 作为属性。

In XPath 2.0 you can use namespace wildcards (if you know what you are doing):

//*:Deployment/*:Deployment.Parts/*:AssemblyPart/@Name

btw. If an attribute doesn't have a prefix it is in no namespace at all. As this is most often the case, I guess, you don't need local-name() for the attribute.

绿萝 2024-10-06 08:11:38

我通过此搜索来到这里: 在此处输入图像描述

,我添加一个“答案”来为您的“5 周年”更新欢呼。

我之所以这样做是因为我有一个使用大量命名空间的 XML 文档 -

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:x2="urn:schemas-microsoft-com:office:excel2" version="1.0" exclude-result-prefixes="msxsl">

显然我必须提前知道所有这些命名空间是什么,以便对 XmlNamespaceManager 进行硬编码,或者编写一些解析命名空间声明的代码自己添加相关的名称空间。看在神圣的份上,为什么 XmlDocument 自己不能做到这一点呢?

XmlDocument databaseXml = new XmlDocument();
databaseXml.LoadXml(xslt.XslTransform);
var dbnsmgr = new XmlNamespaceManager(databaseXml.NameTable);
dbnsmgr.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
dbnsmgr.AddNamespace("ss", "urn:schemas-microsoft-com:office:spreadsheet");
XmlElement databaseStylesElement = (XmlElement)database
Xml.DocumentElement.SelectSingleNode("/xsl:stylesheet/xsl:template");

I came here as a result of this search: enter image description here

and I am adding an "Answer" to cheer on your "5 years on" update.

I was motivated to do this because I have an XML document that uses a tonne of namespaces -

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:x2="urn:schemas-microsoft-com:office:excel2" version="1.0" exclude-result-prefixes="msxsl">

and APPARENTLY I have to know what all those namespaces are in advance in order to hard code the XmlNamespaceManager, or write some code that parses the namespace declarations and adds the relevant name spaces myself. Why in the name of all that is holy does the XmlDocument not manage to do that all by itself?

XmlDocument databaseXml = new XmlDocument();
databaseXml.LoadXml(xslt.XslTransform);
var dbnsmgr = new XmlNamespaceManager(databaseXml.NameTable);
dbnsmgr.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform");
dbnsmgr.AddNamespace("ss", "urn:schemas-microsoft-com:office:spreadsheet");
XmlElement databaseStylesElement = (XmlElement)database
Xml.DocumentElement.SelectSingleNode("/xsl:stylesheet/xsl:template");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文