Как загрузить или прочитать файл XML с помощью ConvertTo-Xml и Select-Xml?

Как я могу выполнить что-то вроде этого:

PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $date=(Get-Date | ConvertTo-Xml)                                         
PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $date

xml                            Objects
---                            -------
version = "1.0" encoding = "utf-8" Objects

PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $date.OuterXml
<?xml version = "1.0" encoding = "utf-8"?><Objects><Object Type = "System.DateTime">12/12/2020 2:43:46 AM</Object></Objects>
PS /home/nicholas/powershell> 

но вместо этого чтение в файле?


как загрузить/импортировать/прочитать/преобразовать файл xml, используя ConvertTo-Xml, для анализа с помощью Select-Xml, используя Xpath?

PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $xml=ConvertTo-Xml ./bookstore.xml
PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $xml                              

xml                            Objects
---                            -------
version = "1.0" encoding = "utf-8" Objects

PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $xml.InnerXml                     
<?xml version = "1.0" encoding = "utf-8"?><Objects><Object Type = "System.String">./bookstore.xml</Object></Objects>
PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> $xml.OuterXml                     
<?xml version = "1.0" encoding = "utf-8"?><Objects><Object Type = "System.String">./bookstore.xml</Object></Objects>
PS /home/nicholas/powershell> 
PS /home/nicholas/powershell> cat ./bookstore.xml

<?xml version = "1.0"?>
<!-- A fragment of a book store inventory database -->
<bookstore xmlns:bk = "urn:samples">
  <book genre = "novel" publicationdate = "1997" bk:ISBN = "1-861001-57-8">
    <title>Pride And Prejudice</title>
    <author>
      <first-name>Jane</first-name>
      <last-name>Austen</last-name>
    </author>
    <price>24.95</price>
  </book>
  <book genre = "novel" publicationdate = "1992" bk:ISBN = "1-861002-30-1">
    <title>The Handmaid's Tale</title>
    <author>
      <first-name>Margaret</first-name>
      <last-name>Atwood</last-name>
    </author>
    <price>29.95</price>
  </book>
  <book genre = "novel" publicationdate = "1991" bk:ISBN = "1-861001-57-6">
    <title>Emma</title>
    <author>
      <first-name>Jane</first-name>
      <last-name>Austen</last-name>
    </author>
    <price>19.95</price>
  </book>
  <book genre = "novel" publicationdate = "1982" bk:ISBN = "1-861001-45-3">
    <title>Sense and Sensibility</title>
    <author>
      <first-name>Jane</first-name>
      <last-name>Austen</last-name>
    </author>
    <price>19.95</price>
  </book>
</bookstore>

PS /home/nicholas/powershell> 

Создание файла xml в самой консоли REPL работает так, как ожидалось:

Как парсить XML в Powershell с помощью Select-Xml и Xpath?

$xml = [xml]( Get-Content .\bookstore.xml -raw ); $xml | Select-Xml YourXPath
zett42 12.12.2020 11:47

@ zett42 Нет, не используйте Get-Content и преобразуйте результат в XML. Это единственная наиболее распространенная ошибка, которую я вижу, когда люди читают XML в PowerShell. Используйте $doc = New-Object xml; $doc.Load('path.to.xml');. Это правильно работает с кодировками файлов. Использование Get-Content успешно искажает ваши данные.

Tomalak 12.12.2020 11:53

@ Томалак Даже с Get-Content -raw?

zett42 12.12.2020 12:01

@ zett42 Да, даже тогда. Смотрите мой ответ по сути.

Tomalak 12.12.2020 12:08

@ Томалак Понял. Возможно, вам просто повезло, потому что большинство XML-документов имеют кодировку UTF-8, которая является кодировкой по умолчанию, используемой Get-Content.

zett42 12.12.2020 12:18

@zett42 Сейчас. Более ранние версии PS по умолчанию использовали любую кодировку «ANSI» по умолчанию, которая была в вашей системе, в Европе / США, вероятно, Windows-1252. Get-Content обращает внимание на спецификацию, поэтому распознает UTF-16 без посторонней помощи, но загруженная из Интернета UTF-8 обычно не имеет спецификации. А Get-Content продолжит разделывать «чужие» однобайтовые кодировки. В конце концов, это действительно удача, когда это работает. И совершенно необязательно полагаться на удачу с XML, когда обнаружение прозрачного кодирования является фундаментальной частью спецификации.

Tomalak 12.12.2020 12:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
3 297
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Правильное чтение XML-документа в Powershell работает следующим образом:

$doc = New-Object xml
$doc.Load( (Convert-Path bookstore.xml) )

XML может иметь множество кодировок файлов, и использование метода XmlDocument.Load гарантирует, что файл будет правильно прочитан без предварительного знания кодировки.

Не чтение файла с правильной кодировкой приведет к искаженным данным или ошибкам, за исключением очень простых или очень удачных случаев.

Часто встречающийся метод использования Get-Content и приведения результирующей строки к [xml] является неправильным способом работы с XML именно по этой причине. Так что не делай этого.

Вы можете получить правильный результат с помощью Get-Content, но для этого требуется

  1. Предварительное знание кодировки файла (например, Get-Content bookstore.xml -Encoding UTF8)
  2. Жестко закодируйте кодировку файла в свой сценарий (это означает, что он сломается, если кодировка XML когда-либо неожиданно изменится)
  3. Ограничение себя очень немногими кодировками файлов, которые поддерживает Get-Content (XML поддерживает больше)

Это означает, что вы ставите себя в положение, когда вам приходится вручную обдумывать и решать проблему, для которой XML был специально разработан для автоматического решения за вас.

Делать что-то правильно с Get-Content — это много ненужной дополнительной работы и ограничений. И делать что-то неправильно бессмысленно, когда сделать это правильно так просто.


Примеры после загрузки $doc, как показано выше.

$doc.bookstore.book

печатает список элементов <book> и их свойств

genre           : novel
publicationdate : 1997
ISBN            : 1-861001-57-8
title           : Pride And Prejudice
author          : author
price           : 24.95

genre           : novel
publicationdate : 1992
ISBN            : 1-861002-30-1
title           : The Handmaid's Tale
author          : author
price           : 29.95

genre           : novel
publicationdate : 1991
ISBN            : 1-861001-57-6
title           : Emma
author          : author
price           : 19.95

genre           : novel
publicationdate : 1982
ISBN            : 1-861001-45-3
title           : Sense and Sensibility
author          : author
price           : 19.95

$doc.bookstore.book | Format-Table

печатает то же самое, что и таблица

genre publicationdate ISBN          title                 author price
----- --------------- ----          -----                 ------ -----
novel 1997            1-861001-57-8 Pride And Prejudice   author 24.95
novel 1992            1-861002-30-1 The Handmaid's Tale   author 29.95
novel 1991            1-861001-57-6 Emma                  author 19.95
novel 1982            1-861001-45-3 Sense and Sensibility author 19.95

$doc.bookstore.book | Where-Object publicationdate -lt 1992 | Format-Table

фильтрует данные

genre publicationdate ISBN          title                 author price
----- --------------- ----          -----                 ------ -----
novel 1991            1-861001-57-6 Emma                  author 19.95
novel 1982            1-861001-45-3 Sense and Sensibility author 19.95

$doc.bookstore.book | Where-Object publicationdate -lt 1992 | Sort publicationdate | select title

сортирует и печатает только поле <title>

title                
-----                
Sense and Sensibility
Emma

Существует множество других способов нарезки и нарезки данных, все зависит от того, что вы хотите сделать.

но теперь это все в онлайн-тексте, и его довольно трудно читать. Как красиво распечатать?

Nicholas Saunders 12.12.2020 12:07

@Nicholas Что ты хочешь красиво распечатать? Значения из XML? Сам XML? Какова общая цель, которую вы хотите достичь?

Tomalak 12.12.2020 12:14

было бы удобно распечатать необработанный xml (как с xmlint), если это встроено в powershell. см. также stackoverflow.com/q/65264292/4531180 для конечной цели. (печать xml будет просто для удобства.)

Nicholas Saunders 12.12.2020 12:19

Я бы добавил, что метод Get-Content в большинстве случаев обходится безнаказанно только потому, что большинство XML-документов имеют кодировку UTF-8, которая является кодировкой по умолчанию, используемой Get-Content. Конечно, это плохое «программирование наугад», и его следует избегать. Я думаю, что большинство людей используют его, потому что им нравятся остроты. Поэтому, если бы мы могли предоставить однострочный текст для правильного метода, это могло бы побудить больше людей использовать его.

zett42 12.12.2020 12:25

@Nicholas PowerShell работает поверх .NET. Все, что можно сделать с помощью .NET, можно сделать с помощью PowerShell, плюс-минус. Напечатать красивый XML, конечно, можно, но я сомневаюсь, что это то, что вам действительно нужно. Вы хотите каким-то образом работать с содержащимися значениями, а вывести красивую таблицу значений проще и полезнее, чем распечатать XML-дерево с отступами. Я добавлю пример в свой ответ.

Tomalak 12.12.2020 12:31

Смущает, как много руководств и даже высоко оцененных ответов SO продвигают неправильный метод Get-Content. напр. stackoverflow.com/a/18509715/7571258

zett42 12.12.2020 12:49

смотрите также: powershellmagazine.com/2013/08/19/…

Nicholas Saunders 12.12.2020 12:51

@ zett42 Это действительно зависит от того, заботитесь ли вы о написании правильного кода или нет. Какой самый лучший однострочный, самый быстрый цикл, самый быстрый поворот, чтобы срезать ценность, когда результат неверен? Люди используют Get-Content не потому, что это однострочник, а потому, что они не заботятся (или не знают) о кодировках, потому что это всегда работало на их машинах, и потому что это повсюду в Интернете, и они просто копировали и вставляли это как остальная часть их кода. ;) Но $doc = New-Object xml; $doc.Load($path) (или $doc = [xml]::new(); $doc.Load($path)) помещается в одну строку, вот и все.

Tomalak 12.12.2020 13:02

@ zett42 И да, смущает, как часто люди ошибаются в этом. На самом деле это безнадежная борьба, такая же безнадежная, как попытка распространить информацию о том, что регулярное выражение не может обрабатывать HTML и что каждая минута попыток сделать это в любом случае тратится впустую. Слишком много плохих примеров.

Tomalak 12.12.2020 13:04

Для меня предпочтительнее был бы однострочный лайнер. Select-Xml -Path подходит близко, но, как ни странно, похоже, имеет ту же проблему с кодировкой, что и Get-Content (только что протестировано с XML-файлом с кодировкой «windows-1251», содержащим кириллические буквы, что не является проблемой для метода [xml]::Load()).

zett42 12.12.2020 16:52

@zett42 Это потрясающе! Я никогда не пробовал, но Select-Xml на самом деле все портит (я пробовал, моя версия PS 5.1.18362). Это настоящая ошибка в PowerShell, и к тому же досадная.

Tomalak 12.12.2020 17:15

... что касается "способности к трубке" - в сценарии я не думаю, что наличие еще одной строки является огромным недостатком. Непосредственно в командной строке для одноразовых... Я бы назвал это небольшим неудобством. В целом, знание правил необходимо для того, чтобы знать, когда вы можете их нарушить.

Tomalak 12.12.2020 17:29

Я создал отчет об ошибке для Select-Xml проблемы с кодировкой: github.com/PowerShell/PowerShell/issues/14404

zett42 12.12.2020 19:48

@mklement0 Может ли XmlDocument.Load() обрабатывать спецификации дисков PowerShell?

Tomalak 28.12.2020 08:52

Нет, API-интерфейсы .NET ничего не знают о дисках PowerShell (и механизм PowerShell не пытается преобразовать их для вызовов методов). Большая проблема заключается в отсутствии синхронизации рабочих каталогов. между PowerShell и .NET — см. github.com/PowerShell/PowerShell/issues/3428 — что само по себе требует передачи полных путей к методам .NET, и Convert-Path является подходящим инструментом для этого из-за разрешения собственного пути — могу ли я предложить вам обновить свой ответ соответственно?

mklement0 28.12.2020 13:50

@mklement0 А, понял. Именно по этой причине я использовал Resolve-Path, интересно узнать, что это неправильный инструмент. Иди и редактируй!

Tomalak 28.12.2020 14:16

@zett42, делать то, что здесь, несомненно, является правильным и наиболее надежным, действительно настолько громоздко и неясно, что люди будут продолжать использовать ярлык [xml] (Get-Content -Raw ...), если мы не предоставим идиоматическую альтернативу PowerShell, которая одновременно надежна и удобна: см. github.com/PowerShell/PowerShell/issues/14505

mklement0 28.12.2020 14:52

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