2011-11-17 9 views
18

Quiero leer en un archivo XML y modificar un elemento y luego guardarlo en el archivo. ¿Cuál es la mejor manera de hacer esto mientras se conserva el formato y también sigue haciendo coincidir el terminador de línea (CRLF contra LF)?Powershell saving XML y formato conservador

Aquí es lo que tengo pero no hace eso:

$xml = [xml]([System.IO.File]::ReadAllText($fileName)) 
$xml.PreserveWhitespace = $true 
# Change some element 
$xml.Save($fileName) 

El problema es que las nuevas líneas de extra (también conocidos como líneas vacías en el xml) se eliminan y después de haber mezclado y LF CRLF.

Gracias por ayudar a un novato :) PowerShell

+1

¿Qué quiere decir con 'preservar el formato'? – manojlds

+1

Probablemente no haga la diferencia, pero ¿ha intentado '$ xml = [xml] (Get-Content $ filename)' en su lugar? De lo contrario, es posible que deba utilizar la clase nativa .NET XmlDocument y los métodos para cargar, editar y guardar el archivo. – Ryan

+2

@manojids Quiero preservar espacios en blanco, saltos, pestañas, etc. –

Respuesta

32

Puede utilizar el [xml] objeto PowerShell y establecer $xml.PreserveWhitespace = $true, o hacer lo mismo utilizando .NET XmlDocument:

$f = '.\xml_test.xml' 

# Using .NET XmlDocument 
$xml = New-Object System.Xml.XmlDocument 
$xml.PreserveWhitespace = $true 

# Or using PS [xml] (older PowerShell versions may need to use psbase) 
$xml = New-Object xml 
#$xml.psbase.PreserveWhitespace = $true # Older PS versions 
$xml.PreserveWhitespace = $true 

# Load with preserve setting 
$xml.Load($f) 
$n = $xml.SelectSingleNode('//file') 
$n.InnerText = 'b' 
$xml.Save($f) 

Sólo asegúrese para establecer PreserveWhitespace antes de llamar a XmlDocument.Load o XmlDocument.LoadXml.

NOTA: ¡Esto no conserva el espacio en blanco entre los atributos XML! Espacio en blanco en Los atributos XML parecen conservarse, pero no entre. La documentación habla sobre la preservación de "espacio en blanco nodos" (node.NodeType = System.Xml.XmlNodeType.Whitespace) y no atributos.

+3

¿Qué son los tipos nativos de Powershell? Todo es .NET :) – manojlds

+1

El uso de los objetos .NET lo solucionó. –

+2

@manojlds tiene razón, aunque PS encapsula algunos tipos de .NET como en este caso (psbase) por lo que "se siente" un poco diferente, incluso si todavía es .NET. :) – Ryan

1

Si guarda utilizando un XmlWriter, las opciones predeterminadas son aplicar sangrado con dos espacios y reemplazar las terminaciones de línea con CR/LF. Puede configurar estas opciones después de crear el escritor o crear el escritor con un objeto XmlSettings configurado según sus necesidades.

$fileXML = New-Object System.Xml.XmlDocument 

    # Try and read the file as XML. Let the errors go if it's not. 
    [void]$fileXML.Load($file) 

    $writerXML = [System.Xml.XmlWriter]::Create($file) 
    $fileXML.Save($writerXML) 
+0

Votando esto aunque podría haber proporcionado más detalles. Esto es particularmente útil cuando se necesita un resultado xml sin * espacio * embellecido *. – TNT

0

Si desea corregir la CRLF que se transforma a LF para los nodos de texto después de llamar al método Save en el XmlDocument puede utilizar una instancia XmlWriterSettings. Utiliza el mismo XmlWriter como MilesDavies192s answer pero también cambia la codificación a utf-8 y mantiene la sangría.

$xml = [xml]([System.IO.File]::ReadAllText($fileName)) 
$xml.PreserveWhitespace = $true 

# Change some element 

#Settings object will instruct how the xml elements are written to the file 
$settings = New-Object System.Xml.XmlWriterSettings 
$settings.Indent = $true 
#NewLineChars will affect all newlines 
$settings.NewLineChars ="`r`n" 
#Set an optional encoding, UTF-8 is the most used (without BOM) 
$settings.Encoding = New-Object System.Text.UTF8Encoding($false) 

$w = [System.Xml.XmlWriter]::Create($fileName, $settings) 
try{ 
    $xml.Save($w) 
} finally{ 
    $w.Dispose() 
}