2016-05-23 5 views
2

Ich komme heute mit einem Problem, das ich nicht lösen kann.Clojure: ein XML analysieren, Kopf- und Schwanzlinien zuerst entfernen

Kontext

Ich habe einen Katalog mit dieser Art von Eingabe:

<catalogue> 
    <produit> 
    <nom>mince</nom> 
    <sku>25</sku> 
    <criterias> 
     <criteria>65</criteria> 
     <criteria>25</criteria> 
    </criterias> 
    </produit> 
    <produit> 
    <nom>gros</nom> 
    <sku>56</sku> 
    <criterias> 
     <criteria>35</criteria> 
     <criteria>8</criteria> 
    </criterias> 
    </produit> 
</catalogue> 

Ich möchte es als EDN verwandeln. In der Tat gelingt mir mit Beispieldaten; Dies ist der erste Schritt (dann kann ich nur faul Verarbeitung):

(defn catalog-fr-to-edn [] 
    (let [content (slurp "catalog-fr.xml")] 
    (->> (xml/parse-str content) 
     (into {})))) 

Aber, wie Sie sehen können - vielleicht ich etwas verpaßt - aber ich sehe nicht andere Möglichkeit, ein XML aus dieser Bibliothek zu analysieren abgesehen von Schlürfen der ganze Inhalt als STR. Das Problem ist, dass ich 700 MB Daten habe!

So tought ich über etwas besser

1) Zuerst die "Katalog" Linien

<produit> 
    <nom>mince</nom> 
    <sku>25</sku> 
    <criterias> 
     <criteria>65</criteria> 
     <criteria>25</criteria> 
    </criterias> 
    </produit> 
    <produit> 
    <nom>gros</nom> 
    <sku>56</sku> 
    <criterias> 
     <criteria>35</criteria> 
     <criteria>8</criteria> 
    </criterias> 
    </produit> 

So, dass ich praktisch N XML "Dateien", die N-Produkte entsprechen.

2) Schreiben Linie Aufzeichnungen für Zeile wie

{: sku 25 ...}

Problem

Ich denke, der erste Schritt in Ordnung ist (ich habe nicht den Schwanz die Datei ist der Header ok) .Er das Skript für diesen ersten Teil ist

(defn remove-lines [input nskip] 
    (let [path (->> (decompose-filepath input) 
        (last) 
        (str "qsdqsdqsdqsd."))] 
    (with-open [rdr (io/reader input)] 
     (with-open [wrt (io/writer path)] 
     (loop [n nskip] 
      (let [line (.readLine rdr)] 
      (cond (nil? line) 
        nil 
        (and (not (nil? line)) (not (empty? (re-find #"<\\catalogue>.*" line)))) 
        nil 
        :else 
        (cond (pos? n) 
          (recur (dec n)) 
          :else 
          (do (doto wrt (.write line) (.newLine)) 
              (recur n)))))))) 
    (io/delete-file input) 
    (rename-file path input))) 

Jetzt möchte ich den zweiten Schritt zu tun, aber ich habe keine Ahnung von ho w, es zu tun. Ich könnte das für 1 Produkt tun, aber ich weiß nicht, wie ich etwas in der Datei habe, die Position darin speichert.

Die XML-Analyse in Ordnung ist, so sagen wir, ich so gerade Linien wollen als Ausgabe (I die Zeilenumbrüche für Sichtbarkeit entfernt):

"<produit><nom>mince</nom><sku>25</sku><criterias><criteria>65</criteria><criteria>25</criteria></criterias></produit>" 

dh den Inhalt lesen, bis erreicht ist, den gelesenen Artikel nehmen, schreibt es und dann zum nächsten Artikel springen.

Benötige ich andere Java-Klassen? Ich kann mit Java-Code arbeiten, wenn es besser ist.

Oder vielleicht vermisse ich etwas aus clojure.data.xml Bibliothek?

Dank

+1

(clojure.data.xml/parse (io/input-stream (io/file "catalog-fr.xml"))) sollte ausreichen. clojure.data.xml/parse gibt Lazy-Tree von Elementdatensätzen zurück – mavbozo

+0

Danke, tatsächlich hatte ich ein Problem mit meiner Schreibfunktion, aber parse ist besser. Ich habe eine Java-Funktion geschrieben, um zu erreichen, was ich will, aber am Ende ist es nutzlos!Alles ist jetzt ok. –

+1

@JosephYourine Wenn Sie das Problem gelöst haben, vergessen Sie bitte nicht, diese Frage selbst zu beantworten (oder löschen Sie es einfach). – glts

Antwort

0

Es ist ein bisschen naiv, und es ist Java-Code, aber es ist leicht tragbar zu Clojure. Ich habe es nicht intensiv ausprobiert, da ich es nicht brauche

Paketdatei;