Powershell XMLDocument บันทึกเป็น UTF-8 โดยไม่มี BOM

Aug 19 2020

ฉันสร้างอ็อบเจ็กต์ XML ประเภท System.Xml.XmlDocument

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

ฉันใช้วิธีบันทึก () เพื่อบันทึกลงในไฟล์

$scheme.save()

ซึ่งจะบันทึกไฟล์ในรูปแบบ UTF-8 ด้วย BOM BOM ทำให้เกิดปัญหากับสคริปต์อื่น ๆ ในบรรทัด

เมื่อเราเปิดไฟล์ XML ใน Notepad ++ และบันทึกเป็น UTF-8 (โดยไม่มี BOM) สคริปต์อื่น ๆ ในบรรทัดจะไม่มีปัญหา ดังนั้นฉันจึงถูกขอให้บันทึกสคริปต์โดยไม่มี BOM

เอกสาร MS สำหรับวิธีการบันทึกฯ :

ค่าของแอตทริบิวต์การเข้ารหัสนำมาจากคุณสมบัติ XmlDeclaration.Encoding ถ้า XmlDocument ไม่มี XmlDeclaration หรือถ้า XmlDeclaration ไม่มีแอ็ตทริบิวต์การเข้ารหัสเอกสารที่บันทึกไว้จะไม่มีอย่างใดอย่างหนึ่ง

เอกสาร MS ใน XmlDeclarationรายการเข้ารหัสคุณสมบัติของ UTF-8, UTF-16 และอื่น ๆ ไม่ได้กล่าวถึง BOM

XmlDeclaration มีคุณสมบัติการเข้ารหัสที่ทำให้ BOM หลุดออกไปหรือไม่

ปล. ลักษณะการทำงานนี้เหมือนกันใน Powershell 5 และ Powershell 7

คำตอบ

2 mklement0 Aug 19 2020 at 09:39

น่าเสียดายที่การมีอยู่อย่างชัดเจนของencoding="utf-8"แอ็ตทริบิวต์ในการประกาศเอกสาร XML ทำให้. NET ไป.Save()ยังเอกสารเป็นไฟล์ที่เข้ารหัส UTF-8 ด้วย BOMหากกำหนดพา ธ ไฟล์เป้าหมายซึ่งอาจทำให้เกิดปัญหาได้

คำขอให้เปลี่ยนแปลงนี้ถูกปฏิเสธเพราะกลัวว่าจะทำลายความเข้ากันได้ย้อนหลัง นี่คือคำร้องขอให้บันทึกพฤติกรรมอย่างน้อยที่สุด

ค่อนข้างแดกดันที่ขาดของencodingแอตทริบิวต์ที่ทำให้เกิด.Save()การสร้างไฟล์ UTF-8 เข้ารหัสโดยไม่ต้อง BOM

ดังนั้นวิธีแก้ไขง่ายๆคือการลบแอตทริบิวต์การเข้ารหัส[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กำหนดให้ UTF-8 เป็นค่าเริ่มต้นอย่างมีประสิทธิภาพหากไม่มีทั้ง BOM และencodingแอตทริบิวต์

1 MathiasR.Jessen Aug 19 2020 at 05:20

ตามที่BACON อธิบายไว้ในความคิดเห็นค่าสตริงของEncodingแอตทริบิวต์ในการประกาศ XML ไม่มีผลต่อการเข้ารหัสไฟล์ที่มีเอกสาร

คุณสามารถควบคุมโดยการสร้างอย่างใดอย่างหนึ่ง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 })

อาร์กิวเมนต์ที่สองคือ[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>