nudZ
nudZ

Reputation: 3

Merge multiple XML in multiple subfolders with Powershell

I am quite new to PowerShell. Currently, I'm struggling with the following setup. There are several XML files contained in this folder structure:

Root
|_2020-XX-XX
   |_file1.xml
   |_file2.xml
|_2020-yy-yy
    |_file1.xml
    |_file2.xml

Now, I want to create a script that merges parts of each folder's xml files into one.

The result should look something like this:

|_2020-XX-XX
   |_file1.xml
   |_file2.xml
   |_newfile2020XXXX.xml
|_2020-yy-yy
    |_file1.xml
    |_file2.xml
    |_newfile2020YYYY.xml

So far, my script looks like this:

$date=Get-Date -Format "yyyyMMdd"
#Get the date for naming the output-file

$xmlFilePath = Get-ChildItem "\\Server\Rootfolder" -Recurse -Force | Sort-Object LastWriteTime
#Get and sort the xml-Files by date

$finalXml = "<root>"

foreach ($file in $_.xmlFilePath) {
    [xml]$xml = Get-Content $file
    $finalXml += $xml.root.InnerXml
}
$finalXml += "</root>"
#XML Object closer

([xml]$finalXml).Save("$pwd\newfile$date.xml")

While the debugger does not produce any error, the created file is

I can't quite figure out what to do, to troubleshoot this and would be grateful for any advice on this.

Thanks in advance for any hint!

Upvotes: 0

Views: 312

Answers (1)

Tomalak
Tomalak

Reputation: 338336

You seem to want to create one "merged" file per folder. That means you need two loops - one for the folders, and one for the files per folder.

$date = Get-Date -Format "yyyyMMdd"

Get-ChildItem "\\Server\Rootfolder" -Directory | ForEach-Object {
    $folder = $_.FullName
    Write-Host "Processing $folder..."

    $allData = [xml]"<root></root>"

    Get-ChildItem $folder -Filter "*.xml" | Sort-Object LastWriteTime | ForEach-Object {
        if ($_.Name -like "newfile*") { return }
        Write-Host " -" $_.name

        $xml = New-Object xml
        $xml.Load($_.FullName)

        $imported = $allData.ImportNode($xml.DocumentElement, $true)
        $allData.DocumentElement.AppendChild($imported) | Out-Null
    }

    $finalPath = Join-Path $folder "newfile_$date.xml"
    $allData.Save($finalPath)
}

Apart from that, don't process XML as if it were plain text. Use XmlDocument.Load() and XmlDocument.Save() for reading and writing, and use XmlDocument.ImportNode() to transfer content from one document to another.

These two lines are synonymous for creating an XmlDocument (docs):

$xml = New-Object xml
$xml = New-Object System.Xml.XmlDocument

Doing so guarantees that input files are interpreted correctly for their file encoding ([xml]$xml = Get-Content ... does not guarantee that) and that generated output is proper XML as well (concatenating some strings and writing the result to file does not guarantee that).

It's also a good idea to exclude "merged" files (if ($_.Name -like "newfile*") { return }), so you don't end up adding them to each other recursively.

Upvotes: 1

Related Questions