Powershell XMLDocument salvo como UTF-8 sem BOM
Criei um objeto XML do tipo System.Xml.XmlDocument.
$scheme.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False XmlDocument System.Xml.XmlNode
Eu uso o método save () para salvá-lo em um arquivo.
$scheme.save()
Isso salva o arquivo no formato UTF-8 com BOM. O BOM causa problemas com outros scripts no futuro.
Quando abrimos o arquivo XML no Notepad ++ e o salvamos como UTF-8 (sem o BOM), outros scripts na linha não têm problemas. Então, fui solicitado a salvar o script sem o BOM.
A documentação da MS para os estados do método de salvamento :
O valor do atributo encoding é obtido da propriedade XmlDeclaration.Encoding. Se o XmlDocument não tiver um XmlDeclaration ou se o XmlDeclaration não tiver um atributo de codificação, o documento salvo também não terá um.
A documentação da MS sobre XmlDeclaration lista propriedades de codificação de UTF-8, UTF-16 e outros. Não menciona um BOM.
O XmlDeclaration tem uma propriedade de codificação que exclui o BOM?
PS. Esse comportamento é idêntico no Powershell 5 e no Powershell 7.
Respostas
Infelizmente, a presença explícita de um encoding="utf-8"
atributo na declaração de um documento XML transforma o .NET .Save()
no documento em um arquivo codificado em UTF-8 com BOM se um caminho de arquivo de destino for fornecido, o que pode de fato causar problemas.
Um pedido para mudar isso foi rejeitado por medo de quebrar a compatibilidade com versões anteriores; aqui está um pedido para pelo menos documentar o comportamento.
Ironicamente, a ausência de um encoding
atributo causa .Save()
a criação de arquivos codificados em UTF-8 sem um BOM.
Uma solução simples é, portanto, remover o atributo de codificação [1] ; por exemplo:
# 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] Isso é seguro, porque a recomendação W3C do XML efetivamente determina que o UTF-8 seja o padrão na ausência de um BOM e de um encoding
atributo.
Como o BACON explica nos comentários , o valor da string do Encoding
atributo na declaração XML não tem qualquer relação com a forma como o arquivo que contém o documento é codificado.
Você pode controlar isso criando tanto um StreamWriter
ou uma XmlWriter
com um não-BOM UTF8Encoding
, em seguida, passar que para 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()
Como alternativa, use um [XmlWriter]
:
# XmlWriter Example
$writer = [System.Xml.XmlWriter]::Create($filename, @{ Encoding = $encoding })
O segundo argumento é um [XmlWriterSettings]objeto, por meio do qual podemos exercer maior controle sobre as opções de formatação, além de definir explicitamente a codificação:
$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>