有没有办法从XML文件中删除命名空间垃圾?

时间:2010-10-26 16:44:44

标签: xpath namespaces linq-to-xml

我需要从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']

更新

在未来的五年里,除了一些想要使用更强壮的东西的纤维之外,我对我的每一根纤维都支持“迷宫般的愚蠢”一词。

2 个答案:

答案 0 :(得分:5)

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名称空间。然而,没有人能够制定出更好的标准并让社区接受它。

答案 1 :(得分:2)

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

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

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