What's wrong with my XPath/XML?

后端 未结 3 500
梦如初夏
梦如初夏 2020-12-05 09:09

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

相关标签:
3条回答
  • 2020-12-05 09:32

    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);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-05 09:39

    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.

    0 讨论(0)
  • 2020-12-05 09:41

    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".

    0 讨论(0)
提交回复
热议问题