在 Powershell 中添加回车符 returns 以手动漂亮打印大型 XML 文件

Add carriage returns in Powershell to manually pretty-print a large XML file

我有一个非常大的 (280 Meg) xml 文件,所有文件都在一行中。我有几个编辑器 勉强 可以打开它,但没有什么能让我打印出来。

我正在尝试在 Powershell 中对其进行格式化,但一直无法弄清楚语法。为了使文件更具可读性,我想做的是用回车符 return + 换行符和结束标记替换所有结束标记,但我无法让它工作。

这是我目前尝试过的方法:

(get-content .\ReallyHugeXMLFile2.xml) -replace ('</','`n</') | out-file .\ReallyHugeXMLFile2Formatted.xml
(get-content .\ReallyHugeXMLFile2.xml) -replace ('</','\r\n</') | out-file .\ReallyHugeXMLFile2Formatted2.xml
(get-content .\ReallyHugeXMLFile2.xml) -replace ('</','\r\n</') | out-file .\ReallyHugeXMLFile2Formatted3.xml

谢谢

TheIncorrigible1在评论中给出了要害指针:

假设您的大型 XML 文件仍然可以作为一个整体 加载到 System.Xml.XmlDocument 实例中 ,您可以简单地调用它的 .Save() 方法来创建一个 漂亮打印的 输出文件(这避免了手动插入换行符的需要;此外,使用 XML 解析器总是比文本操作更可取) .

# Load the file into a [xml] (System.Xml.XmlDocument) instance...
($xmlDoc = New-Object xml).Load($PWD.ProviderPath + '/HugeFile.xml')
# ... and save it, which automatically pretty-prints it.
$xmlDoc.Save($PWD.ProviderPath + '/HugeFilePrettyPrinted.xml')

请注意,需要在文件名前添加 $PWD.ProviderPath 以确保 .NET 使用 PowerShell 的当前目录(.NET 通常不同,并且 .NET 不知道使用New-PSDrive).[1]

注意:生成的文件将只有 LF 换行符,而不是 CRLF 换行符。


一个可行性论证:

首先,运行以下代码 (PSv5+) 创建一个示例 XML 文件,大小约为 280 MB。 请注意,您可以轻松调整代码以指定不同的目标大小。

注:

  • 文件 HugeFile.xml 将在当前目录中创建,运行稍后使用漂亮打印命令会在相同的位置。

  • 创建此文件可能需要几分钟时间。

# Create a sample single-line XML file of a given size (approximately).
# Note: Depending on the target size, this can take a long time to complete.
#       Additionally, for performance reasons the code is written so that
#       the file content must fit into memory as a whole.

# The desired size of the resulting file.
$targetFileSize = 280mb
$targetFile = './HugeFile.xml'

# The XML element to repeat.
$repeatingElementTemplate = '<book><title>De Profundis {0:000000000000}</title></book>'
# Determine how often it must be repeated to reach the target size (approximately)
$repeatCount = $targetFileSize / ($repeatingElementTemplate.Length - 4)

Write-Verbose -vb "Creating XML file '$targetFile' of approximate size $('{0:N2}' -f ($targetFileSize / 1mb)) MB..."
# Create the file.
'<?xml version="1.0"?><catalog>' | Set-Content -NoNewline -Encoding Utf8 $targetFile
-join (1..$repeatCount).ForEach({ $repeatingElementTemplate -f $_ }) |
  Add-Content -NoNewline -Encoding Utf8 $targetFile
'</catalog>' | Add-Content -NoNewline -Encoding Utf8 $targetFile

然后运行上面的美化命令

在我的单核 Windows 10 VM 和 3GB RAM(在旧硬件上)上,这花了大约 40 秒。埃里克本人报告说他的机器上不到 5 秒。


[1] 确保将相对 PowerShell 文件系统路径正确传递给 .NET 方法:

  • 如前所述,.NET 的当前目录概念通常不同于 PowerShell,因此不能按原样使用 PowerShell 相对路径。

  • 使用 $PWD.ProviderPath ($PWD.ProviderPath + '<fileInCurrentDir>) 形成完整路径确保 PowerShell 的当前文件系统位置表示为 本机文件系统路径 (谢谢,TheIncorrigible1)。 .NET 方法只理解后者;他们不知道使用 New-PSDrive 创建的自定义 PowerShell 驱动器,他们不知道 PowerShell 的提供程序前缀表示法,当当前位置是 UNC 路径(例如,
    Microsoft.PowerShell.Core\FileSystem::\some-server\some-share\some-folder).

  • 如果您不使用自定义 PowerShell 驱动器,并且您不是 运行直接从 UNC 位置编译代码,则可以更简单地根据当前的位置
    "$PWD/<fileInCurrentDir>"

  • 相反,对于 完全稳健性,您必须使用
    (Get-Location -PSProvider FileSystem).ProviderPath + '/<fileInCurrentDir>',因为 PowerShell 的当前位置可能是一个来自文件系统提供者 other 的提供者;例如,HKCU:\Console(注册提供商)。