如何使用PowerShell的`select-xml`命令查询XAML文件?

kb5ga3dv  于 2022-11-10  发布在  Shell
关注(0)|答案(2)|浏览(119)

我正在尝试使用PowerShell中的select-xml cmdlet来查询.NET项目中的一些XAML文件。以下是我尝试过的:

select-xml -content (cat $xaml_file_path) -xpath "//GroupBox"

其中$xaml_file_path只是一个字符串,其中包含感兴趣的XAML文件的文件路径。
这将引发一个错误:
SELECT-XML:无法验证参数‘Content’上的参数。参数为Null、空,或者参数集合的某个元素包含Null值。请提供不包含任何null值的集合,然后重试该命令。
我知道XAML是有效的,因为它在Visual Studio上编译得很好。所以我在想,这里面可能有别的事情发生。
有没有办法使用PowerShell来查询XAML文件?如果是这样的话,是怎么做的?

7gs2gvoe

7gs2gvoe1#

要查询使用命名空间的XML(XAML)文档,Select-Xml要求您:[1]

  • 通过**hashtable自己选择的前缀Map到命名空间URI(参数-Namespace),声明您的XPath查询所涉及的所有命名空间**。
  • 那些自己选择的前缀可以但不一定与输入文档中的相同,但默认命名空间(xmlns)的例外,也必须为其选择一个名称,但不能*为xmlns(下面的示例使用_)。
  • 将这些自选前缀用于所有XPath查询中引用的节点**(参数-XPath),包括DEFAULT(隐含)命名空间中的节点。

一个简单的例子:


# Create a sample XAML file.

@"
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Test"
        Title="MainWindow" Height="450" Width="500">
    <Grid>
        <TextBox x:Name="UserInnput" Height="140" TextWrapping="Wrap" VerticalAlignment="Top" AcceptsReturn="True" AcceptsTab="True" Padding="4" VerticalScrollBarVisibility="Auto" />
        <Button x:Name="Save" Content="Save" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" IsDefault="True" Height="22" Margin="170,150,0,0" />        
    </Grid>
</Window>
"@ | Set-Content sample.xml

# Create the hashtable that uses self-chosen names to the URIs

# of those namespaces involved in the XPath query below.

$namespaces = @{ 
  # This is the default namespace, which the elements in the input
  # document that have *no* namespace prefix are *implicitly* in.
  # You must NOT use 'xmlns' as the prefix.
  _ = 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'
  # For non-default namespaces, you may choose the same prefixes 
  # as in the original document.
  # Note:
  #  * This namespace isn't actually used in the query below.
  #  * However, if the nodes involved in the query do fall into
  #    this or other namespaces, they must be declared here too,
  #    and their prefixes must then be used in the query.
  x = 'http://schemas.microsoft.com/winfx/2006/xaml' 
}

# Query the XAML file, passing the hashtable to -Namespace, and

# using its keys as namespace prefixes; here, '_:' must be used

# to refer to nodes in the default namespace.

Select-Xml -LiteralPath sample.xml -Namespace $namespaces -XPath '//_:TextBox'

如果您想避免处理命名空间

  • Select-Xml的上下文中(以及基础的System.Xml.XmlDocument.SelectNodes().NET方法),避免处理命名空间的唯一方法是使用your own answer中所示的*[local-name()='...']解决办法
  • PowerShell's adaption of the [xml] DOM**的上下文中,向[xml](System.Xml.XmlDocument)的示例添加“虚拟”属性
  • 这些属性总是无前缀节点名称命名;也就是说,名称空间实际上被忽略了
  • 这很方便,通常也足够了,但它限制了您在文档中使用*点符号“向下钻取”,而不是能够对文档运行XPath查询;对于后者,您可以使用.SelectNodes().SelectSingleNode()方法,但是,这同样需要名称空间管理。
  • 使用点符号的等效示例,基于相同的示例文件:

# Parse the XML file into an [xml] instance.

($doc = [xml]::new()).Load((Convert-Path sample.xml))

# Drill down to the <TextBox> element.

# Note: If the <Grid> element had *multiple* <TextBox> children,

# they would *all* be returned, as a System.Xml.XmlElement array.

$doc.Window.Grid.TextBox

[1]命名空间管理的需要类似于直接使用底层的System.Xml.XmlDocument.SelectNodes()System.Xml.XmlDocument.SelectSingleNodes().NET API,尽管构造前缀到URI的Map表有点麻烦-请参阅this answer

gcuhipw9

gcuhipw92#

我认为,类似于xmllint,可能有一个处理名称空间的issue
我发现以下方法确实有效:

(select-xml -path $xaml_file_path -xpath "//*[local-name()='GroupBox']").Node

如果有人知道一种更干净/更好的方法(即使用-namespace标志),我会很好奇。

相关问题