Erste Schritte yaml parsen in Java

Status
Nicht offen für weitere Antworten.

BobBob

Mitglied
Hallo,

weiß zufällig jemand von euch, wie man eine (generische) Yaml-Datei in Java einlesen und iterieren kann?

Hier ist mein Versuch:

Java:
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileReader;
import java.util.LinkedHashMap;
import java.util.Map;


public class Main {
    public static class Items {
        public LinkedHashMap<String, Object> map;
    }

    public static void main(String[] args) throws Exception {
        prettify(new File("test.yml"));
    }

    public static void prettify(File file) throws Exception {
        Items load = null;
        try (FileReader fr = new FileReader(file)) {
            load = new Yaml().load(fr);
        }
        assert load != null;
        iterate(load, 0);
    }

    public static void iterate(Items items, int depth) {
        for (Map.Entry<String, Object> e : items.map.entrySet()) {
            if (e.getValue() instanceof Items) {
                iterate((Items) e.getValue(), depth + 1);
            } else {
                System.out.println("  ".repeat(depth) + e);
            }
        }
    }
}

Fehler:
Exception in thread "main" java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class Main$Items (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; Main$Items is in unnamed module of loader 'app')
at Main.prettify(Main.java:20)

Ich hatte auch nach Beispielen gesucht, fand aber nur veralteten Käse.

Nach Dokumentation (https://bitbucket.org/snakeyaml/snakeyaml/wiki/Documentation) sollte dies eigentlich mit SnakeYaml möglich sein.

Oder gäbe es auch noch eine andere Parser Library?

Vielen Dank für jede Anregung
 

BobBob

Mitglied
Ufff, es hat schon geklappt:

Java:
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

import java.io.File;
import java.io.FileReader;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


public class Main {
    public static void main(String[] args) throws Exception {
        prettify(new File("test.yml"));
    }

    public static void prettify(File file) throws Exception {
        LinkedHashMap<String, Object> load = null;
        try (FileReader fr = new FileReader(file)) {
            load = new Yaml(new Constructor(LinkedHashMap.class, new LoaderOptions())).load(fr);
        }
        assert load != null;
        iterate(load, 0);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public static void iterate(LinkedHashMap<String, Object> map, int depth) {
        for (Map.Entry<String, Object> e : map.entrySet()) {
            if (e.getValue() instanceof LinkedHashMap) {
                System.out.println("  ".repeat(depth) + e.getKey() + ":");
                iterate((LinkedHashMap<String, Object>) e.getValue(), depth + 1);
            } else if (e.getValue() instanceof List list) {
                System.out.println("  ".repeat(depth) + e.getKey() + ":");
                for (Object li : list) {
                    System.out.println("  ".repeat(depth) + " - " + li);
                }
            } else {
                System.out.println("  ".repeat(depth) + e);
            }
        }
    }
}

Mit mehrzeiligen Items gibt es aber noch Probleme.

Weiß jemand, wie man einen bestimmten Item ändern kann und dann die Datei neu schreiben kann?
 

BobBob

Mitglied
Machst Du jetzt ein "Suchen & Ersetzen", oder baust Du Dir deinen eigenen Parser?
Ich suche mir "Chunks" heraus und dann jeweils einzelne "Attribute", danach modifiziere und setze ich die "Chunks" geordnet wieder zusammen.

Ein DOM mit Manipulation wäre schön gewesen, aber das bietet die Lib nicht an.
 

BobBob

Mitglied
In der Map fehlt aber die (einfache) Navigierbarkeit. Ich kann nicht sagen, wo ich gerade bin, herkam oder hin will. Das ist etwas unkomfortabel, bzw. brauche ich dann zusätzliche Hilfs-Konstrukte drum rum.
 

BobBob

Mitglied
Na gut mihe7 (eine Antwort auf meine Frage wäre schön gewesen, vielleicht ist das aber auch heutzutage schon zu viel verlangt), bis jetzt habe ich Folgendes:

Java:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.*;

public class Main {
    private static class Service extends AbstractList<String> implements Comparable<Service> {
        private final ArrayList<String> lines = new ArrayList<>();

        @Override
        public String get(int index) {
            return lines.get(index);
        }

        @Override
        public int size() {
            return lines.size();
        }

        @Override
        public boolean add(String s) {
            return lines.add(s);
        }

        @Override
        public String toString() {
            return String.join("\n", lines);
        }

        @Override
        public int compareTo(Service o) {
            boolean b1 = lines.contains("  traefik:");
            boolean b2 = o.lines.contains("  traefik:");
            if (b1 || b2) {
                return b1 ? b2 ? 0 : -1 : 1;
            }
            boolean b3 = lines.contains("    profiles:");
            boolean b4 = o.lines.contains("    profiles:");
            if (b3 ^ b4) {
                return b3 ? 1 : -1;
            }
            boolean b5 = lines.isEmpty();
            boolean b6 = o.lines.isEmpty();
            if (!b5 && !b6) {
                return get(0).replaceAll(":$", "").compareTo(o.get(0).replaceAll(":$", ""));
            }
            return b5 ? b6 ? 0 : -1 : 1;
        }
    }

    public static void main(String[] args) throws Exception {
        format(new File("test.yml"), new File("test_neu.yml"));
    }

    public static void format(File from, File to) throws Exception {
        TreeSet<Service> services = new TreeSet<>();
        try (BufferedReader br = new BufferedReader(new FileReader(from))) {
            Service current = new Service();
            String l;
            while ((l = br.readLine()) != null) {
                if (l.isBlank() || "services:".equals(l)) {
                    continue;
                }
                int c = l.length() - l.replace(" ", "").length();
                if (c == 2 && !current.isEmpty()) {
                    services.add(current);
                    current = new Service();
                }
                current.add(l);
            }
            services.add(current);
        }
        try (PrintWriter pw = new PrintWriter(to)) {
            pw.println("services:");
            pw.println();
            for (Service s : services) {
                pw.println(s);
                pw.println();
            }
        }
    }
}

Vermutlich wird das mit einer Map nicht einfacher umzusetzen sein, sodass reinventing the wheel möglicherweise gegeben ist.

Alle Services sollen nach Name sortiert werden, "traefik" nach vorn und alle mit "profiles" nach unten. Viel mehr Magic passiert nich.
 

KonradN

Super-Moderator
Mitarbeiter
Wenn es Dir um entsprechend klar definierte yml Dateien geht, dann könnte eine Möglichkeit sein, dass man hier die Entity Klassen entsprechend erstellt und dann snakeyaml nutzt, eben genau dieses Entities zu laden.

Wenn ich beim überfliegen es richtig gesehen habe, unterstützt snakeyaml das auch und das würde dir die Möglichkeit geben, halt die Daten direkt zu laden, im Model zu verändern und dann einfach wieder zu dumpen.
 

BobBob

Mitglied

mihe7

Top Contributor
-> indirekte Frage.
Das verstehe ich in einem Forum als Angebot, den Code zu zeigen, falls jemand Bedarf anmeldet.

-> das steht oben drüber, generisch = keine feste Struktur
Bei Deiner Lösung müssen in der Datei mit einer Einrückung von 2 Leerzeichen "traefik:" und mit einer Einrückung von 4 Leerzeichen "profiles:" vorhanden sein. Da scheint mir diesbezüglich doch eine sehr starre Struktur vorausgesetzt zu werden. Letztlich aber egal, so lange Du mit Deiner Lösung zufrieden bist.
 

BobBob

Mitglied
Letztlich aber egal, so lange Du mit Deiner Lösung zufrieden bist.
Mir ist in compareTo noch eine Unschönheit aufgefallen... besser wäre so :

Java:
    @Override
    public int compareTo(Service o) {
      boolean b1 = lines.contains("  traefik:");
      boolean b2 = o.lines.contains("  traefik:");
      if (b1 || b2) {
        return b1 ? b2 ? 0 : -1 : 1;
      }
      boolean b3 = lines.contains("    profiles:");
      boolean b4 = o.lines.contains("    profiles:");
      if (b3 ^ b4) {
        return b3 ? 1 : -1;
      }
      boolean b5 = lines.isEmpty();
      boolean b6 = o.lines.isEmpty();
      if (b5 || b6) {
        return b5 ? b6 ? 0 : -1 : 1;
      }
      return get(0).replaceAll(":$", "").compareTo(o.get(0).replaceAll(":$", ""));
    }

Bei Deiner Lösung müssen in der Datei mit einer Einrückung von 2 Leerzeichen "traefik:" und mit einer Einrückung von 4 Leerzeichen "profiles:" vorhanden sein.
Damit hast du genau recht.

Es wird ein valides und jeweils mit zwei Leerzeichen richtig eingerücktes yaml file vorausgesetzt. Ich fürchte, sollte ich diese Annahme nicht machen , dann wird es codemäßig etwas komplexer werden (da für jede "Zeile" dann eine zusätzliche Klasse brauche).
 

Marinek

Bekanntes Mitglied
Also dein CompareTo sieht ja mal richtig Crazy aus.

Einerseits ist es so, dass es nur mit bestimmten Schlüsselwörtern auskommt. Siehe Implementierung. Aber da drin ist es auch inkonsequent. Warum kann ich denn bei Profiles ein exklusives oder verwenden und bei den anderen reicht oder?

Warum wird, wenn nix zutrifft ein ganz anderer Inhalt verglichen??

Sind wir uns sicher, dass das eine korrekte Implementierung von compareTo ist?

Ich tippe auf nein.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
Beowend String zu Date parsen Java Basics - Anfänger-Themen 1
W Strings und das parsen Java Basics - Anfänger-Themen 8
R String index out of range: -1 beim Datei Parsen Java Basics - Anfänger-Themen 15
K String nach bestimmtem Muster parsen Java Basics - Anfänger-Themen 3
K Datentypen String zu Integer parsen Java Basics - Anfänger-Themen 2
L Jackson JSON parsen Java Basics - Anfänger-Themen 7
7.7GradOst Datentypen Stringeingabe aus z.B. "4,d,<" parsen Java Basics - Anfänger-Themen 7
D InputStream parsen und als Bilddatei abspeichern Java Basics - Anfänger-Themen 1
M JAVA String schnell parsen Java Basics - Anfänger-Themen 14
K Methoden Datum parsen Java Basics - Anfänger-Themen 16
V Java Regex richtig parsen Java Basics - Anfänger-Themen 2
J Rekursives Parsen (ohne Reg Expressions) Java Basics - Anfänger-Themen 8
L Beliebigen Datentypen aus String parsen Java Basics - Anfänger-Themen 6
L Datei aus Multipart parsen und speichern, seltsam codiert? Java Basics - Anfänger-Themen 16
J String aus Json File parsen Java Basics - Anfänger-Themen 6
S Date parsen klappt nicht richtig Java Basics - Anfänger-Themen 3
M Webseiten Parsen Java Basics - Anfänger-Themen 2
M Input/Output Probleme beim Parsen von CSV und TXT Dateien Java Basics - Anfänger-Themen 7
V Umlaute beim Parsen einer HTML Seite Java Basics - Anfänger-Themen 4
P String parsen Java Basics - Anfänger-Themen 5
S fehler beim datum parsen Java Basics - Anfänger-Themen 6
T Klassen CSV datei einlesen und parsen Java Basics - Anfänger-Themen 4
F Methoden Termin parsen Java Basics - Anfänger-Themen 2
Luk10 String (Hexadezimal) zu int parsen Java Basics - Anfänger-Themen 12
O Nicht Standard Form boolesche Funktion in Standard Form parsen Java Basics - Anfänger-Themen 3
E Datentypen Unvollständiges Datum parsen Java Basics - Anfänger-Themen 8
U Website parsen Java Basics - Anfänger-Themen 11
D Java - OutOfMemoryError beim Parsen Java Basics - Anfänger-Themen 15
J String zu Double parsen (multiple points) Java Basics - Anfänger-Themen 2
K Fehlerbehandlung beim Parsen von Strings Java Basics - Anfänger-Themen 9
F Datum AM / PM parsen Java Basics - Anfänger-Themen 5
A Datentypen Datum mit "May" zu Date parsen Java Basics - Anfänger-Themen 6
F Datum parsen Java Basics - Anfänger-Themen 6
R Datumsformatierung parsen Java Basics - Anfänger-Themen 8
E Code parsen/ formatieren Java Basics - Anfänger-Themen 3
G String parsen Java Basics - Anfänger-Themen 3
J int Wert mit getter holen und in String parsen Java Basics - Anfänger-Themen 5
trash Double Parsen? Java Basics - Anfänger-Themen 3
M Datum parsen Java Basics - Anfänger-Themen 10
A Parsen von double zu int? Java Basics - Anfänger-Themen 2
L String zu Enum parsen Java Basics - Anfänger-Themen 8
L String zuverlässig nach Char parsen? Java Basics - Anfänger-Themen 4
S String KeyEvent parsen Java Basics - Anfänger-Themen 2
D Datum parsen Java Basics - Anfänger-Themen 11
H XML Parsen Java Basics - Anfänger-Themen 7
J HTML mit XPath parsen Java Basics - Anfänger-Themen 7
H Gleichung parsen Java Basics - Anfänger-Themen 10
Spin SAX parsen ..XML not found Java Basics - Anfänger-Themen 2
W String zu Calendar parsen Java Basics - Anfänger-Themen 4
S String Parsen Java Basics - Anfänger-Themen 3
T Zeitwerte parsen Java Basics - Anfänger-Themen 6
J Scanner - Zeile parsen Java Basics - Anfänger-Themen 8
S String parsen Java Basics - Anfänger-Themen 17
W Char in String parsen Java Basics - Anfänger-Themen 6
E Wochentag String parsen Java Basics - Anfänger-Themen 2
S Ascii Datei parsen Java Basics - Anfänger-Themen 2
bugmenot args parsen Java Basics - Anfänger-Themen 3
G Swing xml parsen - Office Java Basics - Anfänger-Themen 8
M Bilder "parsen" Java Basics - Anfänger-Themen 5
G String parsen Java Basics - Anfänger-Themen 7
G Char Wert in Int Wert parsen Java Basics - Anfänger-Themen 10
P HTML parsen Java Basics - Anfänger-Themen 2
K Objekte zurück parsen Java Basics - Anfänger-Themen 2
D xml parsen mit Java Java Basics - Anfänger-Themen 5
G Vector Strijng parsen Java Basics - Anfänger-Themen 6
G Url parsen? Java Basics - Anfänger-Themen 3
H parsen Java Basics - Anfänger-Themen 24
M probleme beim parsen Java Basics - Anfänger-Themen 7
T Beim XML-Parsen Text einlesen Java Basics - Anfänger-Themen 5
C parsen Java Basics - Anfänger-Themen 2
G Parsen eines Strings Java Basics - Anfänger-Themen 4
M Object[] parsen Java Basics - Anfänger-Themen 9
E Mathematisch parsen, aber mit einer Variablen X ! Java Basics - Anfänger-Themen 6
N Int parsen Java Basics - Anfänger-Themen 3
D Array Parsen Java Basics - Anfänger-Themen 4
N Datum parsen Java Basics - Anfänger-Themen 3
P Datei mit Strings parsen Java Basics - Anfänger-Themen 4
M Html Parsen / Values von Hidden Fields auslesen Java Basics - Anfänger-Themen 10
W html parsen Java Basics - Anfänger-Themen 2
K Tokens in Integer parsen Java Basics - Anfänger-Themen 2
D HTML-Datei einlesen/parsen Java Basics - Anfänger-Themen 9
J java script mit java parsen Java Basics - Anfänger-Themen 6
G parsen von double zu int Java Basics - Anfänger-Themen 4
RaoulDuke java.util.Date parsen Java Basics - Anfänger-Themen 5
B Problem beim XML-Parsen Java Basics - Anfänger-Themen 10
G Parsen des Datums nicht möglich! Wer kann helfen? Java Basics - Anfänger-Themen 7
M.C.S. String parsen in Java Java Basics - Anfänger-Themen 5
T Parsen einer Datei? Java Basics - Anfänger-Themen 3
R Website mit Java parsen Java Basics - Anfänger-Themen 4
S String nach boolean parsen! Java Basics - Anfänger-Themen 5
M regulärer Ausdruck zum Parsen einer E-Mail Signatur Java Basics - Anfänger-Themen 16
C Text mit Trennzeichen parsen (Bsp. Ich/esse/heute/Eis) Java Basics - Anfänger-Themen 9
A Parsen einer XML-Datei: Wo sind meine Start-Tags??? Java Basics - Anfänger-Themen 22
A erste Schritte auf dem Weg eine XML-Datei zu parsen Java Basics - Anfänger-Themen 2
F Kommandozeile parsen Java Basics - Anfänger-Themen 6
T XML Parsen und Inhalt in ein Byte Array schreiben Java Basics - Anfänger-Themen 3
P String zu Date bei jedem Tastendruck parsen Java Basics - Anfänger-Themen 3
V logfile parsen Java Basics - Anfänger-Themen 7
D HTML Code einlesen und nach Links parsen Java Basics - Anfänger-Themen 10
M String array in Int array parsen und umgekehrt Java Basics - Anfänger-Themen 6

Ähnliche Java Themen

Neue Themen


Oben