I have created a powerscript that exports all transactions from jGnash to a csv-file
You may be interested and use it without any warrenty:
# Setze den Pfad zur XML-Datei automatisch auf den Skript-Ordner
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$transactionsXmlFile = "$scriptDir\test.xml"
$outputCsvTransactionsBase = "$scriptDir\transact"
$outputCsvAccounts = "$scriptDir\accounts.csv"
$outputCsvUnknownAccounts = "$scriptDir\unknown_accounts_transactions.csv"
# Prüfe, ob die Datei existiert
if (-Not (Test-Path $transactionsXmlFile)) {
Write-Host "Fehler: Die Datei test.xml wurde nicht gefunden!" -ForegroundColor Red
exit
}
# XML-Datei einlesen
[xml]$transactionsXmlData = Get-Content $transactionsXmlFile
# Alle Accounts aus test.xml sammeln, um Namen anhand der ID nachschlagen zu können
$accountMap = @{}
$transactionsXmlData.SelectNodes("//Account | //creditAccount | //debitAccount | //parentAccount") | ForEach-Object {
if ($_.id -and $_.name) {
$accountMap[$_.id] = $_.name
}
}
# Funktion zum Nachschlagen von Account-Namen
function Get-AccountName {
param (
[string]$accountId,
[System.Xml.XmlElement]$accountNode
)
if ($accountId) {
if ($accountMap.ContainsKey($accountId)) {
return $accountMap[$accountId]
} else {
Write-Host "Warnung: Account-ID $accountId nicht in der Account-Map gefunden." -ForegroundColor Yellow
return "Unbekannt" # Gebe "Unbekannt" zurück, falls der Name nicht gefunden wird
}
} elseif ($accountNode -and $accountNode.name) {
return $accountNode.name
}
Write-Host "Warnung: Leere Account-ID und kein Account-Node gefunden." -ForegroundColor Yellow
return "Unbekannt"
}
# Funktion zum Formatieren des Datums
function Format-Date {
param (
[string]$date
)
if ($date) {
try {
$dateTime = [datetime]::ParseExact($date, "yyyy-MM-dd", $null)
return $dateTime.ToString("dd.MM.yyyy")
} catch {
Write-Host "Warnung: Konnte Datum '$date' nicht formatieren." -ForegroundColor Yellow
return $date
}
}
return $date
}
# Funktion zum Formatieren des Betrags
function Format-Amount {
param (
[string]$amount
)
if ($amount) {
# Ersetze Punkt durch Komma und formatiere als Währung ohne Tausendertrennzeichen
$formattedAmount = $amount -replace '\.', ','
return "{0:0.00}" -f ([decimal]::Parse($formattedAmount))
}
return "0,00"
}
# Alle Transaktionen finden
$transactions = $transactionsXmlData.SelectNodes("//Transaction")
# Prüfen, ob Transaktionen vorhanden sind
if ($transactions.Count -eq 0) {
exit
}
# Array für CSV-Daten (Transaktionen)
$transactionList = @()
$unknownTransactionList = @()
$counter = 0
$fileIndex = 1
foreach ($t in $transactions) {
# Extrahiere das Datum und den Payee der Transaktion
$date = Format-Date -date $t.date
$payee = $t.payee
$memo = $t.memo
# Gehe durch alle TransactionEntries, um Split-Transaktionen zu berücksichtigen
foreach ($transactionEntry in $t.transactionEntries.TransactionEntry) {
# Prüfe, ob `debitAccount` und `creditAccount` als Referenzen oder direkte Knoten vorliegen
$debitAccountRef = $transactionEntry.debitAccount.reference
$debitAccountNode = $transactionEntry.debitAccount
$creditAccountRef = $transactionEntry.creditAccount.reference
$creditAccountNode = $transactionEntry.creditAccount
# Namen der Accounts nachschlagen, falls vorhanden
$debitAccount = Get-AccountName -accountId $debitAccountRef -accountNode $debitAccountNode
$creditAccount = Get-AccountName -accountId $creditAccountRef -accountNode $creditAccountNode
# Prüfe, ob Beträge existieren und formatiere die Werte als Währung
$creditAmount = if ($transactionEntry.creditAmount) { Format-Amount -amount $transactionEntry.creditAmount } else { "0,00" }
$debitAmount = if ($transactionEntry.debitAmount) { Format-Amount -amount $transactionEntry.debitAmount } else { "0,00" }
# Erstelle das Objekt für CSV (Transaktionen)
$entry = [PSCustomObject]@{
Date = $date
Payee = $payee
Memo = $memo
Amount = $creditAmount
DebitAmount = $debitAmount
DebitAccount = $debitAccount
CreditAccount = $creditAccount
}
if ($debitAccount -eq "Unbekannt" -or $creditAccount -eq "Unbekannt") {
$unknownTransactionList += $entry
} else {
$transactionList += $entry
}
# Erhöhe den Zähler und zeige alle 5.000 Zeilen eine Meldung an
$counter++
if ($counter % 50000 -eq 0) {
$outputCsvTransactions = "${outputCsvTransactionsBase}_${fileIndex}.csv"
$csvStringTransactions = $transactionList | ConvertTo-Csv -NoTypeInformation -Delimiter ';' | Out-String
[System.IO.File]::WriteAllText($outputCsvTransactions, $csvStringTransactions, [System.Text.Encoding]::Default)
Write-Host "$counter Transaktionen verarbeitet und in $outputCsvTransactions gespeichert..." -ForegroundColor Yellow
$transactionList = @()
$fileIndex++
}
}
}
# Exportiere verbleibende Transaktionen
if ($transactionList.Count -gt 0) {
$outputCsvTransactions = "${outputCsvTransactionsBase}_${fileIndex}.csv"
$csvStringTransactions = $transactionList | ConvertTo-Csv -NoTypeInformation -Delimiter ';' | Out-String
[System.IO.File]::WriteAllText($outputCsvTransactions, $csvStringTransactions, [System.Text.Encoding]::Default)
}
# Exportiere Transaktionen mit unbekannten Accounts
if ($unknownTransactionList.Count -gt 0) {
$csvStringUnknownTransactions = $unknownTransactionList | ConvertTo-Csv -NoTypeInformation -Delimiter ';' | Out-String
[System.IO.File]::WriteAllText($outputCsvUnknownAccounts, $csvStringUnknownTransactions, [System.Text.Encoding]::Default)
}
# Array für CSV-Daten (Konten)
$accountList = @()
foreach ($id in $accountMap.Keys) {
$account = [PSCustomObject]@{
AccountID = $id
AccountName = $accountMap[$id]
}
$accountList += $account
}
# In eine Zwischenstring-Variable für Konten exportieren
$csvStringAccounts = $accountList | ConvertTo-Csv -NoTypeInformation -Delimiter ';' | Out-String
# Die Zwischenstring-Variable manuell in Datei mit ANSI-Kodierung schreiben
[System.IO.File]::WriteAllText($outputCsvAccounts, $csvStringAccounts, [System.Text.Encoding]::Default)
# Erfolgsmeldung ausgeben
Write-Host "Export abgeschlossen: $outputCsvAccounts, ${outputCsvTransactionsBase}_*.csv und $outputCsvUnknownAccounts" -ForegroundColor Green