【发布时间】:2011-02-01 19:22:46
【问题描述】:
我正在编写一个 Clojure 库来解析 Mac OS X 的基于 XML 的 property list files。代码可以正常工作,除非你给它一个大的输入文件,此时你会得到java.lang.OutOfMemoryError: Java heap space。
这是一个示例输入文件(小到可以正常工作):
<plist version="1.0">
<dict>
<key>Integer example</key>
<integer>5</integer>
<key>Array example</key>
<array>
<integer>2</integer>
<real>3.14159</real>
</array>
<key>Dictionary example</key>
<dict>
<key>Number</key>
<integer>8675309</integer>
</dict>
</dict>
</plist>
clojure.xml/parse 把它变成:
{:tag :plist, :attrs {:version "1.0"}, :content [
{:tag :dict, :attrs nil, :content [
{:tag :key, :attrs nil, :content ["Integer example"]}
{:tag :integer, :attrs nil, :content ["5"]}
{:tag :key, :attrs nil, :content ["Array example"]}
{:tag :array, :attrs nil, :content [
{:tag :integer, :attrs nil, :content ["2"]}
{:tag :real, :attrs nil, :content ["3.14159"]}
]}
{:tag :key, :attrs nil, :content ["Dictionary example"]}
{:tag :dict, :attrs nil, :content [
{:tag :key, :attrs nil, :content ["Number"]}
{:tag :integer, :attrs nil, :content ["8675309"]}
]}
]}
]}
我的代码把它变成了 Clojure 数据结构
{"Dictionary example" {"Number" 8675309},
"Array example" [2 3.14159],
"Integer example" 5}
我的代码的相关部分看起来像
; extract the content contained within e.g. <integer>...</integer>
(defn- first-content
[c]
(first (c :content)))
; return a parsed version of the given tag
(defmulti content (fn [c] (c :tag)))
(defmethod content :array
[c]
(apply vector (for [item (c :content)] (content item))))
(defmethod content :dict
[c]
(apply hash-map (for [item (c :content)] (content item))))
(defmethod content :integer
[c]
(Long. (first-content c)))
(defmethod content :key
[c]
(first-content c))
(defmethod content :real
[c]
(Double. (first-content c)))
; take a java.io.File (or similar) and return the parsed version
(defn parse-plist
[source]
(content (first-content (clojure.xml/parse source))))
代码的核心是content 函数,这是一个在:tag(XML 标记的名称)上调度的多方法。我想知道是否应该做一些不同的事情来使这种递归更好地工作。我尝试用trampoline content 替换对content 的所有三个调用,但这不起作用。我应该做些什么来让这种相互递归更有效地工作吗?还是我采取了根本错误的方法?
编辑:顺便说一句,这个代码是available on GitHub,它可能更容易使用。
【问题讨论】: