Powershell XMLDocument BOM olmadan UTF-8 olarak kaydedin

Aug 19 2020

System.Xml.XmlDocument türünde bir XML nesnesi oluşturdum.

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

Dosyayı kaydetmek için save () yöntemini kullanıyorum.

$scheme.save()

Bu, dosyayı BOM ile UTF-8 biçiminde kaydeder. BOM, diğer komut dosyalarıyla ilgili sorunlara neden olur.

XML dosyasını Notepad ++ ile açıp UTF-8 olarak kaydettiğimizde (BOM olmadan), satırın altındaki diğer betiklerin bir problemi olmaz. Bu yüzden BOM olmadan komut dosyasını kaydetmem istendi.

Save yöntem MS belgelerine devletler:

Kodlama özniteliğinin değeri, XmlDeclaration.Encoding özelliğinden alınır. XmlDocument bir XmlDeclaration'a sahip değilse veya XmlDeclaration'ın bir kodlama özniteliği yoksa, kaydedilen belgede bir tane de olmayacaktır.

XmlDeclaration MS belgeleri UTF-8, UTF-16 ve diğer özelliklerini kodlayan listeleri. Bir ürün reçetesinden bahsetmez.

XmlDeclaration, BOM'u dışarıda bırakan bir kodlama özelliğine sahip mi?

PS. Bu davranış Powershell 5 ve Powershell 7'de aynıdır.

Yanıtlar

2 mklement0 Aug 19 2020 at 09:39

Ne yazık ki, encoding="utf-8"bir XML belgesinin bildiriminde bir özniteliğin açık varlığı, .NET'in .Save()belgeye, bir hedef dosya yolu verilirse BOM ile UTF-8 kodlu bir dosyaya gitmesine neden olur ve bu da gerçekten sorunlara neden olabilir.

Geriye dönük uyumluluğu bozma korkusuyla bunu değiştirme isteği reddedildi; İşte en azından davranışı belgelemek için bir istek .

Biraz ironik bir şekilde, bir özniteliğin olmaması , BOM olmadan UTF-8 kodlu dosyaların oluşturulmasına encodingneden olur ..Save()

Bu nedenle basit bir çözüm, kodlama özniteliğini [1] kaldırmaktır ; Örneğin:

# 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] Bunu yapmak güvenlidir, çünkü XML W3C Önerisi , hem bir ürün reçetesi hem de bir encodingöznitelik olmadığında varsayılan olarak UTF-8'i etkin bir şekilde zorunlu kılar .

1 MathiasR.Jessen Aug 19 2020 at 05:20

BACON'un yorumlarda açıkladığı gibi Encoding, XML bildirimindeki özniteliğin dize değerinin , belgeyi içeren dosyanın nasıl kodlandığına dair herhangi bir ilgisi yoktur.

Ya bir oluşturarak bu kontrol edebilir StreamWriterya da XmlWriterolmayan bir BOM ile UTF8Encoding, daha sonra pas o kadar 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()

Alternatif olarak bir kullanın [XmlWriter]:

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

İkinci argüman, [XmlWriterSettings]kodlamayı açıkça ayarlamanın yanı sıra formatlama seçenekleri üzerinde daha fazla kontrol uygulayabileceğimiz bir nesnedir:

$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>