Powershell XMLDocument salva come UTF-8 senza BOM
Ho costruito un oggetto XML di tipo System.Xml.XmlDocument.
$scheme.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False XmlDocument System.Xml.XmlNode
Uso il metodo save () per salvarlo in un file.
$scheme.save()
Questo salva il file in formato UTF-8 con BOM. La distinta componenti causa problemi con altri script su tutta la linea.
Quando apriamo il file XML in Notepad ++ e lo salviamo come UTF-8 (senza BOM), gli altri script su tutta la linea non hanno problemi. Quindi mi è stato chiesto di salvare lo script senza la distinta componenti.
La documentazione MS per il metodo di salvataggio afferma:
Il valore dell'attributo di codifica viene preso dalla proprietà XmlDeclaration.Encoding. Se XmlDocument non dispone di XmlDeclaration o se XmlDeclaration non dispone di un attributo di codifica, neanche il documento salvato ne avrà uno.
La documentazione MS su XmlDeclaration elenca le proprietà di codifica di UTF-8, UTF-16 e altri. Non menziona un BOM.
La XmlDeclaration ha una proprietà di codifica che esclude la BOM?
PS. Questo comportamento è identico in Powershell 5 e Powershell 7.
Risposte
Sfortunatamente, la presenza esplicita di un encoding="utf-8"
attributo nella dichiarazione di un documento XML fa sì che .NET .Save()
sul documento diventi un file con codifica UTF-8 con BOM se viene fornito un percorso del file di destinazione, il che può effettivamente causare problemi.
Una richiesta di modifica è stata respinta per paura di rompere la compatibilità con le versioni precedenti; ecco una richiesta per documentare almeno il comportamento.
Un po 'ironicamente, l' assenza di un encoding
attributo causa la .Save()
creazione di file con codifica UTF-8 senza BOM.
Una soluzione semplice è quindi rimuovere l'attributo di codifica [1] ; per esempio:
# 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] Questo è sicuro, perché la raccomandazione XML W3C impone di fatto UTF-8 come impostazione predefinita in assenza sia di una distinta materiali che di un encoding
attributo.
Come spiega BACON nei commenti , il valore stringa Encoding
dell'attributo nella dichiarazione XML non ha alcuna relazione con il modo in cui il file contenente il documento è codificato.
È possibile controllare questo creando sia un StreamWriter
o un XmlWriter
con un non-BOM UTF8Encoding
, quindi passare che per 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()
In alternativa usa un [XmlWriter]
:
# XmlWriter Example
$writer = [System.Xml.XmlWriter]::Create($filename, @{ Encoding = $encoding })
Il secondo argomento è un [XmlWriterSettings]oggetto, attraverso il quale possiamo esercitare un maggiore controllo sulle opzioni di formattazione oltre a impostare esplicitamente la codifica:
$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>