如何将 XmlDocument 保存到 .csproj "formatted like Visual Studio",其中空元素保存在单独的行中?

How to save an XmlDocument to a .csproj "formatted like Visual Studio" where empty elements are saved on separate lines?

目前我已经创建了一个 PowerShell 脚本来处理数百个(是的,数百个)Visual Studio 项目并更新参考以保持一致性,这修复了一些细微的错误。这适用于能够 往返 99% 的 XML,这样 Visual Studio 中的后续编辑项目文件就不会引入其他更改。

但是,对于 XmlDocument.Save()EMPTY 元素在同一行上保存为一对..

<StartupObject></StartupObject>

..而不是 Visual Studio 项目编辑器 保存拆分为两行的 EMPTY 元素的方式 ..

<StartupObject>
</StartupObject>

这会导致在初始提交时出现不必要的噪音,随着程序员从 Visual Studio.

中更新项目,这些噪音将被重置

如何使用相同的格式规则 Visual Studio [至少截至 2017 年] 使用 Visual Studio [修改] XmlDocument 保存?

目前保存是使用显式 XmlWriterXmlWriterSettings 使用以下配置完成的:

$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设置,未修改的节点不受影响。但是,在这种情况下 "improperly formatted" 条目不固定,新节点没有应用正确的 indenting/formatting。

最好可以通过简单修改保存 and/or 设置而不是自定义编写器(因为脚本在 PowerShell 中)或一些 post-保存文本操作(这样感觉有点笨拙)。

虽然一般来说我认为您不应该使用正则表达式篡改 XML,但我也无法在 XmlWriter class 中找到任何会改变写入空元素的样式的设置。

我按照你想要的方式格式化它的唯一方法是让 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 = '<>{0}</>' -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>