Как сохранить XmlDocument в .csproj, «отформатированный как Visual Studio», где пустые элементы сохраняются в отдельных строках? - PullRequest
0 голосов
/ 05 октября 2019

В настоящее время я создал сценарий PowerShell для прохождения сотен (да, сотен) проектов Visual Studio и обновления ссылок для согласованности, которая исправляет ряд тонких ошибок. Это работает для возможности туда-обратно 99% XML, так что последующее редактирование файлов проекта в Visual Studio не вносит другого изменения.

Однако при XmlDocument.Save(), EMPTY элементы сохраняются в виде пары в одной строке ..

<StartupObject></StartupObject>

.. вместо способа, которым редактор проекта Visual Studio сохраняет элемент EMPTY, разделенный на две строки ..

<StartupObject>
</StartupObject>

Это приводит к ненужному шуму при начальном коммите, который будет сброшен при обновлении проектов программистами из Visual Studio.

Как можно [изменить] XmlDocument сохраняются с использованием тех же правил форматирования, которые использует Visual Studio [по крайней мере с 2017 года]?

В настоящее время сохранение выполняется с использованием явных XmlWriter и XmlWriterSettings с использованием следующей конфигурации:

$writerSettings = New-Object System.Xml.XmlWriterSettings
$writerSettings.Indent = $true
$writerSettings.IndentChars = $indent # value stolen previously

$writer = [System.Xml.XmlWriter]::Create($path, $writerSettings)
$xml.Save($writer)

При использовании параметра XmlDocument.PreserveWhitespace неизмененные узлы не затрагиваются. Тем не менее, в этом случае «неправильно отформатированные» записи не являются фиксированными, а новые узлы не имеют правильного отступа / форматирования.

Предпочтительно это может быть выполнено с простой модификацией сохранения и / или настроек вместо пользовательскихписатель (будучи сценарием в PowerShell) или какие-то манипуляции с текстом после сохранения (как таковые ощущаются как нечто вроде клуджа).

1 Ответ

1 голос
/ 06 октября 2019

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

Единственный способ, которым я получилон отформатирован так, как вы хотите, чтобы XmlWriter записывал в поток памяти и использовал регулярное выражение -replace для этого:

$writerSettings             = New-Object System.Xml.XmlWriterSettings
$writerSettings.Indent      = $true
$writerSettings.IndentChars = '  '
$writerSettings.Encoding    = New-Object System.Text.UTF8Encoding $false  # set to UTF-8 No BOM

# create a stream object to write to
$stream = New-Object System.IO.MemoryStream

$writer = [System.Xml.XmlWriter]::Create($stream, $writerSettings)
$writer.WriteStartDocument()
$writer.WriteStartElement("Root")
$writer.WriteElementString("StartupObject", [string]::Empty)
$writer.WriteElementString("AnotherEmptyElement", [string]::Empty)
$writer.WriteEndElement()
$writer.WriteEndDocument()
$writer.Flush()
$writer.Dispose()

# get whatever is written to the stream in a string variable
$xml = [System.Text.Encoding]::Default.GetString(($stream.ToArray()))

# replace self-closing elements: <StartupObject />
# replace empty elements in one line: <StartupObject></StartupObject>
# to the format where opening and closing tags are on separate lines
$format = '$1<$2>{0}$1</$2>' -f [Environment]::NewLine
$xml = $xml -replace '(.*?)<(.*?)\s*/>', $format -replace '(.*?)<(.*?)></(.*?)>', $format

# save do disk
$xml | Out-File -FilePath 'D:\test.xml' -Force -Encoding default

Результат:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <StartupObject>
  </StartupObject>
  <AnotherEmptyElement>
  </AnotherEmptyElement>
</Root>
...