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
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í:
- 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.
- Atributy jsou reprezentovány mapou klíč–hodnota, kde klíč je opět symbolem a nikoli řetězcem.
- Obsahem uzlu je vektor s poduzlem/poduzly nebo přímo s hodnotou.
- 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):
(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
- Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - 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/ - 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/ - 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/ - 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/ - 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/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - 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/ - 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/ - 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/ - 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/ - 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/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - 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/ - 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/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/ - Programovací jazyk Clojure – triky při práci s řetězci
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/ - Programovací jazyk Clojure – triky při práci s kolekcemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/ - 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
- Clojure doc: zipper
http://clojuredocs.org/clojure.zip/zipper - Clojure doc: parse
http://clojuredocs.org/clojure.xml/parse - Clojure doc: xml-zip
http://clojuredocs.org/clojure.zip/xml-zip - Clojure doc: xml-seq
http://clojuredocs.org/clojure.core/xml-seq - Parsing XML in Clojure
https://github.com/clojuredocs/guides - Clojure Zipper Over Nested Vector
https://vitalyper.wordpress.com/2010/11/23/clojure-zipper-over-nested-vector/ - Understanding Clojure's PersistentVector implementation
http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation - Understanding Clojure's PersistentHashMap (deftwice…)
http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html - Assoc and Clojure's PersistentHashMap: part ii
http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html - Ideal Hashtrees (paper)
http://lampwww.epfl.ch/papers/idealhashtrees.pdf - Clojure home page
http://clojure.org/ - Clojure (downloads)
http://clojure.org/downloads - Clojure Sequences
http://clojure.org/sequences - Clojure Data Structures
http://clojure.org/data_structures - 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 - 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 - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc (rozcestník s dokumentací jazyka Clojure)
http://clojuredocs.org/ - Clojure (na Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (na Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - SICP (The Structure and Interpretation of Computer Programs)
http://mitpress.mit.edu/sicp/ - Pure function
http://en.wikipedia.org/wiki/Pure_function - Funkcionální programování
http://cs.wikipedia.org/wiki/Funkcionální_programování - Čistě funkcionální (datové struktury, jazyky, programování)
http://cs.wikipedia.org/wiki/Čistě_funkcionální - 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 - Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html - Clojure Macro Tutorial (Part III: Syntax Quote)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html - Tech behind Tech: Clojure Macros Simplified
http://techbehindtech.com/2010/09/28/clojure-macros-simplified/ - Fatvat – Exploring functional programming: Clojure Macros
http://www.fatvat.co.uk/2009/02/clojure-macros.html - Eulerovo číslo
http://cs.wikipedia.org/wiki/Eulerovo_číslo - List comprehension
http://en.wikipedia.org/wiki/List_comprehension - List Comprehensions in Clojure
http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html - Clojure Programming Concepts: List Comprehension
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#List_Comprehension - Clojure core API: for macro
http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/for - cirrus machina – The Clojure for macro
http://www.cirrusmachina.com/blog/comment/the-clojure-for-macro/ - Riastradh's Lisp Style Rules
http://mumble.net/~campbell/scheme/style.txt - Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Java Virtual Machine Support for Non-Java Languages
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html - Třída java.lang.String
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html - Třída java.lang.StringBuffer
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html - Třída java.lang.StringBuilder
http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html - StringBuffer versus String
http://www.javaworld.com/article/2076072/build-ci-sdlc/stringbuffer-versus-string.html - Threading macro (dokumentace k jazyku Clojure)
https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/-> - Understanding the Clojure → macro
http://blog.fogus.me/2009/09/04/understanding-the-clojure-macro/ - clojure.inspector
http://clojure.github.io/clojure/clojure.inspector-api.html - The Clojure Toolbox
http://www.clojure-toolbox.com/ - Unit Testing in Clojure
http://nakkaya.com/2009/11/18/unit-testing-in-clojure/ - Testing in Clojure (Part-1: Unit testing)
http://blog.knoldus.com/2014/03/22/testing-in-clojure-part-1-unit-testing/ - API for clojure.test – Clojure v1.6 (stable)
https://clojure.github.io/clojure/clojure.test-api.html - Leiningen: úvodní stránka
http://leiningen.org/ - Leiningen: Git repository
https://github.com/technomancy/leiningen - leiningen-win-installer
http://leiningen-win-installer.djpowell.net/ - Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - 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/ - 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/ - 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/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - 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/ - 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/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - 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/ - 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/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - 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/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/ - Clojure.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - Transient Data Structureshttp://clojure.org/transients