我的XPath / XML出了什么问题?

时间:2022-08-16 00:12:33

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

我在这个xml上尝试一个非常基本的XPath(与下面相同),它没有找到任何东西。我正在尝试.NET和这个网站,而像// PropertyGroup,/ PropertyGroup和// MSBuildCommunityTasksPath这样的XPath根本不适合我(他们编译但返回零结果)。

Source XML:

源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>

3 个解决方案

#1


16  

You can add namespaces in your code and all that, but you can effectively wildcard the namespace. Try the following XPath idiom.

您可以在代码中添加名称空间以及所有这些名称空间,但您可以有效地对命名空间进行通配符。尝试以下XPath习语。

//*[local-name()='PropertyGroup']
//*[local-name()='MSBuildCommunityTasksPath']

name() usually works as well, as in:

name()通常也可以,如下所示:

//*[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.

编辑:命名空间很棒,我并不是说它们不重要,但是在将原型代码,一次性桌面工具,XSLT试验等等拼凑在一起时,通配它们会派上用场。平衡您的方便需求与手头任务的可接受风险。仅供参考,如果需要,您还可以剥离或重新分配名称空间。

#2


2  

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.

文档中的标记最终位于由xmlns属性创建的“default”命名空间中,没有前缀。不幸的是,单独的XPath无法查询默认命名空间中的元素。我实际上不确定语义细节,但你必须使用托管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'):

在.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);
        }
    }
}

#3


1  

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

您的问题在于命名空间(xmlns =“http://schemas.microsoft.com/developer/msbuild/2003”)。您正在接收零节点,因为您没有使用命名空间限定它。如果删除xmlns属性,则“// PropertyGroup”XPath将起作用。如何使用命名空间查询通常涉及将默认xmlns别名化为标识符(因为未在属性上指定一个),并选择类似“// myXMLNStoken:PropertyGroup”。

#1


16  

You can add namespaces in your code and all that, but you can effectively wildcard the namespace. Try the following XPath idiom.

您可以在代码中添加名称空间以及所有这些名称空间,但您可以有效地对命名空间进行通配符。尝试以下XPath习语。

//*[local-name()='PropertyGroup']
//*[local-name()='MSBuildCommunityTasksPath']

name() usually works as well, as in:

name()通常也可以,如下所示:

//*[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.

编辑:命名空间很棒,我并不是说它们不重要,但是在将原型代码,一次性桌面工具,XSLT试验等等拼凑在一起时,通配它们会派上用场。平衡您的方便需求与手头任务的可接受风险。仅供参考,如果需要,您还可以剥离或重新分配名称空间。

#2


2  

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.

文档中的标记最终位于由xmlns属性创建的“default”命名空间中,没有前缀。不幸的是,单独的XPath无法查询默认命名空间中的元素。我实际上不确定语义细节,但你必须使用托管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'):

在.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);
        }
    }
}

#3


1  

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

您的问题在于命名空间(xmlns =“http://schemas.microsoft.com/developer/msbuild/2003”)。您正在接收零节点,因为您没有使用命名空间限定它。如果删除xmlns属性,则“// PropertyGroup”XPath将起作用。如何使用命名空间查询通常涉及将默认xmlns别名化为标识符(因为未在属性上指定一个),并选择类似“// myXMLNStoken:PropertyGroup”。