本节书摘来自华章社区《clojure数据分析秘笈》一书中的第1章,第1.7节将xml数据读入incanter数据集,作者(美)eric rochester,更多章节内容可以访问云栖社区“华章社区”公众号查看
1.7 将xml数据读入incanter数据集
一类非常常用的数据格式是xml,人们对其褒贬不一。但在某种情况下,几乎所有人都不得不处理它。clojure可以使用java的xml库,但它也有自己的包,这个包提供了一种在clojure中使用xml的更自然的方式。
1.7.1 准备工作
首先,在leiningen project.clj文件中引入以下依赖:

1.7.3 实现原理
本方法按以下顺序处理xml:
解析xml数据文件。
利用解析树抽取数据节点。
将节点转换成代表数据的映射序列。
最后,将其转换至incanter数据集。
load-xml-data实现了这个过程。其中包括三个参数:输入文件名、传入解析完成的xml的根节点并返回第一个数据节点的函数,以及传入一个数据节点并返回下个数据节点或空值(如果其后没有节点)的函数。
首先,函数解析xml文件并将之装入zipper(将在后面的章节详细讨论zipper),然后利用传入的两个函数将数据节点抽取成一个序列。对于每个数据节点,获取其子节点并将其转换成一系列“标签名/内容”对。每个数据节点的对转换成一个映射,然后映射序列转换至incanter数据集。
1.7.4 更多信息
本方法中使用了一对有趣的数据结构或概念。这两种数据结构在函数式编程语言或者lisp中都很常见,但是都未出现在主流的编程语言中,接下来深入学习一下。
利用zipper浏览结构
解析完成后的xml文件需要作为参数传入clojure.zip/xml-zip。这将使用clojure本身的xml数据结构并将其转换成可以用如clojure.zip/down和clojure.zip/right之类的命令进行快速浏览。作为一门函数式编程语言,clojure使用不可变数据结构;而zipper提供了一种浏览、修改类树结构的高效、自然方法,例如xml文档。
流水线处理
可以使用->>宏来以流水线的方式展示处理过程。对于深度嵌套的函数调用,这个宏需要从右往左阅读,这使得处理过程的数据流和转换序列更清晰。
在clojure中可以执行流水线处理是因为它的宏系统。->>仅将函数调用重写成clojure本身的嵌套的格式,与格式读入的方式一样。传入宏的第一个参数将作为下一个表达式的最后一个参数插入。数据结构则插入第三个表达式作为最后一个参数,等等,直到这种格式结束。也就是说,以(->> x first (map length) (apply +))表达式开始。接下来是clojure构建最终表达式的一系列中间步骤(需要整合的元素在每个阶段都会高亮显示)。
(->> x first (map length) (apply +))
(->> (first x) (map length) (apply +))
(->> (map length (first x)) (apply +))
(apply + (map length (first x)))
比较xml和json
xml和json(在1.4节中提到)非常相似。可以证实的是,json的流行很大程度上是被对xml冗长特性的醒悟所驱动的。
当在clojure中处理这些格式的数据时,最大的不同在于json数据是直接转换成对应数据内容的clojure内部数据结构,例如映射和向量。然而对于xml而言,xml被读入至反映xml结构的记录类型,而不是反映数据结构的记录类型。
换句话说,json中的映射的键值来自域,例如,来自first_name或者age。然而,xml中映射的键值来自数据格式、标签、属性或者子节点,也就是说,标签和属性名来自域。这额外的一层抽象使得xml更加不灵活。