Clojure:解析一个XML,先去掉头尾行

Clojure : parse a XML, remove head and tail lines first

我今天带着我无法解决的问题来了。

上下文

我有一个包含这种输入的目录:

<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>

我想将其转换为EDN。事实上,我成功地使用了示例数据;这是第一步(然后我只做懒处理):

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

但是,如您所见 - 也许我遗漏了一些东西 - 但除了将所有内容都作为 STR 外,我没有看到其他方法来解析此库中的 XML。问题是我有 700 MB 的数据!

所以我想到了更好的事情

1) 首先删除 "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>

所以我实际上有 N XML "files" 对应 N 个产品。

2) 像

一样逐行写入记录

{:sku 25 ...}

问题

我觉得第一步就ok了(我没看到文件尾,header就ok了)。他就是这个第一部分的脚本

(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)))

现在我想做第二步,但我不知道该怎么做。我可以为 1 个产品执行此操作,但我不知道如何在文件中保存位置。

XML 解析没问题所以假设我只想要这样的行作为输出(为了可见性我删除了换行符):

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

即阅读内容直到到达,将阅读的文章拿走,写完然后跳转到下一篇文章。

我需要其他 Java 类 吗?如果更好的话,我可以使用 Java 代码。

或者我错过了 clojure.data.xml 图书馆的一些东西?

谢谢

它有点天真,它是 Java 代码,但它很容易移植到 Clojure。因为不需要,所以没有深入尝试

打包文件;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CatalogReader {

    public static void processFile (String input, String output) throws FileNotFoundException {

        try {

            // File input
            FileInputStream fstream = new FileInputStream(input);   
            DataInputStream in = new DataInputStream(fstream);
            BufferedReader br = new BufferedReader (new InputStreamReader(in));

            //File output
            File out = new File(output);
            FileOutputStream fos = new FileOutputStream(out);
            BufferedWriter bw = new BufferedWriter (new OutputStreamWriter(fos));

            String line;
            String product = "";

            Pattern pat = Pattern.compile("</catalogue>");
            Matcher mat;

            while ((line = br.readLine()) != null) {

                mat = pat.matcher(line);

                while (!mat.find()) {

                    product.concat(line);

                }

                bw.write(product);
                bw.newLine()
                product = "";

            }

            br.close();
            bw.close();
        }

        catch (IOException e) { System.err.println("Error: " + e.getMessage());}
    }

}