Created
December 20, 2014 06:47
-
-
Save juxtin/07a32f9c51fbee54f49c to your computer and use it in GitHub Desktop.
Parse Garmin TCX files with Clojure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns clj-tcx.core | |
(:require [clojure.data.xml :as xml] | |
[clojure.java.io :as io] | |
[clojure.walk :refer [postwalk]])) | |
(defmulti tcx-walker | |
"A multimethod that converts xml.Elments into Clojure maps and | |
LazySeqs into either bare strings or vectors depending on context. | |
Calls identity otherwise. Should be used to walk a parsed XML tree | |
to make it look more like an idiomatic Clojure data structure." | |
type) | |
(defmethod tcx-walker clojure.data.xml.Element | |
[{:keys [tag content]}] | |
(if (and (vector? content) ;; if this is | |
(pos? (count content)) ;; a non-empty vector | |
(every? map? content) ;; of k-v pairs | |
(apply distinct? (mapcat keys content))) ;; where keys are distinct | |
;; then this is a vector of k-v pairs representing a single | |
;; map, and we want to merge them together | |
{tag (apply merge content)} | |
;; otherwise it's just a named value | |
{tag content})) | |
(defmethod tcx-walker clojure.lang.LazySeq | |
[coll] | |
(if (and (= 1 (count coll)) ;; if this looks like | |
(string? (first coll))) ;; ("val") | |
;; then it's just a needlessly wrapped value | |
(first coll) ;; and we can unwrap it | |
;; otherwise it should be a vector | |
(vec coll))) | |
;; default is just identity | |
(defmethod tcx-walker :default [x] x) | |
(defn xml->map | |
"Recursively walks the given XML data, converting it into (more) | |
idiomatic Clojure maps and vectors." | |
[parsed-xml] | |
(postwalk tcx-walker parsed-xml)) | |
(defn xml-file->map | |
[file] | |
(-> file | |
slurp | |
xml/parse-str | |
xml->map)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment