clojure.data.xml

repository·master·Indexed 42 days ago

https://github.com/clojure/data.xml

A Clojure library for reading and writing XML data using StAX. It provides lazy parsing of large XML documents into Clojure data structures and supports emitting XML via element maps or Hiccup-style S-expressions. Features include XML namespace handling with QNames, location metadata tracking, and ClojureScript integration with the native DOM. Available in stable version 0.0.8 and preview version 0.2.0.

Tokens
3K
Snippets
10
Records
10
Agent score
4%

What's inside clojure.data.xml

  1. Handle XML Namespaces with QNames and Keywords

    master

    In data.xml, XML Namespaced names (QNames) are encoded into Clojure keywords by percent-encoding the namespace URI. For example, {http://www.w3.org/1999/xhtml}head becomes :http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml/head.

    When parsing, the resulting tag will be a keyword with the encoded namespace. When emitting, you can use xml/alias-uri to create shorthands for namespaces, allowing you to use Clojure's ::kw-ns/shorthands (e.g., ::xh/html).

    ;; Parsing a namespaced element
    (xml/parse-str "<?xml version="1.0" encoding="UTF-8"?>
                    <foo:html xmlns:foo="http://www.w3.org/1999/xhtml"/>")
    ;; => #xml/element{:tag :xmlns.http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml/html}
    
    ;; Emitting with aliases
    (xml/alias-uri 'xh "http://www.w3.org/1999/xhtml")
    (xml/emit-str {:tag ::xh/html :content []})
    ;; => <?xml version="1.0" encoding="UTF-8"?>
    ;;    <a:html xmlns:a="http://www.w3.org/1999/xhtml"></a:html>
  2. Use data.xml in ClojureScript with Native DOM

    master

    In ClojureScript, data.xml provides integration with the browser's native DOM.

    • Parse to DOM: Call parse with :raw true to get native DOM nodes instead of Clojure maps.
    • Treat DOM as Data: Call (extend-dom-as-data!) to extend native DOM prototypes to ClojureScript collection protocols, allowing you to treat DOM nodes like data.xml parse trees.
    • Coercion: Use element-node to coerce to native DOM and element-data to coerce to data.xml records.

    Note: Streaming is not currently supported in ClojureScript; only the *-str variants of parse and emit are implemented as wrappers for native browser XML functions.

    ```clojure
    ;; Example ClojureScript usage pattern
    (require '[clojure.data.xml :as xml])
    
    ;; Parse into native DOM
    (let [dom (xml/parse ".<div/>" :raw true)]
      ;; Use extend-dom-as-data! to treat 'dom' like a data.xml tree
      (xml/extend-dom-as-data!)
      (println (.tagName dom)))```
  3. Install data.xml

    master

    You can install data.xml using Maven, Leiningen, or Clojure CLI (deps.edn).

    Note that the 0.2.0 series (preview) includes support for XML Namespaces and Clojurescript, whereas 0.0.8 is the latest stable release.

    ;; For Clojure CLI (deps.edn)
    ;; Stable version:
    org.clojure/data.xml {:mvn/version "0.0.8"}
    
    ;; Preview version (Namespace/Clojurescript support):
    org.clojure/data.xml {:mvn/version "0.2.0-alpha11"}
    
    ;; For Leiningen (project.clj)
    [org.clojure/data.xml "0.0.8"]
    
    ;; For Maven (pom.xml)
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>data.xml</artifactId>
      <version>0.0.8</version>
    </dependency>
  4. Customize XML Namespace Prefixes

    master

    By default, data.xml generates prefixes automatically if they are not specified. To customize a prefix, explicitly declare it as an attribute in the xmlns keyword-namespace.

    Note that javax.xml.namespace.QName instances and strings with the {ns}name encoding are also supported for tag definitions.

    ;; Explicitly setting a prefix 'foo' via xmlns/foo
    (xml/emit-str
      (xml/element (xml/qname "http://www.w3.org/1999/xhtml" "title")
                   {:xmlns/foo "http://www.w3.org/1999/xhtml"}
                   "Example title"))
    ;; => <foo:title xmlns:foo="http://www.w3.org/1999/xhtml">Example title</foo:title>
    
    ;; Using string encoding
    (xml/emit-str {:tag "{http://www.w3.org/1999/xhtml}html"})
    
    ;; Using QName instances
    (xml/emit-str {:tag (xml/qname "http://www.w3.org/1999/xhtml" "html")})
  5. Emit Namespaced XML without prefixes

    master

    To emit namespaced tags without a prefix (using the default namespace), set the xmlns attribute on the root element to match the URI used in your namespace aliases. You can do this using standard element maps or the more concise Hiccup-style syntax via xml/sexp-as-element.

    ```clojure
    ;; Using standard element maps
    (xml/alias-uri 'xh "http://www.w3.org/1999/xhtml")
    (xml/emit-str
      (xml/element ::xh/html
                   {:xmlns "http://www.w3.org/1999/xhtml"}
                   (xml/element ::xh/head)
                   (xml/element ::xh/body {} "DOCUMENT")))
    
    ;; Using Hiccup-style syntax
    (xml/emit-str
      (xml/sexp-as-element
        [::xh/html {:xmlns "http://www.w3.org/1999/xhtml"}
         [::xh/head]
         [::xh/body "DOCUMENTGreat
    ]]))```
  6. Emit Clojure data as XML

    master

    To write XML, you can use the clojure.data.xml/element function, plain maps with :tag, :attrs, and :content keys, or a Hiccup-style S-expression via sexp-as-element. Use xml/emit to write to a java.io.Writer or xml/emit-str to get a string.

    (require '[clojure.data.xml :as xml])
    
    ;; Using the element function to write to a file
    (let [tags (xml/element :foo {:foo-attr "foo value"}
                     (xml/element :bar {:bar-attr "bar value"}
                       (xml/element :baz {} "The baz value"))))]
      (with-open [out-file (java.io.FileWriter. "/tmp/foo.xml")]
        (xml/emit tags out-file)))
    
    ;; Using Hiccup-style S-expressions
    (xml/sexp-as-element [:foo {:foo-attr "foo value"}
                          [:bar {:bar-attr "bar value"}
                           [:baz {} "The baz value"]]])
  7. Parse XML into Clojure data structures

    master

    Use clojure.data.xml/parse to read XML from a java.io.Reader or java.io.InputStream. The resulting data is returned as defrecords which can be manipulated like standard Clojure data structures.

    You can also use parse-str for string-based input. For specific parsing behaviors, such as CDATA handling, you can pass additional options like :coalescing.

    (require '[clojure.data.xml :as xml])
    
    ;; Parsing from a Reader
    (let [input-xml (java.io.StringReader. "<?xml version="1.0" encoding="UTF-8"?>
                                            <foo><bar><baz>The baz value</baz></bar></foo>")]
      (xml/parse input-xml))
    
    ;; Parsing from a String with options
    (xml/parse-str "<a><![CDATA[\nfoo bar\n]]><![CDATA[\nbaz\n]]></a>" :coalescing false)
  8. Emit CDATA and XML Comments

    master

    You can include CDATA sections and XML comments in your output by using special helper functions or specific S-expression tags.

    Note on CDATA: While xml/cdata allows you to emit CDATA, these sections are read back as regular character data during parsing. Note on Comments: XML comments can be emitted, but they are ignored when the XML is parsed back into data structures.

    (require '[clojure.data.xml :as xml])
    
    ;; Emitting CDATA
    (xml/emit-str (xml/element :foo {}
                    (xml/cdata "<non><escaped><info><here>")))
    
    ;; Emitting Comments
    (xml/emit-str
      (xml/element :foo {}
        (xml/xml-comment "Just a <comment> goes here")
        (xml/element :bar {} "and another element")))
    
    ;; Using S-expression syntax for CDATA/Comments
    (xml/sexp-as-element [:tag {:attr "value"} [:body {} [:-cdata "not parsed <stuff"]] ])
    (xml/sexp-as-element [:tag {:attr "value"} [:body {} [:-comment "comment text"]] ])
  9. Format XML with indentation for debugging

    master

    The library provides xml/indent-str to produce pretty-printed XML strings. This is intended as a debugging feature and may be slow for large documents.

    (print (xml/indent-str (xml/element :foo {:foo-attr "foo value"}
                             (xml/element :bar {:bar-attr "bar value"}
                               (xml/element :baz {} "The baz value1")
                               (xml/element :baz {} "The baz value2"))))))
  10. Access XML Location Information

    master

    The parser can attach location metadata to elements. This metadata includes :character-offset, :column-number, and :line-number, all accessible under the :clojure.data.xml/location-info key in the element's metadata.

    To disable this behavior and improve performance, pass :location-info false to the parser.

    ;; Accessing location info
    (let [input "<a><b/>\n<b/></a>"
          location-meta (comp :clojure.data.xml/location-info meta)]
      (-> input xml/parse-str location-meta :line-number))
    ;; => 1
    
    ;; Disabling location info
    (xml/parse-str your-input :location-info false)