replaceByJPath.ps1
<#PSScriptInfo
.VERSION 1.2 .GUID 7cdb1a91-ade2-4d26-9942-5005fa790e33 .AUTHOR Frédéric Jacques .COMPANYNAME .COPYRIGHT Frédéric Jacques .TAGS JPath XPath XML JSON Replace .LICENSEURI http://www.apache.org/licenses/LICENSE-2.0 .PROJECTURI https://github.com/freddycoder/ReplaceByJPath .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES Fix space added attributes when there is only one attribute in a node #> <# .DESCRIPTION A script to replace values in json and xml file given a replacement json object #> param( [string] $inputFileName="", [string] $replaceJson="", [string] $outputFileName="" ) # Section validation des paramètres d'entrés ## Transformer l'objet de replacement $replaceObject = $replaceJson | ConvertFrom-Json; # Variable global a utiliser lors de la sauvegarde $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False # Section de définition des fonctions ## Formats JSON in a nicer format than the built-in ConvertTo-Json does. function Format-Json([Parameter(Mandatory, ValueFromPipeline)][String] $json) { $indent = 0; $preFormated = ($json -Split '\n' | ForEach-Object { if ($_ -match '[\}\]]') { # This line contains ] or }, decrement the indentation level $indent-- } $line = (' ' * $indent * 2) + $_.TrimStart().Replace(': ', ': ') if ($_ -match '[\{\[]') { # This line contains [ or {, increment the indentation level $indent++ } $line }) -Join "`n"; $preFormated = $preFormated -replace '\[\s+\]', '[]'; $preFormated; } ## Function to dynamicaly get value of a property of a json object function Get-Value($jobject) { $a = $jobject.Definition.Split('='); $type = $jobject.Definition.Split(' ')[0]; if ($type -eq "decimal") { return [System.Decimal]::Parse($a[$a.Length - 1]); } if ($a -eq "System.Object[]") { [System.Collections.ArrayList]$al = @() return $al; # Dans l'état actuel, cela ce transforme en null dans l'objet } if ($type -eq "object" -and $a[$a.Length - 1] -eq "null") { return [System.Object]; } return $a[$a.Length - 1]; } ## Fonction permettant de déduire si une chaine de caractère est un json function TypeFichier([string] $text) { $indiceJson = $text.IndexOf('{'); $indiceXml = $text.IndexOf('<'); if ($indiceJson -eq 0) { return "json"; } if ($indiceXml -eq 0) { return "xml"; } if (($indiceXml -eq -1 -and $indiceJson -ge 0) -or $indiceXml -gt $indiceJson) { return "json"; } if (($indiceJson -eq -1 -and $indiceXml -ge 0) -or $indiceJson -gt $indiceXml) { return "xml"; } return "inconnu"; } # Cette fonction a été tiré de cette page web # source : https://docs.microsoft.com/en-us/archive/blogs/sergey_babkins_blog/how-to-pretty-print-xml-in-powershell-and-text-pipelines function Format-Xml { param( ## Text of an XML document. [Parameter(ValueFromPipeline = $true)] [string[]]$Text ) begin { $data = New-Object System.Collections.ArrayList } process { [void] $data.Add($Text -join "`n") } end { $doc=New-Object System.Xml.XmlDataDocument $doc.LoadXml($data -join "`n") $sw=New-Object System.Io.Stringwriter $writer=New-Object System.Xml.XmlTextWriter($sw) $writer.Formatting = [System.Xml.Formatting]::Indented $doc.WriteContentTo($writer) $sw.ToString().Replace('" />', '"/>'); } } # Algoritme de transformation ## Désérialiser le contenu $content = Get-Content $inputFileName -Encoding utf8; $typeFichier = TypeFichier($content); if ($typeFichier -eq "json") { $json = $content | ConvertFrom-Json; ## Remplacement générique depuis l'objet de replacement foreach ($jpath in $replaceObject | Get-Member -MemberType "NoteProperty") { $ref = $json $pathElements = $jpath.Name.Split('.'); for ($i = 0; $i -lt $pathElements.Length - 1; $i++) { $ref = $ref.($pathElements[$i]); } if ($ref -is [system.array]) { for ($j = 0; $j -lt $ref.Length; $j++) { Write-Output $ref[$j].($pathElements[$pathElements.Length - 1]); $ref[$j].($pathElements[$pathElements.Length - 1]) = Get-Value($jpath); Write-Output $ref[$j].($pathElements[$pathElements.Length - 1]); } } else { Write-Output $ref.($pathElements[$pathElements.Length - 1]); $ref.($pathElements[$pathElements.Length - 1]) = Get-Value($jpath); Write-Output $ref.($pathElements[$pathElements.Length - 1]); } } ## Écrire le contenu dans un fichier $outputContent = ""; if ($json -is [system.array]) { $outputContent = ConvertTo-Json @($json) -Depth 64 | Format-Json; } else { $outputContent = ConvertTo-Json @($json)[0] -Depth 64 | Format-Json; } $isRooted = [System.IO.Path]::IsPathRooted($outputFileName); if ($isRooted -eq $false) { $outputFileName = $PWD.Path + "\" + $outputFileName; } [System.IO.File]::WriteAllText($outputFileName, $outputContent, $Utf8NoBomEncoding); } elseif ($typeFichier -eq "xml") { $xmlDoc = [xml]$content.Replace(' xmlns="', ' notxmlns="'); $xmlDoc.PreserveWhitespace = $true; ## Remplacement générique depuis l'objet de replacement foreach ($jpath in $replaceObject | Get-Member -MemberType "NoteProperty") { $nodes = $xmlDoc.SelectNodes($jpath.Name); foreach ($node in $nodes) { if ($null -ne $node) { if ($node.NodeType -eq "Element") { Write-Output $node.InnerXml; $node.InnerXml = Get-Value($jpath); Write-Output $node.InnerXml; } else { Write-Output $node.Value; $node.Value = Get-Value($jpath); Write-Output $node.Value; } } } } ## Écrire le contenu dans un fichier $xmlString = $xmlDoc.OuterXml; $xmlOut = [xml]($xmlString.Replace(' notxmlns="', ' xmlns="')); $isRooted = [System.IO.Path]::IsPathRooted($outputFileName); if ($isRooted -eq $false) { $outputFileName = $PWD.Path + "\" + $outputFileName; } $xmlOut.save($outputFileName); $xmlWithTrimSpace = (Get-Content $outputFileName -Encoding utf8) | Format-Xml; [System.IO.File]::WriteAllText($outputFileName, $xmlWithTrimSpace, $Utf8NoBomEncoding); } else { Write-Error "Contenu non reconnu, le fichier n'est ni un json, ni un xml"; } |