Reputation: 29919
Using PowerShell Core 7.4.6.
Given the file /path/to/file.csproj
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="Path\To\Something.csproj" />
</ItemGroup>
</Project>
I expect that the following snippet will select the ProjectReference
node from that file, using the built-in XPath ends-with
function
select-xml -path "/path/to/file.csproj" `
-xpath "/Project/ItemGroup/ProjectReference[ends-with(@Include, 'Something.csproj')]"
but instead it yields the error
Select-Xml: Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function.
If I try to explicitly scope it using the XPath function namespace
select-xml -path "/path/to/file.csproj" `
-xpath "/Project/ItemGroup/ProjectReference[fn:ends-with(@Include, 'Something.csproj')]" `
-namespace @{ "fn" = "http://www.w3.org/2005/xpath-functions" }
I get a different error
Select-Xml: XsltContext is needed for this query because of an unknown function.
What am I missing? The documentation for Select-Xml
mentions no limitations on invoking XPath functions, so I assume they are natively supported.
Upvotes: 1
Views: 71
Reputation: 27516
I think I've got Xpath 2.0 working with Saxon HE 10.9 for .net. You have to install that setup file first to get the dll. I haven't gotten downloading the dll through nuget working.
# https://github.com/Saxonica/Saxon-HE/blob/main/10/Dotnet/SaxonHE10-9N-setup.exe
Add-Type -Path "C:\Program Files\Saxonica\SaxonHE10.9N\bin\saxon-he-api-10.9.dll"
# Initialize Saxon Processor and Components
$processor = New-Object Saxon.Api.Processor
$documentBuilder = $processor.NewDocumentBuilder()
$xpathCompiler = $processor.NewXPathCompiler()
# Load XML Document
$doc = $documentBuilder.Build("$pwd\file.csproj")
# Compile the XPath Expression
$xpathExpression = $xpathCompiler.Compile(
"/Project/ItemGroup/ProjectReference[ends-with(@Include, 'Something.csproj')]")
# Create an XPath Selector
$xpathSelector = $xpathExpression.Load()
# Set the context for the XPath Selector
$xpathSelector.ContextItem = $doc
# Evaluate the XPath Expression
$result = $xpathSelector.Evaluate()
# Output Results
foreach ($item in $result) {
Write-Output $item.ToString()
}
Output:
<ProjectReference Include="Path\To\Something.csproj"/>
Upvotes: 0
Reputation: 329
Inspecting code of Select-Xml cmdlet I found out that internally it uses SelectNodes method of NET class System.Xml.XmlNode. Thus you can find list of recognized functions in this Microsoft XPath reference documentation: XPath Reference
Upvotes: 0
Reputation: 174825
The built-in XPath support in .NET only covers functions specified by XPath version 1.0/1.1 - and ends-with
was not part of XPath until version 2.
You can use substring
/string-length
to cut the tail of the string and look for that instead:
$tailValue = 'Something.csproject'
$xPathEndsWithExpression = "/Project/ItemGroup/ProjectReference[string-length(@Include) >= $($tailValue.Length) and substring(@Include, string-length(@Include) - $($tailValue.Length - 1)) = '${tailValue}')]"
Select-Xml -Path "/path/to/file.csproj" -XPath $xPathEndsWithExpression
Upvotes: 1