PowershellXMLDocumentはBOMなしでUTF-8として保存

Aug 19 2020

System.Xml.XmlDocumentタイプのXMLオブジェクトを作成しました。

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

save()メソッドを使用してファイルに保存します。

$scheme.save()

これにより、ファイルがBOM付きのUTF-8形式で保存されます。BOMは、他のスクリプトで問題を引き起こします。

XMLファイルをNotepad ++で開き、UTF-8(BOMなし)として保存する場合、他のスクリプトに問題はありません。そのため、BOMなしでスクリプトを保存するように求められました。

saveメソッドのMSドキュメントには、次のように記載されています。

encoding属性の値は、XmlDeclaration.Encodingプロパティから取得されます。XmlDocumentにXmlDeclarationがない場合、またはXmlDeclarationにエンコード属性がない場合、保存されたドキュメントにもエンコード属性はありません。

XMLDECLARATIONオンMSドキュメントUTF-8、UTF-16などの特性をコードリスト。BOMについては触れていません。

XmlDeclarationには、BOMを除外するエンコーディングプロパティがありますか?

PS。この動作は、Powershell5とPowershell7で同じです。

回答

2 mklement0 Aug 19 2020 at 09:39

残念ながら、encoding="utf-8"XMLドキュメントの宣言に属性が明示的に存在すると、ターゲットファイルパスが指定されている場合、.NETから.Save()ドキュメントへのUTF-8エンコードファイルへのBOMが発生し、実際に問題が発生する可能性があります。

これを変更する要求は、下位互換性を損なうことを恐れて拒否されました。少なくとも動作を文書化するためのリクエストがあります。

皮肉なことに、encoding属性がないと、BOMなしで.Save()UTF-8でエンコードされたファイルが作成されます。

したがって、簡単な解決策は、エンコーディング属性を削除することです[1]。例えば:

# 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勧告では、BOMとencoding属性の両方がない場合、デフォルトとしてUTF-8が効果的に義務付けられているため、これは安全に実行できます。

1 MathiasR.Jessen Aug 19 2020 at 05:20

以下のようBACONはコメントで説明して、文字列値EncodingXML宣言の属性は、文書を含むファイルのエンコード方法上の任意のベアリングを持っていません。

あなたはどちらか作成することによって、これを制御することができますStreamWriterまたはXmlWriter非BOMでUTF8Encoding、その後、渡すことをするには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 })

2番目の引数は[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>