【问题标题】:Any way to strip namespace garbage from XML file?有什么方法可以从 XML 文件中去除命名空间垃圾?
【发布时间】:2010-10-26 16:44:44
【问题描述】:

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

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

那么有什么办法可以去除文件中的线路噪音?还是我卡住了? Linq-to-XML 迷宫般的低能真的是小恶魔吗?

[1]

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

更新

五年后,我的每一根纤维都支持“迷宫般的愚蠢”一词,除了少数想要使用更强大的东西的纤维。

【问题讨论】:

  • 看到这是一个 XAML 文件,使用的命名空间将被标准化,所以我不同意你的观点,即这会不必要地脆弱。此外,XML 命名空间的存在有一个非常真实的原因 - 不要只是将它们标记为“垃圾” - 学会利用它们来发挥自己的优势!
  • @marc_s,我完全同意 Plunkett 先生的观点。难以编写的代码往往很脆弱。代码稳定性是最重要的,忽略某些东西会变脆的唠叨感觉是愚蠢的。这并不是说你说的话没有任何价值,而是说“suck it up”更糟糕。
  • @Star:除了他没有说“接受它”(即,是的,这很糟糕,但忽略它并无论如何都要这样做)。他说 XML 命名空间是有原因的,您可以学习如何利用它们来发挥自己的优势。我已经这样做了,命名空间还不错;最不方便的部分是学习每个 XPath-to-my-code 接口如何处理它们。而且 XmlNamespaceManager 也不是那么糟糕……这是相当合乎逻辑的。 没有命名空间的混合 XML 词汇表是脆弱的。
  • @Ed,你在什么环境下开发,所以我们可以知道有哪些方法可用/实用?您提到了 linq-to-xml,但听起来您正在寻找它的替代品。我猜你使用的是 .NET?
  • LarsH,你正确推断出 .NET。

标签: xpath namespaces linq-to-xml


【解决方案1】:

Ed,here's an example 在 System.Xml.XPath Extensions 类中使用命名空间。我已对其进行了修改以匹配您正在查看的输入:

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 命名空间。然而,没有人设法制定出更好的标准并被社区接受。

【讨论】:

  • 拉斯,再次感谢。我希望能够以给定的形式遍历 XML,而不必事先知道名称空间将是什么。如果一个属性被称为“x:Name”,我不介意这样称呼它,但是必须知道架构 URL “x”指的是什么很烦人。坦率地说,我不一定在乎。代码能够非常严格地验证自己的 XML 是很有价值的,并且命名空间的东西允许这样做 - 但代码能够相当随意地查看其他人的 XML 也很有价值。
  • @Ed,感谢您的评论。我同意,为了从 XML 文档中选择位,必须了解所涉及的模式会很麻烦。但值得庆幸的是,从命名空间到模式(或从 ns URI 到其他任何东西……它们只是抽象标识符)之间没有必要的链接。您可以完全忽略模式并完全忽略验证,这不会影响您使用 XPath 选择文档部分的能力(除非您开始使用数据类型或其他东西进行模式感知处理,但这在我的经验)。
【解决方案2】:

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

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

顺便说一句。如果一个属性没有前缀,那么它根本就没有命名空间。因为这是最常见的情况,我猜,你不需要 local-name() 属性。

【讨论】:

  • +1,好建议。 Linq-to-XML 是否支持 XPath 2.0,你知道吗?
  • @LarsH:.NET 中不支持 XPath 2.0。
  • 谢谢——我会试一试(尽管我看到另一条评论表明 .NET 不支持 XPath 2.0,该死的......)。我确实知道无前缀/无名称空间属性;多年来一直在使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-12
  • 1970-01-01
  • 2020-08-30
  • 2014-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多