Sonderzeichen aus XML-Datei umwandeln

Hey,

es ist in etwa ähnlich wie das Problem aus meinem letzten Thread, nur das ich diesmal keine unicodes benutzen kann (Dachte damit könnte ich das lösen).
Also das Problem ist folgendes:
Ich habe einen riesigen Musik-Ordner, den ich immer mal wieder durchgehe und meine derzeitigen Lieblingslieder rauskopiere. Damit das deutlich angenehmer ist (Man nicht nur auf Namen schauen muss sondern auch kurz reinhören kann), habe ich den kompletten Ordner in VLC hinzugefügt und durch durchhören die Leider gefiltert und das ganze dann als xspf-Datei gespeichert (Ist im Grunde ne XML-Datei). Da ich das ganze öfters mache und immer andere Lieder drinne sind hab ich das ganze automatisiert. Dazu filtere ich aus der Datei die einzelnen Pfade raus und kopiere nur diese in nen neuen, vordefinierten Ordner, den ich dann hören kann. Allerdings kodiert der VLC Sonderzeichen und Umlaute, die wenn ich sie einfach kopieren wollen würde zu Fehlern führen, da ich diese erst zurückumwandeln muss.
Allerdings habe ich keine wirklich zuverlässige Möglichkeit dafür gefunden, ich hab durch googlelei und ausprobiererei paar De/Encoder ausprobiert und der bisher beste war der java.net.URLDecoder. Allerdings macht der es nicht 100% korrekt. Als Beispiel:
Die Kopier-klasse schaut so aus (alles per hand eingetragen):

public static void main(String[] args) {
    int anzahlDateien = 0;
    final File playlistDest = new File("D:\\Musik\\Musik-Oberordner\\Playlist.xspf");
    final File newDir = new File("D:\\Musik\\Musik-Oberordner\\VLC-Kopie");

    if (!newDir.exists()) {
        newDir.mkdir();
    } else {
        deleteFiles(newDir);
    }

    String curLine;
    try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(playlistDest)))) {
        while ((curLine = br.readLine()) != null) {
            if (curLine.contains("<location>")) {
                StringBuilder sb = new StringBuilder(curLine.trim());
                curLine = sb.replace(0, sb.indexOf("file:///") + 8, "")
                        .replace(sb.indexOf("</location>"), sb.length(), "").toString()
                        .replace("%20", " ")
                        .replace("&amp;", "&")
                        .replace("%2C", ",")
                        .replace("%27", "'")
                        .replace("&#39;", "'")
                        .replace("%C3%BC", "ü")
                        .replace("%C3%9C", "Ü")
                        .replace("%C3%A4", "ä")
                        .replace("%C3%84", "Ä")
                        .replace("%C3%A9", "é")
                        .replace("%C3%A1", "á")
                        .replace("%5B", "[")
                        .replace("%28", "(")
                        .replace("%29", ")")
                        .replace("%23", "#")
                        .replace("%21", "!")
                        .replace("%C3%9F", "ß")
                        .replace("%26", "&")
                        .replace("%C2%B4", "´")
                        .replace("%C3%B6", "ö")
                        .replace("o%CC%88", "ö")
                        .replace("%E2%84%A2", "™")
                        .replace("%E2%88%9E", "∞")
                        .replace("%5D", "]");
                if (!curLine.contains("/Maria/")) {
                    System.out.println((++anzahlDateien) + ": " + curLine);
                    Files.copy(Paths.get(curLine),
                            Paths.get(newDir.getPath() + "\\" + new File(curLine).getName()),
                            StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING);
                }
            }
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    System.out.println();
    System.out.println("Es wurden " + anzahlDateien + " Dateien kopiert!");
}

private static void deleteFiles(File dir) {
    for (File f : dir.listFiles()) {
        if (f.isDirectory()) {
            deleteFiles(f);
        }
        f.delete();
    }
}

Wie man sieht wird aus “&” “& amp;” und aus “,” “%2C”. Der URLDecoder macht nun aus Beispielsweise den “%2C” korrekt das “,”, aber beim “&” macht er einfach “%26” draus, also aus dem “& amp;” macht er einfach nix mit… GIbts ne Klasse die das schon vornherein macht, oder muss ich alle weiteren Fälle auch per Hand eintragen?

String umzuwandeln = "&,'";
    String back = URLEncoder.encode(umzuwandeln, "utf-8");
    System.out.println("Umgewandelt: " + back);
    String neu = URLDecoder.decode("&amp;", "utf-8");
    System.out.println("Zurück: " + neu);

Ausgabe ist:
Umgewandelt: %26%2C%27
Zurück: &

Ich vermute mal, dass dies an einer Art Escaping liegt. Die HTML-Codes bauen sich ja wie folgt auf:
&<Abk.>;
Wenn der URL-Encoder <Abk.> nicht kennt (er kennt nunmal nicht alle), muß er annehmen, dass das & dort alleine steht und macht deswegen das %26 draus. Selbiges gilt natürlich auch umgekehrt für den Decoder.

Da du hier anscheinend nur mit Dateien im eigenen Dateisystem arbeitest, solltest du aus den Texten zwischen den Location-Tags URLs erstellen und dir dann mal die URL-Methoden “getPath()” und “getQuery()” ansehen.

Wenn du das ganze in eine Methode wie

private static String sanitize(String input) {
     ... viele replace-Aufrufe ...

     return output;
}

packen und eine Methode

private static void testReplacements() {
    System.out.println(sanitize("Umlaute und &amp; sind bl%C3%B6de Schei%C3%9Fe"));
    System.out.println(sanitize("Und auch &#39;Anf%C3%BChrungszeichen&#39;"));
    ....
}

erstellen würdest, dann…

  • könnte jeder das schnell testen ohne sich einen Ordner “D:\Musik\Musik-Oberordner” erstellen zu müssen
  • könnte jeder (auch du!) leicht rausfiltern, welche Fälle gerade noch Probleme machen!
  • könnte jeder (auch du!) die problematischen Fälle notfalls gezielt im debugger durchlaufen
  • Wäre der Code ganz allgemein besser strukturiert
  • wäre das schon fast ein Unit-Test!!!

Aua

bist du sicher dass das xspf nicht ein utf-8 codiertes xml ist, das du hier in iso-8891-1 oder sowas einliest?

besser: http://www.xspf.org/applications/ suche nach Library

Die xspf ist ein in utf-8 codiertes XML, ja. Wenn ich dem Inputstreamreader aber das Charset utf-8 mitgebe habe ich das selbe Problem, wie ohne. Allerdings habe ich es einfach so gelöst:

curLine = URLDecoder.decode(sb.replace(0, sb.indexOf("file:///") + 8, "")
                        .replace(sb.indexOf("</location>"), sb.length(), "").toString(), "utf-8");

Bis jetzt hat er alle Dateien Problemlos so einlesen können und ich kann mir die ganzen replaces sparen.

@Marco13: Sowas hab ich sogar tatsächlich in ner anderen Klasse schon stehen, sie hier aber nicht gepostet. Hab da aber sowas nur ausprobiert. Ja, normalerweise sollte man sowas immer auslagern, da das Programm ansich aber nur für mich gebraucht wird, in 10min entstanden ist und auch nicht geplant war, dass das überhaupt mal wer außer mir sieht hab ichs halt so direkt gemacht.