I'm trying a very basic XPath on this xml (same as below), and it doesn't find anything.
I'm trying both .NET and this website, and XPaths such as //PropertyGroup
, /PropertyGroup
and //MSBuildCommunityTasksPath
are simply not working for me (they compiled but return zero results).
Source XML:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- $Id: FxCop.proj 114 2006-03-14 06:32:46Z pwelter34 $ -->
<PropertyGroup>
<MSBuildCommunityTasksPath>$(MSBuildProjectDirectory)\MSBuild.Community.Tasks\bin\Debug</MSBuildCommunityTasksPath>
</PropertyGroup>
<Import
Project="$(MSBuildProjectDirectory)\MSBuild.Community.Tasks\MSBuild.Community.Tasks.Targets" />
<Target Name="DoFxCop">
<FxCop TargetAssemblies="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.dll"
RuleLibraries="@(FxCopRuleAssemblies)"
AnalysisReportFileName="Test.html"
DependencyDirectories="$(MSBuildCommunityTasksPath)"
FailOnError="True"
ApplyOutXsl="True"
OutputXslFileName="C:\Program Files\Microsoft FxCop 1.32\Xml\FxCopReport.xsl" />
</Target>
</Project>
You can add namespaces in your code and all that, but you can effectively wildcard the namespace. Try the following XPath idiom.
//*[local-name()='PropertyGroup']
//*[local-name()='MSBuildCommunityTasksPath']
name() usually works as well, as in:
//*[name()='PropertyGroup']
//*[name()='MSBuildCommunityTasksPath']
EDIT: Namespaces are great and i'm not suggesting they're not important, but wildcarding them comes in handy when cobbling together prototype code, one-off desktop tools, experimenting with XSLT, and so forth. Balance your need for convenience against acceptable risk for the task at hand. FYI, if need be, you can also strip or reassign namespaces.
The tags in the document end up in the "default" namespace created by the xmlns attribute with no prefix. Unfortunately, XPath alone can not query elements in the default namespace. I'm actually not sure of the semantic details, but you have to explicitly attach a prefix to that namespace using whatever tool is hosting XPath.
There may be a shorter way to do this in .NET, but the only way I've seen is via a NameSpaceManager. After you explicitly add a namespace, you can query using the namespace manager as if all the tags in the namespaced element have that prefix (I chose 'msbuild'):
using System;
using System.Xml;
public class XPathNamespace {
public static void Main(string[] args) {
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(
@"<?xml version=""1.0"" encoding=""utf-8""?>
<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
<!-- $Id: FxCop.proj 114 2006-03-14 06:32:46Z pwelter34 $ -->
<PropertyGroup>
<MSBuildCommunityTasksPath>$(MSBuildProjectDirectory)\MSBuild.Community.Tasks\bin\Debug</MSBuildCommunityTasksPath>
</PropertyGroup>
<Import Project=""$(MSBuildProjectDirectory)\MSBuild.Community.Tasks\MSBuild.Community.Tasks.Targets""/>
<Target Name=""DoFxCop"">
<FxCop
TargetAssemblies=""$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.dll""
RuleLibraries=""@(FxCopRuleAssemblies)""
AnalysisReportFileName=""Test.html""
DependencyDirectories=""$(MSBuildCommunityTasksPath)""
FailOnError=""True""
ApplyOutXsl=""True""
OutputXslFileName=""C:\Program Files\Microsoft FxCop 1.32\Xml\FxCopReport.xsl""
/>
</Target>
</Project>");
XmlNamespaceManager namespaceManager = new
XmlNamespaceManager(xmlDocument.NameTable);
namespaceManager.AddNamespace("msbuild", "http://schemas.microsoft.com/developer/msbuild/2003");
foreach (XmlNode n in xmlDocument.SelectNodes("//msbuild:MSBuildCommunityTasksPath", namespaceManager)) {
Console.WriteLine(n.InnerText);
}
}
}
Your issue is with the namespace (xmlns="http://schemas.microsoft.com/developer/msbuild/2003"). You're receiving zero nodes because you aren't qualifying it with the namespace. If you remove the xmlns attribute, your "//PropertyGroup" XPath will work. How you query with namespace usually involves aliasing a default xmlns to an identifier (since one is not specified on the attribute), and selecting like "//myXMLNStoken:PropertyGroup".