Powershell XMLDocument wird als UTF-8 ohne Stückliste gespeichert
Ich habe ein XML-Objekt vom Typ System.Xml.XmlDocument erstellt.
$scheme.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False XmlDocument System.Xml.XmlNode
Ich benutze die Methode save (), um es in einer Datei zu speichern.
$scheme.save()
Dadurch wird die Datei im Format UTF-8 mit Stückliste gespeichert. Die Stückliste verursacht später Probleme mit anderen Skripten.
Wenn wir die XML-Datei in Notepad ++ öffnen und als UTF-8 (ohne Stückliste) speichern, haben andere Skripte auf der ganzen Linie kein Problem. Deshalb wurde ich gebeten, das Skript ohne Stückliste zu speichern.
In der MS-Dokumentation für die Speichermethode heißt es:
Der Wert des Codierungsattributs wird aus der Eigenschaft XmlDeclaration.Encoding übernommen. Wenn das XmlDocument keine XmlDeclaration hat oder wenn die XmlDeclaration kein Codierungsattribut hat, hat das gespeicherte Dokument auch keine.
In der MS-Dokumentation zu XmlDeclaration sind die Codierungseigenschaften von UTF-8, UTF-16 und anderen aufgeführt. Eine Stückliste wird nicht erwähnt.
Verfügt die XmlDeclaration über eine Codierungseigenschaft, die die Stückliste auslässt?
PS. Dieses Verhalten ist in Powershell 5 und Powershell 7 identisch.
Antworten
Leider führt das explizite Vorhandensein eines encoding="utf-8"Attributs in der Deklaration eines XML-Dokuments dazu, dass .NET .Save()das Dokument in eine UTF-8-codierte Datei mit Stückliste umwandelt, wenn ein Zieldateipfad angegeben wird, was tatsächlich Probleme verursachen kann.
Ein Antrag auf Änderung wurde aus Angst vor einer Unterbrechung der Abwärtskompatibilität abgelehnt. Hier ist eine Anfrage , um zumindest das Verhalten zu dokumentieren .
Ironischerweise führt das Fehlen eines encodingAttributs dazu .Save(), dass UTF-8-codierte Dateien ohne Stückliste erstellt werden.
Eine einfache Lösung besteht daher darin , das Codierungsattribut [1] zu entfernen . z.B:
# 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] Dies ist sicher, da die XML W3C-Empfehlung UTF-8 effektiv als Standard vorschreibt, wenn weder eine Stückliste noch ein encodingAttribut vorhanden sind.
Wie BACON in den Kommentaren erklärt , hat der Zeichenfolgenwert des EncodingAttributs in der XML-Deklaration keinen Einfluss darauf, wie die Datei mit dem Dokument codiert wird.
Sie können dies steuern , indem entweder ein StreamWriteroder XmlWritermit einem nicht-BOM UTF8Encoding, passieren dann , dass an 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()
Alternativ können Sie Folgendes verwenden [XmlWriter]:
# XmlWriter Example
$writer = [System.Xml.XmlWriter]::Create($filename, @{ Encoding = $encoding })
Das zweite Argument ist ein [XmlWriterSettings]Objekt, mit dem wir zusätzlich zur explizit festgelegten Codierung eine bessere Kontrolle über die Formatierungsoptionen ausüben können:
$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>