Как я могу выполнить что-то вроде этого:
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
работает так, как ожидалось:
@ zett42 Нет, не используйте Get-Content
и преобразуйте результат в XML. Это единственная наиболее распространенная ошибка, которую я вижу, когда люди читают XML в PowerShell. Используйте $doc = New-Object xml; $doc.Load('path.to.xml');
. Это правильно работает с кодировками файлов. Использование Get-Content
успешно искажает ваши данные.
@ Томалак Даже с Get-Content -raw
?
@ zett42 Да, даже тогда. Смотрите мой ответ по сути.
@ Томалак Понял. Возможно, вам просто повезло, потому что большинство XML-документов имеют кодировку UTF-8, которая является кодировкой по умолчанию, используемой Get-Content
.
@zett42 Сейчас. Более ранние версии PS по умолчанию использовали любую кодировку «ANSI» по умолчанию, которая была в вашей системе, в Европе / США, вероятно, Windows-1252. Get-Content
обращает внимание на спецификацию, поэтому распознает UTF-16 без посторонней помощи, но загруженная из Интернета UTF-8 обычно не имеет спецификации. А Get-Content
продолжит разделывать «чужие» однобайтовые кодировки. В конце концов, это действительно удача, когда это работает. И совершенно необязательно полагаться на удачу с XML, когда обнаружение прозрачного кодирования является фундаментальной частью спецификации.
Правильное чтение XML-документа в Powershell работает следующим образом:
$doc = New-Object xml
$doc.Load( (Convert-Path bookstore.xml) )
XML может иметь множество кодировок файлов, и использование метода XmlDocument.Load гарантирует, что файл будет правильно прочитан без предварительного знания кодировки.
Не чтение файла с правильной кодировкой приведет к искаженным данным или ошибкам, за исключением очень простых или очень удачных случаев.
Часто встречающийся метод использования Get-Content
и приведения результирующей строки к [xml]
является неправильным способом работы с XML именно по этой причине. Так что не делай этого.
Вы можете получить правильный результат с помощью Get-Content
, но для этого требуется
Get-Content bookstore.xml -Encoding UTF8
)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 Что ты хочешь красиво распечатать? Значения из XML? Сам XML? Какова общая цель, которую вы хотите достичь?
было бы удобно распечатать необработанный xml (как с xmlint), если это встроено в powershell. см. также stackoverflow.com/q/65264292/4531180 для конечной цели. (печать xml будет просто для удобства.)
Я бы добавил, что метод Get-Content
в большинстве случаев обходится безнаказанно только потому, что большинство XML-документов имеют кодировку UTF-8, которая является кодировкой по умолчанию, используемой Get-Content
. Конечно, это плохое «программирование наугад», и его следует избегать. Я думаю, что большинство людей используют его, потому что им нравятся остроты. Поэтому, если бы мы могли предоставить однострочный текст для правильного метода, это могло бы побудить больше людей использовать его.
@Nicholas PowerShell работает поверх .NET. Все, что можно сделать с помощью .NET, можно сделать с помощью PowerShell, плюс-минус. Напечатать красивый XML, конечно, можно, но я сомневаюсь, что это то, что вам действительно нужно. Вы хотите каким-то образом работать с содержащимися значениями, а вывести красивую таблицу значений проще и полезнее, чем распечатать XML-дерево с отступами. Я добавлю пример в свой ответ.
Смущает, как много руководств и даже высоко оцененных ответов SO продвигают неправильный метод Get-Content
. напр. stackoverflow.com/a/18509715/7571258
смотрите также: powershellmagazine.com/2013/08/19/…
@ zett42 Это действительно зависит от того, заботитесь ли вы о написании правильного кода или нет. Какой самый лучший однострочный, самый быстрый цикл, самый быстрый поворот, чтобы срезать ценность, когда результат неверен? Люди используют Get-Content
не потому, что это однострочник, а потому, что они не заботятся (или не знают) о кодировках, потому что это всегда работало на их машинах, и потому что это повсюду в Интернете, и они просто копировали и вставляли это как остальная часть их кода. ;) Но $doc = New-Object xml; $doc.Load($path)
(или $doc = [xml]::new(); $doc.Load($path)
) помещается в одну строку, вот и все.
@ zett42 И да, смущает, как часто люди ошибаются в этом. На самом деле это безнадежная борьба, такая же безнадежная, как попытка распространить информацию о том, что регулярное выражение не может обрабатывать HTML и что каждая минута попыток сделать это в любом случае тратится впустую. Слишком много плохих примеров.
Для меня предпочтительнее был бы однострочный лайнер. Select-Xml -Path
подходит близко, но, как ни странно, похоже, имеет ту же проблему с кодировкой, что и Get-Content
(только что протестировано с XML-файлом с кодировкой «windows-1251», содержащим кириллические буквы, что не является проблемой для метода [xml]::Load()
).
@zett42 Это потрясающе! Я никогда не пробовал, но Select-Xml
на самом деле все портит (я пробовал, моя версия PS 5.1.18362). Это настоящая ошибка в PowerShell, и к тому же досадная.
... что касается "способности к трубке" - в сценарии я не думаю, что наличие еще одной строки является огромным недостатком. Непосредственно в командной строке для одноразовых... Я бы назвал это небольшим неудобством. В целом, знание правил необходимо для того, чтобы знать, когда вы можете их нарушить.
Я создал отчет об ошибке для Select-Xml
проблемы с кодировкой: github.com/PowerShell/PowerShell/issues/14404
@mklement0 Может ли XmlDocument.Load()
обрабатывать спецификации дисков PowerShell?
Нет, API-интерфейсы .NET ничего не знают о дисках PowerShell (и механизм PowerShell не пытается преобразовать их для вызовов методов). Большая проблема заключается в отсутствии синхронизации рабочих каталогов. между PowerShell и .NET — см. github.com/PowerShell/PowerShell/issues/3428 — что само по себе требует передачи полных путей к методам .NET, и Convert-Path
является подходящим инструментом для этого из-за разрешения собственного пути — могу ли я предложить вам обновить свой ответ соответственно?
@mklement0 А, понял. Именно по этой причине я использовал Resolve-Path
, интересно узнать, что это неправильный инструмент. Иди и редактируй!
@zett42, делать то, что здесь, несомненно, является правильным и наиболее надежным, действительно настолько громоздко и неясно, что люди будут продолжать использовать ярлык [xml] (Get-Content -Raw ...)
, если мы не предоставим идиоматическую альтернативу PowerShell, которая одновременно надежна и удобна: см. github.com/PowerShell/PowerShell/issues/14505
$xml = [xml]( Get-Content .\bookstore.xml -raw ); $xml | Select-Xml YourXPath