如何在 C# 中使用 XPath 包含

Posted

技术标签:

【中文标题】如何在 C# 中使用 XPath 包含【英文标题】:How to use XPath contains in C# 【发布时间】:2021-04-05 14:49:35 【问题描述】:

我正在努力使用 XPATH 中的 contains(text,'some text')。

我看到了这个链接How to use XPath contains(),但由于某种原因对我不起作用

我需要删除项目引用,因此我只想使用“ProjectName”进行选择(不指定完整路径) 我从这个答案How do I use Powershell to add/remove references to a csproj? 中获取了一个脚本(请参阅 RemoveReference.ps1)

这是我的代码,也是一个小提琴https://dotnetfiddle.net/Cq5fa6

using System;
using System.Xml;
                    
public class Program

    public static void Main()
    
            //Declare the XML Document here
            XmlDocument Doc = new XmlDocument();

            //Load you xml here
            //Doc.LoadXml(TransportResponse.Response)
            Doc.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8""?>
<Project ToolsVersion=""15.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
  <ItemGroup>
    <ProjectReference Include=""..\ProjectReferencesToolkit.Core\ProjectReferencesToolkit.Core.csproj"">
      <Project>6c167ddd-7ce8-4087-9f8c-6986145b97d1</Project>
      <Name>ProjectReferencesToolkit.Core</Name>
    </ProjectReference>
  </ItemGroup>
  <Import Project=""$(MSBuildToolsPath)\Microsoft.CSharp.targets"" />
</Project>
");

//I need to use contains here to only search for ProjectReferencesToolkit.Core.csproj (not specifying full path)
var XPath = String.Format("//a:ProjectReference[@Include='0']","..\\ProjectReferencesToolkit.Core\\ProjectReferencesToolkit.Core.csproj");    
    var nsmgr = new XmlNamespaceManager(Doc.NameTable);
    nsmgr.AddNamespace("a","http://schemas.microsoft.com/developer/msbuild/2003");
    var node = Doc.SelectSingleNode(XPath, nsmgr);
        
Console.WriteLine(node.InnerXml);
        
    


【问题讨论】:

你知道,一般来说我会说这是一个坏主意......你如何将字符串转义为 xpath 字符串?假设文件名是My'Beautiful'Flower.csproj... 我没有那种 csproj 文件名。 如果你不在你的项目或文件夹中尝试一些有趣的名字,你作为程序员的生活一定很无聊:-) :-) 如果你不破坏资源管理器,你就是' t 甚至玩 :-) 【参考方案1】:

我认为这是个坏主意。在 XPath 中转义字符串很痛苦。

我正在做一个ends-with 而不是contains,这应该更适合你想要的。明明ends-with是XPath 2.0,.NET只支持1.0,所以只好用substring

string fileName = "ProjectReferencesToolkit.Core.csproj";
var XPath = string.Format("//a:ProjectReference[substring(@Include, string-length(@Include) - 0 + 1) = '1']", fileName.Length, fileName);

还有一点转义:

// https://***.com/a/38254661/613130
public static string EscapeXPathString(string value)

    if (!value.Contains("'"))
    
        return '\'' + value + '\'';
    
    else if (!value.Contains("\""))
    
        return '"' + value + '"';
    
    else
    
        return "concat('" + value.Replace("'", "',\"'\",'") + "')";
    

在xml中:

<ProjectReference Include=""..\ProjectReferencesToolkit.Core\ProjectReferencesToolkit&quot;'.Core.csproj"">

然后:

string fileName = @"ProjectReferencesToolkit""'.Core.csproj";
string fileNameEscaped = EscapeXPathString(fileName);
var XPath = string.Format("//a:ProjectReference[substring(@Include, string-length(@Include) - 0 + 1) = 1]", fileName.Length, fileNameEscaped);

(现在我已经摆脱了 XPath 字符串,我感觉好多了?)

【讨论】:

谢谢,我试试看告诉你【参考方案2】:

最好使用 LINQ to XML API。它自 2007 年起在 .Net Framework 中可用。

c#

void Main()

    XDocument xsdoc = XDocument.Parse(@"<?xml version='1.0' encoding='utf-8'?>
        <Project ToolsVersion='15.0'
                 xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
            <ItemGroup>
                <ProjectReference Include='..\ProjectReferencesToolkit.Core\ProjectReferencesToolkit.Core.csproj'>
                    <Project>6c167ddd-7ce8-4087-9f8c-6986145b97d1</Project>
                    <Name>ProjectReferencesToolkit.Core</Name>
                </ProjectReference>
            </ItemGroup>
            <Import Project='$(MSBuildToolsPath)\Microsoft.CSharp.targets'/>
        </Project>");
        
        string SearchFor = @"ProjectReferencesToolkit.Core.csproj";
        
        XNamespace ns = xsdoc.Root.GetDefaultNamespace();
        XElement xelem = xsdoc.Descendants(ns + "ProjectReference")
            .FirstOrDefault(x => x.Attribute("Include").Value.EndsWith(SearchFor));
        
        Console.WriteLine(xelem);

【讨论】:

以上是关于如何在 C# 中使用 XPath 包含的主要内容,如果未能解决你的问题,请参考以下文章

如何使用多个 XPath 查询在 c# 中选择单个 XML 节点

如何使用 C# 将 XSLT 更改为使用动态 XPath?

如何在 XPath“包含”函数中使用正则表达式

如何在 PHP 中使用 XPath 设置 (not(contains))

无论特定 Id 如何,如何使用 XPath 选择类别 XML 节点?

如何在 XPath 中使用“not”?