Programovací jazyk Clojure – základy zpracování XML

Pavel Tišnovský 18. 8. 2015

Další důležitou součástí standardních knihoven programovacího jazyka Clojure jsou funkce umožňující zpracování dat uložených v XML. Dnes se zaměříme na funkce clojure.xml/parse, clojure.core/xml-seq a clojure.zip/xml-zip, které postačují pro přístup k jednotlivým uzlům, atributům i hodnotám v XML.

Obsah

1. Programovací jazyk Clojure – základy zpracování XML

2. Parsing XML a reprezentace obsahu XML souboru ve formě stromu

3. První demonstrační příklad: parsing XML souborů

4. Druhý demonstrační příklad: přístup ke XML reprezentovaného ve formě stromové struktury

5. Třetí demonstrační příklad: funkce xml-seq

6. Čtvrtý demonstrační příklad: jednoduché filtry postavené na funkci xml-seq

7. Použití zipperů pro přístup k prvkům XML

8. Pátý demonstrační příklad: základy použití zipperů

9. Šestý demonstrační příklad: složitější zipper

10. Repositář s dnešními demonstračními příklady

11. Odkazy na předchozí části tohoto seriálu

12. Odkazy na Internetu

1. Programovací jazyk Clojure – základy zpracování XML

Programovací jazyk Clojure se některými svými vlastnostmi, zejména pak již několikrát zmíněnou homoikonicitou a taktéž podporou líných sekvencí (lazy sequences), hodí pro zpracování strukturovaných dat, neboť tato data lze reprezentovat s využitím (většinou vnořených) seznamů, vektorů, map a popř. i množin. Předností této reprezentace dat je jejich relativně snadné zpracování pomocí funkcí dostupných již ve standardní knihovně jazyka Clojure (filtry, mapování funkcí na sekvence atd.). To samozřejmě platí i pro XML, což si ostatně ukážeme na několika demonstračních příkladech uvedených v navazujících kapitolách. Pro zpracování XML souborů nám budou postačovat jen tři speciální funkce. Jedna z těchto funkcí slouží pro parsování XML, druhá pak pro vytvoření sekvence z předaných dat a třetí funkce pro vytvoření takzvaného zipperu, s jehož využitím je možné procházet stromovou strukturou. Pro pokročilejší práci (například i pro proudové zpracování XML) je nutné použít mírně odlišné funkce popsané příště.

2. Parsing XML a reprezentace obsahu XML souboru ve formě stromu

Před vlastním zpracováním strukturovaných dat uložených v souborech typu XML je nutné provést načtení a syntaktickou analýzu XML. Pro tento účel slouží funkce pojmenovaná příhodně parse. Tato funkce je umístěna v knihovně nazvané clojure.xml, což mj. znamená, že před prvním voláním parse je nutné tuto knihovnu načíst s využitím require či use. V demonstračních příkladech budu pro jednoduchost používat funkci use, i když v praxi se pravděpodobně mnohem častěji setkáte s použitím require. Vraťme se však k funkci clojure.xml/parse. Tato funkce se většinou volá s jediným parametrem představujícím soubor nebo vstupní proud, z něhož se mají načíst data reprezentovaná v XML. Je možné použít i adresu (URI) reprezentovanou řetězcem. Pozor je nutné dát jen na to, že tento řetězec skutečně obsahuje jen URI a nikoli vlastní XML (načtené například funkcí slurp)!:

user=> (use '[clojure.xml])
 
user=> (doc parse)
-------------------------
clojure.xml/parse
([s] [s startparse])
  Parses and loads the source s, which can be a File, InputStream or
  String naming a URI. Returns a tree of the xml/element struct-map,
  which has the keys :tag, :attrs, and :content. and accessor fns tag,
  attrs, and content. Other parsers can be supplied by passing
  startparse, a fn taking a source and a ContentHandler and returning
  a parser

Výsledkem volání této funkce je stromová struktura, v níž je každý uzel z původního XML reprezentován mapou obsahující tři prvky s klíči :tag, :attrs a :content. Pod klíčem :tag je uložen název původního uzlu (jako symbol, ne jako řetězec, což je poměrně výhodné), pod klíčem :attrs mapa atributů uzlu a konečně pod klíčem :content se skrývá obsah uzlu, včetně rekurzivně uložených poduzlů.

3. První demonstrační příklad: parsing XML souborů

V prvním demonstračním příkladu, jehož úplnou podobu je možné nalézt na adrese https://github.com/tisnik/clojure-examples/tree/master/xmltest01, je ukázáno použití výše uvedené funkce clojure.xml/parse při syntaktické analýze jednoduchého XML souboru. Nejprve je obsah tohoto souboru načten (interně se sice používá SAX, ale i přesto se načte celé XML!), následně je provedena jeho syntaktická analýza a výsledkem je datová struktura zmíněná v předchozí kapitole. Tuto strukturu vypíšeme v čitelné podobě s využitím další užitečné funkce nazvané clojure.pprint/pprint:

(ns xmltest01.core)
 
(use '[clojure.xml])
(use '[clojure.pprint])
 
 
 
(defn xmltest01
    []
    (let [parsed-xml (clojure.xml/parse "test.xml")]
        (clojure.pprint/pprint parsed-xml)))
 
(defn -main
    [& args]
    (xmltest01))

Vstupní XML soubor, který se bude načítat a zpracovávat:

<?xml version="1.0"?>
<first value="42">
  <second>
    <third firstTag="10" secondTag="20">
      <fourth>Hello!
      </fourth>
    </third>
  </second>
</first>

Výsledkem načtení a syntaktické analýzy je tato struktura:

{:tag :first,
 :attrs {:value "42"},
 :content
 [{:tag :second,
   :attrs nil,
   :content
   [{:tag :third,
     :attrs {:firstTag "10", :secondTag "20"},
     :content
     [{:tag :fourth, :attrs nil, :content ["Hello!\n      "]}]}]}]}

Povšimněte si několika zajímavostí:

  1. Pod klíčem :tag je uložen název tagu, a to vždy jako symbol, ne jako řetězec. To je příjemné, protože pokud se bude zpracovávat XML s milionem tagů ≶strašně_dlouhé_jméno_tagu>, bude řetězec se jménem tagu použit v paměti jen jedenkrát a ne milionkrát.
  2. Atributy jsou reprezentovány mapou klíč–hodnota, kde klíč je opět symbolem a nikoli řetězcem.
  3. Obsahem uzlu je vektor s poduzlem/poduzly nebo přímo s hodnotou.
  4. Obsahem uzlu fourth je vektor obsahující řetězec (což očekáváme), který obsahuje jak konec řádku, tak i mezery na začátku druhého řádku (před uzavíracím tagem).

4. Druhý demonstrační příklad: přístup ke XML reprezentovaného ve formě stromové struktury

Ve druhém demonstračním příkladu jsou ukázány dva způsoby, jak poměrně nemotorně přistupovat ke stromové struktuře reprezentující zparsovaný XML soubor. Vzhledem k tomu, že celá struktura je skutečně stromem (uzly s vektory poduzlů), a jména původních uzlů jsou reprezentována symboly, je přístup k prvkům stromu relativně jednoduchý. Připomeňme si, že v mapě je možné k prvku přistupovat buď přes funkci (get mapa :klíč) nebo alternativně (:klíč mapa), což je kratší a po chvilce tréninku i čitelnější varianta. Navíc je možné využít oblíbené threading makro ->. Ostatně podívejme se na zdrojový kód demonstračního příkladu a dvě podobné funkce nazvané get-attributes-v1 a get-attributes-v2. Druhá zmíněná funkce je čitelnější a navíc se mnohem lépe čte zleva doprava (či shora dolů) a chybí zde nechvalně známá změť LISPovských závorek:

(ns xmltest02.core)
 
(use '[clojure.xml])
(use '[clojure.pprint])
 
 
 
(defn get-attributes-v1
    [parsed-xml]
    (:attrs (first (:content (first (:content parsed-xml))))))
 
(defn get-attributes-v2
    [parsed-xml]
    (-> parsed-xml
        :content
        first
        :content
        first
        :attrs))
 
(defn xmltest02
    []
    (let [parsed-xml (clojure.xml/parse "test.xml")]
        (clojure.pprint/pprint parsed-xml)
        (println "----------------------------------")
        (println (get-attributes-v1 parsed-xml))
        (println (get-attributes-v2 parsed-xml))))
 
(defn -main
    [& args]
    (xmltest02))

Výstupem tohoto příkladu by měly být následující řádky:

{:tag :first,
 :attrs {:value "42"},
 :content
 [{:tag :second,
   :attrs nil,
   :content
   [{:tag :third,
     :attrs {:firstTag "10", :secondTag "20"},
     :content
     [{:tag :fourth, :attrs nil, :content ["Hello!\n      "]}]}]}]}
----------------------------------
{:firstTag 10, :secondTag 20}
{:firstTag 10, :secondTag 20}

5. Třetí demonstrační příklad: funkce xml-seq

Druhou důležitou funkcí, která se poměrně často používá při zpracování XML souborů, je funkce nazvaná xml-seq. Tuto funkci nalezneme přímo ve standardní knihovně, takže se nemusí provádět její explicitní načtení. xml-seq na svém vstupu očekává výstup z výše popsané funkce clojure.xml/parse a jejím výsledkem je sekvence, jejíž prvky jsou získány průchodem původního stromu:

user=> (doc xml-seq)
-------------------------
clojure.core/xml-seq
([root])
  A tree seq on the xml elements as per xml/parse

Z jakého důvodu je tato funkce užitečná, si ukážeme v navazující kapitole, nyní nás však bude zajímat výsledná podoba sekvence. Proto se v dnešním třetím příkladu bude procházet vytvořenou sekvencí s využitím „smyčky“ realizované přes makro doseq, v němž se postupně jednotlivé prvky sekvence tisknou na standardní výstup:

(ns xmltest03.core)
 
(use '[clojure.xml])
(use '[clojure.pprint])
 
(defn print-xml-seq
    [parsed-xml]
    (doseq [item (xml-seq parsed-xml)]
        (println item)))
 
(defn xmltest03
    []
    (let [parsed-xml (clojure.xml/parse "nested.xml")]
        (clojure.pprint/pprint parsed-xml)
        (println "----------------------------------")
        (print-xml-seq parsed-xml)))
 
(defn -main
    [& args]
    (xmltest03))

Podoba vstupního souboru byla oproti předchozím příkladům upravena – povšimněte si dvojice poduzlů uložených v kořenovém uzlu:

<?xml version="1.0"?>
<first>
  <second value="A">
    <third>
      <fourth>Hello A</fourth>
    </third>
  </second>
  <second value="B">
    <third>
      <fourth>Hello B</fourth>
    </third>
  </second>
</first>

Následuje výstup vytvořený tímto demonstračním příkladem:

{:tag :first,
 :attrs nil,
 :content
 [{:tag :second,
   :attrs {:value "A"},
   :content
   [{:tag :third,
     :attrs nil,
     :content [{:tag :fourth, :attrs nil, :content ["Hello A"]}]}]}
  {:tag :second,
   :attrs {:value "B"},
   :content
   [{:tag :third,
     :attrs nil,
     :content [{:tag :fourth, :attrs nil, :content ["Hello B"]}]}]}]}
----------------------------------
{:tag :first, :attrs nil, :content [{:tag :second, :attrs {:value A}, :content [{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello A]}]}]} {:tag :second, :attrs {:value B}, :content [{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello B]}]}]}]}
{:tag :second, :attrs {:value A}, :content [{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello A]}]}]}
{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello A]}]}
{:tag :fourth, :attrs nil, :content [Hello A]}
Hello A
{:tag :second, :attrs {:value B}, :content [{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello B]}]}]}
{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello B]}]}
{:tag :fourth, :attrs nil, :content [Hello B]}
Hello B

Po ilustraci si výstupní sekvenci uložme do tabulky:

# Prvek
1 {:tag :first, :attrs nil, :content [{:tag :second, :attrs {:value A}, :content [{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello A]}]}]} {:tag :second, :attrs {:value B}, :content [{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello B]}]}]}]}
2 {:tag :second, :attrs {:value A}, :content [{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello A]}]}]}
3 {:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello A]}]}
4 {:tag :fourth, :attrs nil, :content [Hello A]}
5 Hello A
6 {:tag :second, :attrs {:value B}, :content [{:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello B]}]}]}
7 {:tag :third, :attrs nil, :content [{:tag :fourth, :attrs nil, :content [Hello B]}]}
8 {:tag :fourth, :attrs nil, :content [Hello B]}
9 Hello B

Samotná podoba sekvence může být poněkud překvapivá, ovšem skutečně se jedná o výsledek průchodu původním stromem (otázka pro čtenáře: jedná se o průchod typu pre-order, in-order či post-order?). Zajímavé je, že i textová hodnota uložená v uzlech fourth je vrácena jako samostatný prvek sekvence, čehož se ostatně v praxi často využívá.

Poznámka: vzhledem ke sdílení struktury v Clojure není výsledná sekvence nijak paměťově náročná, i když by se možná mohlo zdát, že se informace v jednotlivých prvcích musí duplikovat.

6. Čtvrtý demonstrační příklad: jednoduché filtry postavené na funkci xml-seq

Sekvenci prvků stromu získaného po syntaktické analýze XML souborů a po aplikaci funkce xml-seq, je možné použít různým způsobem. Poměrně elegantní je filtrace s využitím makra pojmenovaného for, které se v Clojure používá pro realizaci generátorové notace seznamu/sekvence (list comprehension). Připomeňme si, že toto makro podporuje i modifikátory :let, :while a :when. V našem případě se pro filtraci nejvíce hodí využití modifikátoru :when, což je ostatně patrné i při pohledu na uživatelské funkce filter-seq-1 a filter-seq-2:

(ns xmltest04.core)
 
(use '[clojure.xml])
(use '[clojure.pprint])
 
 
 
(defn filter-seq-1
    [parsed-xml]
    (for [item (xml-seq parsed-xml)
                :when (= :second (:tag item))]
             (:attrs item)))
 
(defn filter-seq-2
    [parsed-xml]
    (for [item (xml-seq parsed-xml)
                :when (= :fourth (:tag item))]
             (:content item)))
 
(defn xmltest04
    []
    (let [parsed-xml (clojure.xml/parse "nested.xml")]
        (clojure.pprint/pprint parsed-xml)
        (println "----------------------------------")
        (clojure.pprint/pprint (filter-seq-1 parsed-xml))
        (println "----------------------------------")
        (clojure.pprint/pprint (filter-seq-2 parsed-xml))))
 
(defn -main
    [& args]
    (xmltest04))

Výsledek běhu dnešního čtvrtého demonstračního příkladu:

{:tag :first,
 :attrs nil,
 :content
 [{:tag :second,
   :attrs {:value "A"},
   :content
   [{:tag :third,
     :attrs nil,
     :content [{:tag :fourth, :attrs nil, :content ["Hello A"]}]}]}
  {:tag :second,
   :attrs {:value "B"},
   :content
   [{:tag :third,
     :attrs nil,
     :content [{:tag :fourth, :attrs nil, :content ["Hello B"]}]}]}]}
----------------------------------
({:value "A"} {:value "B"})
----------------------------------
(["Hello A"] ["Hello B"])

Poznámka: samozřejmě by bylo možné použít i funkci filter, to je však v tomto případě zbytečně komplikované (tvorba anonymní funkce atd.).

7. Použití zipperů pro přístup k prvkům XML

Existuje ještě jeden poměrně elegantní a v mnoha případech i vhodný způsob přístupu k datům uloženým v XML souborech. Vzhledem k tomu, že obsah XML je reprezentován stromovou datovou strukturou, nabízí se použití takzvaných zipperů, které programátorům umožňují mj. i průchod stromem stylem „jdi na první poduzel“, „přesuň se na další uzel ve stejné úrovni“ atd. Běžný zipper je možné použít na jakoukoli základní datovou strukturu Clojure:

user=> (use '[clojure.zip])
 
user=> (doc zipper)
-------------------------
clojure.zip/zipper
([branch? children make-node root])
  Creates a new zipper structure.
 
  branch? is a fn that, given a node, returns true if can have
  children, even if it currently doesn't.
 
  children is a fn that, given a branch node, returns a seq of its
  children.
 
  make-node is a fn that, given an existing node and a seq of
  children, returns a new branch node with the supplied children.
  root is the root node.

Nás však bude namísto funkce zipper zajímat jeho speciální podoba určená přímo pro soubory typu XML. Tento zipper je vytvořen (a vrácen) funkcí clojure.zip/xml-zip:

user=> (use '[clojure.zip])
 
user=> (doc xml-zip)
-------------------------
clojure.zip/xml-zip
([root])
  Returns a zipper for xml elements (as from xml/parse),
  given a root element

8. Pátý demonstrační příklad: základy použití zipperů

Podívejme se na jeden ze způsobů použití zipperu. Ve zdrojovém kódu pátého demonstračního příkladu jsou funkce zipperu volány v rámci threading makra, což je výhodné, protože výstup z jedné funkce skutečně ihned použijeme ve funkci následující (navíc je kód značně čitelnější). Funkce clojure.zip/down a clojure.zip/right slouží pro průchod stromem, ovšem musíme si strom představit skutečně tak, jak se obvykle v informatice kreslí (kořen nahoře, poduzly kořenu jsou pod ním v jedné řadě atd.). XML struktura je v tomto případě poněkud matoucí, protože v ní je strom jakoby pootočen o 90°, takže směry „dolů“ a „doprava“ zde mají odlišný význam:

(ns xmltest05.core)
 
(use '[clojure.xml])
(use '[clojure.pprint])
(use '[clojure.zip])
 
(defn xmltest05
    []
    (let [parsed-xml (clojure.xml/parse "nested.xml")
          zipper     (clojure.zip/xml-zip parsed-xml)]
        (clojure.pprint/pprint parsed-xml)
        (println "----------------------------------")
        (println (:tag (clojure.zip/node zipper)))
        (println (:tag (-> zipper
                           clojure.zip/node)))
        (println (:tag (-> zipper
                           clojure.zip/down    ; prvni synovsky uzel
                           clojure.zip/node)))
        (println (:tag (-> zipper
                           clojure.zip/down    ; prvni synovsky uzel
                           clojure.zip/down    ; synovsky uzel prvniho synovskeho uzlu
                           clojure.zip/node)))
        (println (:attrs (-> zipper
                           clojure.zip/down    ; prvni synovsky uzel
                           clojure.zip/right   ; druhy uzel v rade
                           clojure.zip/node)))))
 
(defn -main
    [& args]
    (xmltest05))

Výsledek běhu pátého příkladu:

{:tag :first,
 :attrs nil,
 :content
 [{:tag :second,
   :attrs {:value "A"},
   :content
   [{:tag :third,
     :attrs nil,
     :content [{:tag :fourth, :attrs nil, :content ["Hello A"]}]}]}
  {:tag :second,
   :attrs {:value "B"},
   :content
   [{:tag :third,
     :attrs nil,
     :content [{:tag :fourth, :attrs nil, :content ["Hello B"]}]}]}]}
----------------------------------
:first
:first
:second
:third
{:value B}

9. Šestý demonstrační příklad: složitější zipper

Dnešní poslední demonstrační příklad je vlastně obdobou příkladu předchozího, ovšem threading makro je zde použito skutečně důsledně. Nejprve se provede načtení a syntaktická analýza souboru s XML, následně se na strom vzniklý syntaktickou analýzou aplikuje funkce clojure.zip/xml-zip a posléze již přichází čas pro průchod stromem s využitím zipperu a následně pro získání obsahu uzlu (:content node) a přečtení prvního (a jediného) prvku z obsahu (first content):

widgety

(ns xmltest06.core)
 
(use '[clojure.xml])
(use '[clojure.pprint])
(use '[clojure.zip])
 
(defn xmltest06
    []
    (let [parsed-xml (clojure.xml/parse "nested.xml")
          zipper     (clojure.zip/xml-zip parsed-xml)]
        (clojure.pprint/pprint parsed-xml)
        (println "----------------------------------")
        (println (-> zipper
                     clojure.zip/down   ; prvni synovsky uzel: <second>
                     clojure.zip/right  ; druhy synovsky uzel: (taktez <second>)
                     clojure.zip/down   ; poduzel: <third>
                     clojure.zip/down   ; poduzel: <fourth>
                     clojure.zip/node   ; hodnota uzlu <fourth>
                     :content           ; nahrada za get
                     first))            ; prvni (a jediny prvek vektoru)
                     ))
 
(defn -main
    [& args]
    (xmltest06))

Výsledek běhu šestého demonstračního příkladu:

{:tag :first,
 :attrs nil,
 :content
 [{:tag :second,
   :attrs {:value "A"},
   :content
   [{:tag :third,
     :attrs nil,
     :content [{:tag :fourth, :attrs nil, :content ["Hello A"]}]}]}
  {:tag :second,
   :attrs {:value "B"},
   :content
   [{:tag :third,
     :attrs nil,
     :content [{:tag :fourth, :attrs nil, :content ["Hello B"]}]}]}]}
----------------------------------
Hello B

10. Repositář s dnešními demonstračními příklady

Všech šest dnes popsaných demonstračních příkladů bylo, podobně jako v předchozích částech tohoto seriálu, uloženo do Git repositáře dostupného na adrese https://github.com/tisnik/clojure-examples. V tabulce zobrazené pod tímto odstavcem naleznete na zdrojové kódy jednotlivých demonstračních příkladů přímé odkazy:

11. Odkazy na předchozí části tohoto seriálu

  1. Leiningen: nástroj pro správu projektů napsaných v Clojure
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/
  2. Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/
  3. Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/
  4. Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/
  5. Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/
  6. Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/
  7. Programovací jazyk Clojure a databáze (1.část)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/
  8. Pluginy pro Leiningen
    http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/
  9. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/
  10. Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/
  11. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
    http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/
  12. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/
  13. Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/
  14. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/
  15. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (2)
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/
  16. Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
    http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/
  17. Programovací jazyk Clojure a práce s Gitem
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/
  18. Programovací jazyk Clojure a práce s Gitem (2)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/
  19. Programovací jazyk Clojure – triky při práci s řetězci
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/
  20. Programovací jazyk Clojure – triky při práci s kolekcemi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/
  21. Programovací jazyk Clojure – práce s mapami a množinami
    http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/

12. Odkazy na Internetu

  1. Clojure doc: zipper
    http://clojuredocs.org/clo­jure.zip/zipper
  2. Clojure doc: parse
    http://clojuredocs.org/clo­jure.xml/parse
  3. Clojure doc: xml-zip
    http://clojuredocs.org/clojure.zip/xml-zip
  4. Clojure doc: xml-seq
    http://clojuredocs.org/clo­jure.core/xml-seq
  5. Parsing XML in Clojure
    https://github.com/clojuredocs/guides
  6. Clojure Zipper Over Nested Vector
    https://vitalyper.wordpres­s.com/2010/11/23/clojure-zipper-over-nested-vector/
  7. Understanding Clojure's PersistentVector implementation
    http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation
  8. Understanding Clojure's PersistentHashMap (deftwice…)
    http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html
  9. Assoc and Clojure's PersistentHashMap: part ii
    http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html
  10. Ideal Hashtrees (paper)
    http://lampwww.epfl.ch/pa­pers/idealhashtrees.pdf
  11. Clojure home page
    http://clojure.org/
  12. Clojure (downloads)
    http://clojure.org/downloads
  13. Clojure Sequences
    http://clojure.org/sequences
  14. Clojure Data Structures
    http://clojure.org/data_structures
  15. The Structure and Interpretation of Computer Programs: 2.2.1 Representing Sequences
    http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-15.html#%_sec2.2.1
  16. The Structure and Interpretation of Computer Programs: 3.3.1 Mutable List Structure
    http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-22.html#%_sec3.3.1
  17. Clojure – Functional Programming for the JVM
    http://java.ociweb.com/mar­k/clojure/article.html
  18. Clojure quick reference
    http://faustus.webatu.com/clj-quick-ref.html
  19. 4Clojure
    http://www.4clojure.com/
  20. ClojureDoc (rozcestník s dokumentací jazyka Clojure)
    http://clojuredocs.org/
  21. Clojure (na Wikipedia EN)
    http://en.wikipedia.org/wiki/Clojure
  22. Clojure (na Wikipedia CS)
    http://cs.wikipedia.org/wiki/Clojure
  23. SICP (The Structure and Interpretation of Computer Programs)
    http://mitpress.mit.edu/sicp/
  24. Pure function
    http://en.wikipedia.org/wi­ki/Pure_function
  25. Funkcionální programování
    http://cs.wikipedia.org/wi­ki/Funkcionální_programová­ní
  26. Čistě funkcionální (datové struktury, jazyky, programování)
    http://cs.wikipedia.org/wi­ki/Čistě_funkcionální
  27. Clojure Macro Tutorial (Part I, Getting the Compiler to Write Your Code For You)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-i-getting.html
  28. Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html
  29. Clojure Macro Tutorial (Part III: Syntax Quote)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html
  30. Tech behind Tech: Clojure Macros Simplified
    http://techbehindtech.com/2010/09/28/clo­jure-macros-simplified/
  31. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  32. Eulerovo číslo
    http://cs.wikipedia.org/wi­ki/Eulerovo_číslo
  33. List comprehension
    http://en.wikipedia.org/wi­ki/List_comprehension
  34. List Comprehensions in Clojure
    http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html
  35. Clojure Programming Concepts: List Comprehension
    http://en.wikibooks.org/wi­ki/Clojure_Programming/Con­cepts#List_Comprehension
  36. Clojure core API: for macro
    http://clojure.github.com/clo­jure/clojure.core-api.html#clojure.core/for
  37. cirrus machina – The Clojure for macro
    http://www.cirrusmachina.com/blog/com­ment/the-clojure-for-macro/
  38. Riastradh's Lisp Style Rules
    http://mumble.net/~campbe­ll/scheme/style.txt
  39. Dynamic Languages Strike Back
    http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html
  40. Scripting: Higher Level Programming for the 21st Century
    http://www.tcl.tk/doc/scripting.html
  41. Java Virtual Machine Support for Non-Java Languages
    http://docs.oracle.com/ja­vase/7/docs/technotes/gui­des/vm/multiple-language-support.html
  42. Třída java.lang.String
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­g.html
  43. Třída java.lang.StringBuffer
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­gBuffer.html
  44. Třída java.lang.StringBuilder
    http://docs.oracle.com/ja­vase/7/docs/api/java/lang/Strin­gBuilder.html
  45. StringBuffer versus String
    http://www.javaworld.com/ar­ticle/2076072/build-ci-sdlc/stringbuffer-versus-string.html
  46. Threading macro (dokumentace k jazyku Clojure)
    https://clojure.github.io/clo­jure/clojure.core-api.html#clojure.core/->
  47. Understanding the Clojure → macro
    http://blog.fogus.me/2009/09/04/un­derstanding-the-clojure-macro/
  48. clojure.inspector
    http://clojure.github.io/clo­jure/clojure.inspector-api.html
  49. The Clojure Toolbox
    http://www.clojure-toolbox.com/
  50. Unit Testing in Clojure
    http://nakkaya.com/2009/11/18/unit-testing-in-clojure/
  51. Testing in Clojure (Part-1: Unit testing)
    http://blog.knoldus.com/2014/03/22/tes­ting-in-clojure-part-1-unit-testing/
  52. API for clojure.test – Clojure v1.6 (stable)
    https://clojure.github.io/clo­jure/clojure.test-api.html
  53. Leiningen: úvodní stránka
    http://leiningen.org/
  54. Leiningen: Git repository
    https://github.com/techno­mancy/leiningen
  55. leiningen-win-installer
    http://leiningen-win-installer.djpowell.net/
  56. Clojure 1: Úvod
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/
  57. Clojure 2: Symboly, kolekce atd.
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/
  58. Clojure 3: Funkcionální programování
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/
  59. Clojure 4: Kolekce, sekvence a lazy sekvence
    http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/
  60. Clojure 5: Sekvence, lazy sekvence a paralelní programy
    http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/
  61. Clojure 6: Podpora pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/
  62. Clojure 7: Další funkce pro paralelní programování
    http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/
  63. Clojure 8: Identity, stavy, neměnné hodnoty a reference
    http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/
  64. Clojure 9: Validátory, pozorovatelé a kooperace s Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/
  65. Clojure 10: Kooperace mezi Clojure a Javou
    http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/
  66. Clojure 11: Generátorová notace seznamu/list comprehension
    http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/
  67. Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
    http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/
  68. Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
    http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/
  69. Clojure 14: Základy práce se systémem maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/
  70. Clojure 15: Tvorba uživatelských maker
    http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/
  71. Clojure 16: Složitější uživatelská makra
    http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/
  72. Clojure 17: Využití standardních maker v praxi
    http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/
  73. Clojure 18: Základní techniky optimalizace aplikací
    http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/
  74. Clojure 19: Vývojová prostředí pro Clojure
    http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/
  75. Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
    http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/
  76. Clojure 21: ClojureScript aneb překlad Clojure do JS
    http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/
  77. Clojure.org: Vars and the Global Environment
    http://clojure.org/Vars
  78. Clojure.org: Refs and Transactions
    http://clojure.org/Refs
  79. Clojure.org: Atoms
    http://clojure.org/Atoms
  80. Clojure.org: Agents as Asynchronous Actions
    http://clojure.org/agents
  81. Transient Data Structureshttp://clojure.or­g/transients
Našli jste v článku chybu?
DigiZone.cz: Další programatické formáty

Další programatické formáty

Vitalia.cz: 5 důvodů, proč jet na výlov rybníka

5 důvodů, proč jet na výlov rybníka

Lupa.cz: Další Češi si nechali vložit do těla čip

Další Češi si nechali vložit do těla čip

Vitalia.cz: Inspekce našla nelegální sklad v SAPĚ. Zase

Inspekce našla nelegální sklad v SAPĚ. Zase

120na80.cz: Zlepšete si kondici s kořenem z Dálného východu

Zlepšete si kondici s kořenem z Dálného východu

DigiZone.cz: DVB-T2 ověřeno: seznam TV zveřejněn

DVB-T2 ověřeno: seznam TV zveřejněn

Vitalia.cz: Jsou vegani a vyrábějí nemléko

Jsou vegani a vyrábějí nemléko

Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

Byla finanční manažerka, teď cvičí jógu

Vitalia.cz: dTest odhalil ten nejlepší kečup

dTest odhalil ten nejlepší kečup

Lupa.cz: Jak se prodává firma za miliardu?

Jak se prodává firma za miliardu?

Vitalia.cz: Tahák, jak vyzrát nad zápachem z úst

Tahák, jak vyzrát nad zápachem z úst

DigiZone.cz: Koncesionářské poplatky pro RTVS

Koncesionářské poplatky pro RTVS

Vitalia.cz: Tohle jsou nejlepší česká piva podle odborníků

Tohle jsou nejlepší česká piva podle odborníků

Vitalia.cz: Voda z Vltavy před a po úpravě na pitnou

Voda z Vltavy před a po úpravě na pitnou

DigiZone.cz: Rapl: seriál, který vás smíří s ČT

Rapl: seriál, který vás smíří s ČT

Vitalia.cz: 5 pravidel proti infekci močových cest

5 pravidel proti infekci močových cest

DigiZone.cz: Wimbledon na Nova Sport až do 2019

Wimbledon na Nova Sport až do 2019

DigiZone.cz: Test: brýle pro virtuální realitu Exos Urban

Test: brýle pro virtuální realitu Exos Urban

Podnikatel.cz: Znáte už 5 novinek k #EET

Znáte už 5 novinek k #EET

DigiZone.cz: Technisat připravuje trojici DAB

Technisat připravuje trojici DAB