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());}
}
}
我今天带着我无法解决的问题来了。
上下文
我有一个包含这种输入的目录:
<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());}
}
}