Как запросить файл XAML с помощью командной строки Powershell `select-xml`?

я пытаюсь использоватьselect-xmlкомандлет в Powershell для запроса некоторых файлов XAML в моем проекте .NET. Вот что я пробовал:

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

Где$xaml_file_path— это просто строка, содержащая путь к интересующему XAML-файлу.

Это вызывает ошибку:

Select-Xml: не удается проверить аргумент параметра «Содержимое». Аргумент имеет значение null, пуст или элемент коллекции аргументов содержит значение null. Укажите коллекцию, которая не содержит нулевых значений, а затем повторите команду.

Я знаю, что XAML действителен, поскольку он отлично компилируется в Visual Studio. Так что я думаю, что здесь может быть что-то еще.

Есть ли способ запросить файлы XAML с помощью Powershell? Если да, то как?

2 ответа

Чтобы запросить документ XML (XAML), использующий пространства имен , требует от вас : [1]

  • объявить все пространства имен , в которых находятсялюбые узлы, участвующие в вашем запросе XPath, с помощью хэш-таблицы, которая сопоставляет выбранные вами префиксы с URI пространства имен (параметр-Namespace).

    • Эти самостоятельно выбранные префиксы могут, но не обязательно, быть такими же, как во входном документе, за исключением пространства имен по умолчанию (), для которого также необходимо выбрать имя, но которое нельзя изменить .xmlns(пример ниже использует_).
  • использовать эти самостоятельно выбранные префиксы для всех узлов, на которые есть ссылки в запросе XPath (параметр-XPath), в том числе в пространстве имен по умолчанию (подразумеваемом).

Простой пример:

      # 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(а также лежащие в основе.NET), единственный способ избежать работы с пространствами имен — использовать метод *[local-name()='...'] обходной путь , показанный в вашем собственном ответе .

  • В контексте адаптации DOM PowerShell, которая добавляет «виртуальные» свойства к экземплярам[xml]( System.Xml.XmlDocument):

    • Эти свойства всегда именуются по именам узлов без префикса ; то есть пространства имен эффективно игнорируются .

    • Это удобно и часто достаточно, но ограничивает вас «детализацией» документа с точечной нотацией , в отличие от возможности выполнять запросы XPath к документу; для последнего можно использовать.SelectNodes()и.SelectSingleNode() методы , которые, однако, снова требуют управления пространством имен. [1]

    • Эквивалентный пример с точечной нотацией, основанный на том же файле примера:

                # 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 там немного более громоздко — см. этот ответ .

Я думаю, что аналогичноxmllintможет возникнуть проблема с обработкой пространств имен.

Я обнаружил, что работает следующее:

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

Если кто-нибудь знает более чистый/лучший способ сделать это (т.е. с помощью-namespaceфлаг), мне было бы любопытно услышать об этом.

Другие вопросы по тегам