Powershell XMLDocument сохранить как UTF-8 без спецификации
Я построил объект XML типа System.Xml.XmlDocument.
$scheme.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False XmlDocument System.Xml.XmlNode
Я использую метод save (), чтобы сохранить его в файл.
$scheme.save()
Это сохраняет файл в формате UTF-8 с BOM. Спецификация вызывает проблемы с другими скриптами в дальнейшем.
Когда мы открываем XML-файл в Notepad ++ и сохраняем его как UTF-8 (без спецификации), другие скрипты в дальнейшем не имеют проблем. Поэтому меня попросили сохранить сценарий без спецификации.
В документации MS для метода сохранения указано:
Значение атрибута кодировки берется из свойства XmlDeclaration.Encoding. Если XmlDocument не имеет XmlDeclaration или если XmlDeclaration не имеет атрибута кодирования, сохраненный документ также не будет иметь его.
В документации MS по XmlDeclaration перечислены свойства кодирования UTF-8, UTF-16 и других. В нем не упоминается спецификация.
Есть ли у XmlDeclaration свойство кодирования, которое не учитывает спецификацию?
PS. Это поведение идентично в Powershell 5 и Powershell 7.
Ответы
К сожалению, явное присутствие encoding="utf-8"
атрибута в объявлении XML-документа приводит к тому, что .NET превращает .Save()
документ в файл в кодировке UTF-8 со спецификацией, если указан путь к целевому файлу, что действительно может вызвать проблемы.
Запрос на изменение этого параметра был отклонен из-за опасения нарушить обратную совместимость; вот просьба хотя бы задокументировать поведение.
Несколько по иронии судьбы, отсутствие из encoding
атрибута приводит .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 фактически предписывает UTF-8 по умолчанию при отсутствии как спецификации, так и encoding
атрибута.
Как поясняет BACON в комментариях , строковое значение Encoding
атрибута в объявлении XML не имеет никакого отношения к тому, как кодируется файл, содержащий документ.
Вы можете управлять этим путем создания либо StreamWriter
или XmlWriter
с не-бом 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>