Powershell XML文档另存为无BOM的UTF-8

问题描述 投票:0回答:2

我构建了一个 System.Xml.XmlDocument 类型的 XML 对象。

$scheme.gettype()
IsPublic IsSerial Name BaseType                                                         
-------- -------- ---- --------                                                         
True     False    XmlDocument System.Xml.XmlNode 

我使用 save() 方法将其保存到文件中。

$scheme.save()

这会将文件保存为带 BOM 的 UTF-8 格式。 BOM 会导致其他脚本出现问题。

当我们在 Notepad++ 中打开 XML 文件并将其保存为 UTF-8(不含 BOM)时,其他脚本不会出现问题。所以我被要求保存没有 BOM 的脚本。

保存方法的 MS 文档指出:

encoding 属性的值取自 XmlDeclaration.Encoding 属性。如果 XmlDocument 没有 XmlDeclaration,或者 XmlDeclaration 没有编码属性,则保存的文档也将没有编码属性。

有关 XmlDeclaration 的 MS 文档列出了 UTF-8、UTF-16 等的编码属性。它没有提到 BOM。

XmlDeclaration 是否具有省略 BOM 的编码属性?

PS。此行为在 Powershell 5 和 Powershell 7 中是相同的。

.net powershell utf-8 byte-order-mark
2个回答
6
投票

不幸的是,当给定文件路径

时,XML 文档声明中存在
显式encoding="utf-8"
属性
会导致 .NET 的
[xml]
(System.Xml.XmlDocument
) 类型变为
.Save()文档,到 UTF-8 编码的文件使用 BOM,这 确实会导致问题(尽管它不应该[1])。

更改此项的请求原则上已经绿灯,但自 .NET 9.0 起尚未实现(由于有关将

[System.Text.Encoding]::UTF8
更改为使用 BOM 的更大讨论) ,在这种情况下
.Save()
也将自动不再创建 BOM)。

有点讽刺的是,encoding属性的

缺失
导致
.Save()
创建UTF-8编码的文件没有BOM

因此,一个简单的解决方案是删除编码属性[2];例如:

# Create a sample XML document:
$xmlDoc = [xml] '<?xml version="1.0" encoding="utf-8"?><foo>bar</foo>'

# Remove the 'encoding' attribute from the declaration.
# Without this, the .Save() method below would create a UTF-8 file *with* BOM.
$xmlDoc.ChildNodes[0].Encoding = $null

# Now, saving produces a UTf-8 file *without* a BOM.
$xmlDoc.Save("$PWD/out.xml")

[1] 根据 XML W3C 建议:“以 UTF-8 编码的实体可以以字节顺序标记开头”[BOM]。

[2] 这样做是安全的,因为在缺乏 BOM 和 encoding 属性的情况下,

XML W3C 建议
有效地强制将 UTF-8 作为默认值。


5
投票

正如 BACON 在注释中解释的那样,XML 声明中

Encoding
属性的字符串值与包含文档的文件的编码方式没有任何关系。

您可以通过创建

StreamWriter
或带有非 BOM
XmlWriter
UTF8Encoding
来控制这一点,然后将 that 传递给
Save($writer)

$filename = Resolve-Path path\to\output.xml

# Create UTF8Encoding instance, sans BOM
$encoding = [System.Text.UTF8Encoding]::new($false)

# Create StreamWriter instance
$writer = [System.IO.StreamWriter]::new($filename, $false, $encoding)

# Save using (either) writer
$scheme.Save($writer)

# Dispose of writer
$writer.Dispose()

或者使用

[XmlWriter]
:

# XmlWriter Example
$writer = [System.Xml.XmlWriter]::Create($filename, @{ Encoding = $encoding })

第二个参数是一个

[XmlWriterSettings]
对象,通过它,除了显式设置编码之外,我们还可以对格式选项进行更大的控制:

$settings = [System.Xml.XmlWriterSettings]@{
  Encoding = $encoding
  Indent = $true
  NewLineOnAttributes = $true
}
$writer = [System.Xml.XmlWriter]::Create($filename, $settings)

#  <?xml version="1.0" encoding="utf-8"?>
#  <Config>
#    <Group
#      name="PropertyGroup">
#      <Property
#        id="1"
#        value="Foo" />
#      <Property
#        id="2"
#        value="Bar"
#        exclude="false" />
#    </Group>
#  </Config>
© www.soinside.com 2019 - 2024. All rights reserved.