1

I have XML files where I want to replace certain strings.

The replacement source is a CSV file that contains 2 columns

old       |           new
-------------------------
OldPart1  |  NewPartName1
OldPart2  |  NewPartName2
OldPart3  |  NewPartName3

I want to replace all occurances of old with new in the XML files. I guess it does not really matter if the files are XML or just text. The replacement strings don't collide with XML tag names.

  • Have you tried simple text editors such as Notepad and Notepad++? – ComFreek Aug 2 '14 at 8:12
  • Yes, it did not find a method for mass replacements – juergen d Aug 2 '14 at 10:07
  • In Notepad++ press Ctrl+H to open the search & replace dialog. – ComFreek Aug 2 '14 at 10:24
  • I know. And where do I choose the CSV file to replace 1000 different strings one after each other? – juergen d Aug 2 '14 at 10:25
  • I misunderstood you, sorry. I don't think there are any editors which support your special requirement. I've experimented a little bit with PowerShell (it's fun). Please see my answer. – ComFreek Aug 2 '14 at 11:06
2

A little PowerShell magic.

Additional comments:

  • Your CSV file must not contain headers and must use ; as delimiters.
  • Your input and CSV file must both be encoded in UTF-8 or UTF-16. Other encodings can't be automatically guessed by PowerShell.
  • The script won't exit if you specify invalid filenames. Don't expect a nice error dialog to open :)
<#
  Copied from: http://blogs.technet.com/b/heyscriptingguy/archive/2009/09/01/hey-scripting-guy-september-1.aspx
  Many thanks to the Scripting Guy :)
  Changes:
    - Added a title parameter and assigned it to $OpenFileDialog.title
    - Changed the function's name to Get-OpenFile
#>
Function Get-OpenFile($initialDirectory, $title)
{   
 [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
 Out-Null

 $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
 $OpenFileDialog.title = $title;
 $OpenFileDialog.initialDirectory = $initialDirectory
 $OpenFileDialog.filter = "All files (*.*)| *.*"
 $OpenFileDialog.ShowDialog() | Out-Null
 $OpenFileDialog.filename
} #end function Get-FileName

Function Get-SaveFile($initialDirectory, $title)
{   
 [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
 Out-Null

 $OpenFileDialog = New-Object System.Windows.Forms.SaveFileDialog
 $OpenFileDialog.title = $title;
 $OpenFileDialog.initialDirectory = $initialDirectory
 $OpenFileDialog.filter = "All files (*.*)| *.*"
 $OpenFileDialog.ShowDialog() | Out-Null
 $OpenFileDialog.filename
} #end function Get-OpenFile

# $PSScriptRoot is only available for PowerShell >= 3
# Fallback needed
$scriptDir = $PSScriptRoot

$inputFile = Get-OpenFile -initialDirectory $scriptDir -title "Choose your input file"
$csvFile = Get-OpenFile -initialDirectory $scriptDir -title "Choose your CSV file"

$inputStr = [Io.File]::ReadAllText($inputFile);
$csvData = Import-Csv $csvFile -Header @("Needle", "Replacement") -Delimiter ';'

$csvData | % {
    $inputStr = $inputStr.Replace($_.needle, $_.replacement);
}

$outputFilename = Get-SaveFile -initialDirectory $scriptDir -title "Save your file"
$inputStr | Out-File -FilePath $outputFilename
1

Using python, (available on/for most platforms and free), and assuming that your xml file will fit in memory and that the separator is , with no space:

with open(r"XML/File/Name").read() as xml: 
    with open(r"Path/To/Output/File", "w") as outfile:
        for line in open(r"CSV/File/Name").readlines():
            (orig, replacement) = ','.split(line) # Change ',' to your separator
            xml.replace(orig, replacement)
            outfile.writeline(line)

I am sure that there are better/more generic ways to do this but it is late at the moment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.