views:

60

answers:

2

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']
+2  A: 

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.

Dennis Knochenwefel
+1, good suggestion. Does Linq-to-XML support XPath 2.0, do you know?
LarsH
@LarsH: There is no XPath 2.0 support in .NET.
Dimitre Novatchev
+5  A: 

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.

LarsH
+1 for a comprehensive example.
Dimitre Novatchev