我的XPath / XML有什么问题?
我正在此xml上尝试一个非常基本的XPath(与下面相同),但找不到任何东西。
我正在尝试.NET和此网站,而XPath(例如// PropertyGroup
,/ PropertyGroup
和// MSBuildCommunityTasksPath
)对我来说根本不起作用(它们编译后返回零结果)。
源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>
解决方案
问题与名称空间有关(xmlns =" http://schemas.microsoft.com/developer/msbuild/2003")。我们收到零个节点,因为我们没有使用名称空间来限定它。如果删除xmlns属性,则" // PropertyGroup" XPath将起作用。如何使用名称空间查询通常涉及将默认xmlns别名作为标识符(因为未在属性上指定一个),然后选择" // myXMLNStoken:PropertyGroup"。
文档中的标签以xmlns属性创建的"默认"名称空间结尾,没有前缀。不幸的是,仅XPath不能查询默认名称空间中的元素。我实际上不确定语义的细节,但是我们必须使用托管XPath的任何工具将前缀显式地添加到该命名空间。
在.NET中,执行此操作的方法可能更短,但是我所看到的唯一方法是通过NameSpaceManager。在显式添加名称空间之后,可以使用名称空间管理器进行查询,就好像名称空间元素中的所有标记都具有该前缀(我选择了" 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); } } }
我们可以在代码等中添加名称空间,但可以有效地对名称空间进行通配。尝试以下XPath习惯用法。
//*[local-name()='PropertyGroup'] //*[local-name()='MSBuildCommunityTasksPath']
name()通常也可以正常工作,例如:
//*[name()='PropertyGroup'] //*[name()='MSBuildCommunityTasksPath']
编辑:命名空间很棒,我并不是在暗示它们并不重要,但是在将原型代码,一次性桌面工具,XSLT实验等结合在一起时,通配符会派上用场。平衡便利需求和手头工作可接受的风险。仅供参考,如果需要,我们还可以剥离或者重新分配名称空间。