{"id":22772568,"url":"https://github.com/edarc/sxml-jaxp","last_synced_at":"2025-06-29T18:03:13.114Z","repository":{"id":1074386,"uuid":"915792","full_name":"edarc/sxml-jaxp","owner":"edarc","description":"Clojure library for using SXML-inspired XML respresentations with JAXP.","archived":false,"fork":false,"pushed_at":"2013-12-16T01:04:31.000Z","size":216,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-15T06:49:26.019Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/edarc.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2010-09-16T15:15:41.000Z","updated_at":"2023-08-21T12:34:36.000Z","dependencies_parsed_at":"2022-07-06T05:02:26.093Z","dependency_job_id":null,"html_url":"https://github.com/edarc/sxml-jaxp","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/edarc/sxml-jaxp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edarc%2Fsxml-jaxp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edarc%2Fsxml-jaxp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edarc%2Fsxml-jaxp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edarc%2Fsxml-jaxp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/edarc","download_url":"https://codeload.github.com/edarc/sxml-jaxp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edarc%2Fsxml-jaxp/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260816442,"owners_count":23067303,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-11T17:08:55.942Z","updated_at":"2025-06-29T18:03:13.091Z","avatar_url":"https://github.com/edarc.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"=========\nsxml-jaxp\n=========\n\n**sxml-jaxp** is a library of tools for using SXML-inspired XML representations\nwith the Java XML infrastructure. It uses JAXP internally, so it does not\ndepend on any particular XML library, although the author has personally tested\nit with the OpenJDK default Xerces/Xalan and Saxon 9.1.\n\nIncluded are tools for reading XML into SXML forms (using SAX), transforming\nSXML using XSL Transformations as well as converting it back to XML (using the\nTrAX APIs).\n\nClojure-flavored SXML\n=====================\n\nClojure-flavored SXML uses vectors, keywords, and maps to denote elements,\ntags, and attributes. [1]_\n\n.. code:: clojure\n\n  [:item {}\n    [:title {} \"Memorandum\"]\n    [:author {} \"tyler.durden@paperstreetsoap.com\"]\n    [:media/content {:url \"http://paperstreetsoap.com/snowflake.jpg\",\n                     :type \"image/jpeg\",\n                     :height \"100\",\n                     :width \"100\"}]\n    [:description {} \"You are not a beautiful and unique snowflake.\"]\n    [:some-other-thing {}]]\n\nElements take the form ``[tag attrs \u0026 children]``, where ``tag`` is a keyword\ndenoting the element name, ``attrs`` is a possibly-empty map of keywords\n(attribute names) to values (strings), and ``children`` is a possibly empty\nsequence of child nodes, which may be strings or other elements. This is the\n*normalized* form.\n\nThere is also a *simplified* form:\n\n.. code:: clojure\n\n  [:item\n    [:title \"Memorandum\"]\n    [:author \"tyler.durden@paperstreetsoap.com\"]\n    [:media/content {:url \"http://paperstreetsoap.com/snowflake.jpg\",\n                     :type \"image/jpeg\",\n                     :height \"100\",\n                     :width \"100\"}]\n    [:description \"You are not a beautiful and unique snowflake.\"]\n    :some-other-thing]\n\nIn this form, tags may be of the form ``[tag attrs \u0026 children]``, empty\nattribute maps can be elided as ``[tag \u0026 children]``, and elements with no\nchildren *or* attributes may elide the vector altogether, leaving a bare\nkeyword as ``tag``, where ``tag`` is a keyword denoting the element name,\n``attrs`` is a *non-empty* map of keywords, and ``children`` is a *non-empty*\nsequence of child nodes.\n\n``sxml-jaxp`` provides the function ``normalize`` to convert SXML to normalized\nform, and ``simplify`` to convert to simplified form. Functions generally\naccept either form (or some mixture), but typically return normalized form.\n\n.. [1] This is in contrast with the original Scheme SXML which uses lists and\n   symbols for everything.\n\nUsage\n=====\n\nHere are some examples of using ``sxml-jaxp`` for various tasks. We'll assume\nthe following ``require``'s:\n\n.. code:: clojure\n\n  (require '[sxml-jaxp.core :as core]\n           '[sxml-jaxp.sax :as sax]\n           '[sxml-jaxp.transform :as xfm]\n           '[sxml-jaxp.transform.xslt :as xsl]\n           '[clojure.java.io :as io])\n\nParsing XML to SXML\n-------------------\n\nYou can use the ``sxml-jaxp.sax/read-sxml`` function to read from some source\nof XML data and return it in SXML format:\n\n.. code:: clojure\n\n  user=\u003e (sax/read-sxml \"\u003cgreet\u003eHello world!\u003c/greet\u003e\")\n  [:greet {} \"Hello world!\"]\n\nYou can use ``Reader``'s, ``InputStream``'s, and ``File``'s too.\n\n.. code:: clojure\n\n  user=\u003e (sax/read-sxml (java.io.StringReader. \"\u003cgreet\u003eHello world!\u003c/greet\u003e\"))\n  [:greet {} \"Hello world!\"]\n\nSXML manipulation helpers\n-------------------------\n\nThere are several helper functions to allow you to easily access and modify\nSXML elements and forms.\n\nAccess functions\n................\n\nThe functions ``sxml-jaxp.core/tag``, ``attrs``, and ``children`` allow you to\naccess the components of SXML elements easily.\n\n.. code:: clojure\n\n  user=\u003e (def fancy-hello [:greet {:language \"en\"} \"Hello world!\"])\n  #'user/fancy-hello\n  user=\u003e (core/tag fancy-hello)\n  :greet\n  user=\u003e (core/attrs fancy-hello)\n  {:language \"en\"}\n  user=\u003e (core/children fancy-hello)\n  [\"Hello world!\"]\n\nThese are more robust than regular vector access methods, firstly because they\nwork on SXML that might not be normalized:\n\n.. code:: clojure\n\n  user=\u003e (def simple-hello [:greet \"Hello world!\"])\n  #'user/simple-hello\n  user=\u003e (core/attrs simple-hello)\n  {}\n  user=\u003e (core/children simple-hello)\n  [\"Hello world!\"]\n\nAdditionally, they are also XML-namespace-aware. They can help you propagate\nnamespace prefix declarations automatically when navigating, and keep them out\nof your hair when working with attributes:\n\n.. code:: clojure\n\n  user=\u003e (def namespacey-hello\n           [:hi/greetings\n            {:xmlns/hi \"http://w3.org/TR/Hello\" :language \"en\"}\n            [:hi/greet \"Hello world!\"]])\n  user=\u003e (core/attrs namespacey-hello)\n  {:language \"en\"}\n  user=\u003e (core/children namespacey-hello)\n  [[:hi/greet {:xmlns/hi \"http://w3.org/TR/Hello\"} \"Hello world!\"]]\n\nThere is also one other access function specifically for namespace\ndeclarations, ``ns-decls``:\n\n.. code:: clojure\n\n  user=\u003e (core/ns-decls namespacey-hello)\n  {:hi \"http://w3.org/TR/Hello\"}\n\nModification functions\n......................\n\nThe modification functions are in three groups, and all take an element as\ntheir first argument. The first is the *alter* group, which update an element\nby applying a function to some portion of it. These are ``alter-tag``,\n``alter-attrs``, ``alter-children`` and ``alter-ns-decls``:\n\n.. code:: clojure\n\n  user=\u003e (core/alter-tag fancy-hello (fn [t] (-\u003e t name .toUpperCase keyword)))\n  [:GREET {:language \"en\"} \"Hello world!\"]\n  user=\u003e (core/alter-attrs fancy-hello #(assoc % :language \"en-US\"))\n  [:greet {:language \"en-US\"} \"Hello world!\"]\n  user=\u003e (core/alter-children namespacey-hello (partial mapcat core/children))\n  [:hi/greetings\n   {:xmlns/hi \"http://w3.org/TR/Hello\", :language \"en\"}\n   \"Hello world!\"]\n  user=\u003e (core/alter-ns-decls\n           namespacey-hello (fn [nsd] (assoc nsd nil (:hi nsd))))\n  [:hi/greetings\n   {:xmlns/hi \"http://w3.org/TR/Hello\",\n    :xmlns \"http://w3.org/TR/Hello\",\n    :language \"en\"}\n   [:hi/greet \"Hello world!\"]]\n\nThe second group is the *replace* group, ``replace-tag``, ``replace-attrs``,\n``replace-children``, ``replace-ns-decls``. These are shorthand for altering an\nelement by replacing it with a constant value [2]_:\n\n.. code:: clojure\n\n  user=\u003e (core/replace-tag fancy-hello :salutation)\n  [:salutation {:language \"en\"} \"Hello world!\"]\n  user=\u003e (core/replace-children fancy-hello [[:with-feeling \"Hello world!!!\"]])\n  [:greet {:language \"en\"} [:with-feeling \"Hello world!!!\"]]\n\nThe third group is the special group, which contains ``update-attrs``,\n``update-ns-decls``, and ``map-children``. These are also shorthand, for\naltering the attributes or XML namespace declarations by merging a map of new\nand updated values, like Clojure's ``merge`` function. [2]_\n\n``map-children`` is similar to ``alter-children`` except that it maps the\nfunction across each child element in turn, while ``alter-children`` calls the\nfunction once and passes the entire sequence of children as the parameter.\n\n.. code:: clojure\n\n  user=\u003e (core/map-children [:parent :one :two :three [:four \"4\"]]\n                            (comp name core/tag))\n  [:parent {} \"one\" \"two\" \"three\" \"four\"]\n\nThere are also two tiny combinators for helping construct functions to pass\ninto ``alter-*`` and ``map-children``, which are named ``on-tags`` and\n``on-text``. These work by turning your function into an identity when the type\nof element passed is not a tag or a text node:\n\n.. code:: clojure\n\n  user=\u003e (core/map-children [:parent :one :two :three \"surprise\"]\n                            (comp name core/tag))\n  ClassCastException java.lang.Character cannot be cast to clojure.lang.Named\n  clojure.core/name (core.clj:1505)\n  user=\u003e (core/map-children [:parent :one :two :three \"surprise\"]\n                            (core/on-tags (comp name core/tag)))\n  [:parent {} \"one\" \"two\" \"three\" \"surprise\"]\n  user=\u003e (core/map-children [:parent :one :two :three \"surprise\"]\n                            (core/on-text #(.toUpperCase %)))\n  [:parent {} :one :two :three \"SURPRISE\"]\n\n.. [2] They are implemented using the ``alter-`` functions with Clojure's\n   ``constantly`` and ``merge`` functions.\n\nOutputting to XML\n-----------------\n\nThe ``sxml-jaxp.transform/copy!`` function can be used to copy SXML into various\nkinds of output \"sinks\". Here, we'll use a ``Writer``. Notice it returns the\nthing you passed as the \"sink\" so you can do more stuff with it:\n\n.. code:: clojure\n\n  user=\u003e (.toString (xfm/copy! fancy-hello (java.io.StringWriter.)))\n  \"\u003c?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?\u003e\u003cgreet language=\\\"en\\\"\u003eHello world!\u003c/greet\u003e\"\n\n``copy!`` also recognizes the special sink ``:string``, which is the default\nwhen you don't provide a sink. [3]_ This causes it to return the source as a\nstring of XML:\n\n.. code:: clojure\n\n  user=\u003e (xfm/copy! fancy-hello :string)\n  \"\u003c?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?\u003e\u003cgreet language=\\\"en\\\"\u003eHello world!\u003c/greet\u003e\"\n  user=\u003e (xfm/copy! fancy-hello)\n  \"\u003c?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?\u003e\u003cgreet language=\\\"en\\\"\u003eHello world!\u003c/greet\u003e\"\n\nXSL Transforms\n--------------\n\nTransformations are performed with the ``sxml-jaxp.transform/transform!``\nfunction.  This accepts a stylesheet, a source, and a result. I'll use the XSLT\nDSL (defined in ``sxml-jaxp.transform.xslt``) to create XSLT stylesheets.\n\n.. code:: clojure\n\n  user=\u003e (xfm/transform! (xsl/stylesheet \"1.0\"\n                           (xsl/match-template \"/once-old\"\n                             [:new-again (xsl/copy-of \"@*|node()\")]))\n                         [:once-old \"Hi!\"])\n  [:new-again {} \"Hi!\"]\n\nI didn't provide a target for the result, so it defaulted to the special target\n``:sxml`` [3]_. Like ``copy!``, it recognizes the special target ``:string`` as\nwell, and you can use any other reasonable object as your result target.\n\nHere's a more complex example, getting a seq of the latest article titles on\nArs Technica using their RSS feed:\n\n.. code:: clojure\n\n  user=\u003e (def rss-title-tmpl\n           (xfm/compile-template\n             (xsl/stylesheet \"1.0\"\n               (xsl/match-template \"/rss/channel/item\"\n                 [:link {:title \"{title}\"}])\n               (xsl/match-template \"/rss\"\n                 [:items (xsl/apply-templates-to \"channel/item\")]))))\n  #'user/rss-title-tmpl\n  user=\u003e (with-open [at-rss-in (io/input-stream\n                                 \"http://feeds.arstechnica.com/arstechnica/everything\")]\n           (map (comp :title core/attrs)\n                (core/children (xfm/transform! rss-title-tmpl at-rss-in))))\n  (\"Forget Amazon’s two-day shipping, soon you can select drone delivery\"\n   \"Why Comcast and other cable ISPs aren’t selling you gigabit Internet\"\n   \"What’s the difference between college-level and corporate programming?\"\n   \"Comet ISON fizzles… but there’s a sting in the tail\"\n   \"Despacio: The 50,000-watt sound system designed for discerning audiophiles\"\n   \"Anti-GMO crop paper to be forcibly retracted\"\n   \"Gallery: Disorienting audiovisual show prepares you for teleportation\"\n   \"Off Siberia’s Arctic coast, the seafloor belches methane\"\n   \"Ars’ resident racer takes a second look at Forza Motorsport 5\"\n   \"Chairs Technica: Where your favorite Ars writers park their rears\"\n   \"Five complaints Ars readers have about OS X Mavericks\"\n   \"Unhappy Thanksgiving for Prenda Law, ordered to pay $261K to defendants\"\n   \"TV news team falls for Facebook doppelgänger scam\"\n   \"Robot Garden 1.0: Putting Click and Grow to the test\"\n   \"Water-repellant surface so efficient that drops bounce back off\"\n   \"Successful killing by stealthy seahorses comes down to their snouts\"\n   \"Tricksy hobbit-sized black hole pretends to be a giant\"\n   \"Ars Technica System Guide: November 2013\"\n   \"Dealmaster Black Friday blowout continues, with updated deals!\"\n   \"Google removes CyanogenMod Installer from Play Store\"\n   \"How to talk your family out of bad consumer electronics purchases\"\n   \"Once-great SSD manufacturer OCZ filing for bankruptcy\"\n   \"Catch up on last-gen gaming with these Black Friday deals\"\n   \"New Linux worm targets routers, cameras, “Internet of things” devices\"\n   \"Elusive Higgs decay channel spotted; particle looks ever more standard\")\n\nHere we've pre-compiled our XSL template using ``compile-template``. This can\nbe used if you plan on transforming more than one document with a particular\nstylesheet. It uses TrAX to compile the template into some object implementing\n``Templates``, so that it doesn't have to parse and compile it for every\ninvocation.\n\n.. [3] ``copy!`` actually recognizes the ``:sxml`` sink also, although I don't\n   know why you'd ever need that; generally you'd want to use\n   ``sxml-jaxp.sax/read-sxml`` which bypasses TrAX and reads the input directly\n   with SAX.\n\nXSLT DSL\n........\n\nThe namespace ``sxml-jaxp.transform.xslt`` [4]_ defines a DSL for writing XSL\ntransformation stylesheets in Clojure. This DSL outputs the stylesheets in SXML\nformat. Here's the template we used in the last example:\n\n.. code:: clojure\n\n  user=\u003e (xsl/stylesheet \"1.0\"\n           (xsl/match-template \"/rss/channel/item\"\n             [:link {:title \"{title}\"}])\n           (xsl/match-template \"/rss\"\n             [:items (xsl/apply-templates-to \"channel/item\")]))\n  [:xsl/stylesheet\n   {:xmlns/xsl \"http://www.w3.org/1999/XSL/Transform\", :version \"1.0\"}\n   [:xsl/template\n    {:match \"/rss/channel/item\"}\n    [:link {:title \"{title}\"}]]\n   [:xsl/template\n    {:match \"/rss\"}\n    [:items [:xsl/apply-templates {:select \"channel/item\"}]]]]\n\nIt does not abstract XSLT very much, except for defining some instructions to\naccept positional parameters when they are otherwise always required as\nattributes. For example, ``\u003cxsl:value-of /\u003e`` always requires a ``select``\nattribute, so ``\u003cxsl:value-of select=\"foo\" /\u003e`` is written simply\n``(xsl/value-of \"foo\")``. Additional, optional attributes can be added by\nsupplying a map after the positional parameter.\n\nThere are a handful of exceptions:\n\n* ``\u003cxsl:template /\u003e`` is actually exposed as two separate functions,\n  ``match-template`` and ``named-template``, where the positional argument is\n  the XPath ``match`` expression and the template name, respectively, since it\n  is fairly common to specify either one or the other.\n\n* ``\u003cxsl:choose /\u003e``, a particularly contorted and wordy XSLT construct, is\n  exposed as ``cond*``, which looks like an ordinary Clojure ``cond`` except\n  that in the predicate position are boolean XPath expressions (which appear\n  in the ``\u003cxsl:when test=\"\" /\u003e`` attribute) or ``:else`` (for\n  ``\u003cxsl:otherwise /\u003e``), and in the consequent position is the contents of\n  the ``when`` or ``otherwise`` instructions. You can put multiple elements\n  inside the consequent by placing them in a vector, as long as the vector\n  does not start with a keyword:\n\n  .. code:: clojure\n\n    user=\u003e (xsl/cond*\n             \"foo\" (xsl/value-of \"foo\")\n             \"bar\" :bar\n             :else [[:foo \"bar\"] [:baz \"baz\"]])\n    [:xsl/choose\n     [:xsl/when {:test \"foo\"} [:xsl/value-of {:select \"foo\"}]]\n     [:xsl/when {:test \"bar\"} :bar]\n     [:xsl/otherwise [:foo \"bar\"] [:baz \"baz\"]]]\n\n* ``\u003cxsl:if /\u003e`` is exposed as ``if*``. Beware that it behaves like XSLT\n  ``\u003cxsl:if /\u003e`` and does not accept an alternate expression like Clojure's\n  ``if``; all arguments after the condition expression are part of the\n  consequent. (It is more akin to Clojure's ``when``). If you need to express\n  an alternate, use ``cond*``.\n\n* ``\u003cxsl:apply-templates /\u003e`` is exposed as ``apply-templates`` for the\n  wildcard case, and ``apply-templates-to`` for the selective case. The latter\n  accepts as it's positional parameter the XPath expression appearing in the\n  ``select`` attribute.\n\n.. [4] ``:use``'ing the ``sxml-jaxp.transform.xslt`` namespace should be done\n   with caution, as XSLT uses names for several instructions that collide with\n   identically-named Clojure core functions. Use ``:only``, ``:exclude``, or\n   ``:refer-clojure`` to control these collisions if you absolutely must\n   ``:use`` the XSLT DSL namespace.\n\nXML namespaces\n==============\n\nAs has been mentioned, ``sxml-jaxp`` is XML-namespace-aware. As you've probably\nguessed from the preceding sections, namespaces on keywords in SXML are\ninterpreted as XML namespace prefixes, e.g. ``:xsl/stylesheet``,\n``:xi/include``, or ``:fo/page-sequence``.\n\nNamespace prefix declarations are also specified in an analogous way to XML:\nusing ``xmlns`` attributes:\n\n.. code:: clojure\n\n  [:html {:xmlns \"http://www.w3.org/1999/xhtml\",\n          :xmlns/xi \"http://www.w3.org/2001/XInclude\"}\n   [:head [:title \"Namespace example\"]]\n   [:xi/include {:href \"body.xml\"}]]\n\nThese attributes are recognized as namespace prefix declarations and\ncommunicated to the various Java XML APIs as required.\n\nWhenever an SXML form is traversed by ``sxml-jaxp``'s SAX reader, a map\ncontained in ``sxml-jaxp.sax/*default-xmlns*`` is used to resolve un-declared\nnamespace prefixes:\n\n.. code:: clojure\n\n  user=\u003e (use '[sxml-jaxp.sax :only [*default-xmlns*]])\n  nil\n  user=\u003e (binding [*default-xmlns* {nil \"http://www.w3.org/1999/xhtml\",\n                                    :xi \"http://www.w3.org/2001/XInclude\"}]\n           (xfm/copy! [:html\n                       [:head [:title \"Namespace example\"]]\n                       [:xi/include {:href \"body.xml\"}]]\n                      *out*))\n  \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\u003chtml xmlns=\"http://www.w3.org/1999/xhtml\"\n                                              xmlns:xi=\"http://www.w3.org/2001/XInclude\"\u003e\n     \u003chead\u003e\n        \u003cmeta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /\u003e\n        \u003ctitle\u003eNamespace example\u003c/title\u003e\n     \u003c/head\u003e\n     \u003cxi:include href=\"body.xml\"\u003e\u003c/xi:include\u003e\n  \u003c/html\u003e#\u003cOutputStreamWriter java.io.OutputStreamWriter@484ae502\u003e\n\nNote that for convenience, ``sxml-jaxp.transform.xslt/stylesheet``\nautomatically declares the ``xsl`` prefix.\n\nSAX event filters\n=================\n\nThe ``sxml-jaxp.sax.filter`` module allows filters to be inserted which operate\non the SAX event seq [5]_ generated when SXML is fed as input into JAXP. This\nAPI is experimental, but an example application of this is the Hiccup filter in\n``sxml-jaxp.sax.filter.hiccup``, which allows writing XHTML ``id`` and\n``class`` attributes using Hiccup's shortcut syntax. Here we'll use\n``xfm/copy!``'s ``:sxml`` target to help make it clearer what's going on:\n\n.. code:: clojure\n\n  user=\u003e (use '[sxml-jaxp.sax.filter]\n              '[sxml-jaxp.sax.filter.hiccup])\n  nil\n  user=\u003e (def hiccup-example\n           [:html\n            [:div#main\n             [:p.example.first \"An example\"]\n             [:p.example \"Another example\"]]])\n  #'user/hiccup-example\n  user=\u003e (xfm/copy! (filter-with [hiccup] hiccup-example) :sxml)\n  [:html\n   {}\n   [:div\n    {:id \"main\"}\n    [:p {:class \"example first\"} \"An example\"]\n    [:p {:class \"example\"} \"Another example\"]]]\n\nIf an ``:id`` key appears in an element's attribute map, it overrides the\nHiccup-specified one. If a ``:class`` key is present in the attribute map, it\nmay be a HTML-style space-delimited string, or a set of strings. The class\nnames so specified are unioned with the Hiccup-specified classes.\n\n.. code:: clojure\n\n  user=\u003e (xfm/copy! (filter-with [hiccup]\n                      [:div#old {:id \"new\"}]) :sxml)\n  [:div {:id \"new\"}]\n  user=\u003e (xfm/copy! (filter-with [hiccup]\n                      [:div.a.b {:class \"b c\"}]) :sxml)\n  [:div {:class \"a b c\"}]\n\n.. [5] The SAX event seq format was originally added to decouple SXML traversal\n   from the dirty work of interoperating with the Java SAX API. Perhaps in the\n   future, the SAX event seq format will be available in more parts of the API,\n   to make the filter feature more useful and composable.\n\nSXML precompilation\n-------------------\n\n**Here be dragons.**\n\nSXML can be \"pre-compiled\", in a sense, by converting it to SAX event seq\nformat ahead of time. This allows the SAX interop to get better performance by\npre-computing the traversal of an oft-used SXML form. The\n``sxml-jaxp.transform`` APIs all accept this format as input.  The easiest way\nto use this is the ``sxml-jaxp.sax/compiled-sxml`` macro, which will\npre-compile a literal SXML form at compile time:\n\n.. code:: clojure\n\n  user=\u003e (let [a \"foo\" b \"bar\" c \"baz\"]\n           (xfm/copy! (sax/compiled-sxml [:root a b [:c c]])))\n  \"\u003c?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?\u003e\u003croot\u003efoobar\u003cc\u003ebaz\u003c/c\u003e\u003c/root\u003e\"\n\nIt comes in a vanilla function version as well, ``compile-sxml``.\n\nHowever, there are several caveats in the current implementation (which may be\nfixable but I haven't thought about it enough):\n\n* Expressions may be used in the content of a pre-compiled literal, but in the\n  current implementation, they are are fixed as element names when at the head\n  of a vector, and as text nodes anywhere else. They cannot affect the element\n  structure of the resulting document:\n\n  .. code:: clojure\n\n    user=\u003e (let [elem :go]\n             (xfm/copy! (sax/compiled-sxml [:ready :set elem [elem]])))\n    \"\u003c?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?\u003e\u003cready\u003e\u003cset/\u003e:go\u003cgo/\u003e\u003c/ready\u003e\"\n    user=\u003e (let [fail [:fail \"fail!\"]]\n             (xfm/copy! (sax/compiled-sxml [:ready :set fail])))\n    \"\u003c?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?\u003e\u003cready\u003e\u003cset/\u003e[:fail \\\"fail!\\\"]\u003c/ready\u003e\"\n\n* Attributes must be literal maps, but they may contain expressions in the\n  key and value positions. This is probably much easier to fix.\n\nLimitations and future work\n===========================\n\n* Currently the SXML parser ignores processing instructions, and there is no\n  way to express a processing instruction in SXML. Advice and suggestions\n  welcome.\n\n* Add support for interoperating with the ``clojure.xml`` data format, and\n  investigate if there is anything interesting to add for traversing SXML with\n  ``clojure.walk``.\n\n* XPath support would be pretty awesome. This can probably be done by providing\n  some help with feeding SXML into a ``Document``, along with a function to run\n  XPath expressions against it and SXMLify the result.\n\n* Allow filters to be more composable by separating the SAX parser into two\n  stages, such that an event seq is generated first, and the shift-reduce SXML\n  generation operates on that. Then stream filters can be inserted between\n  them. Currently the SAX handler directly feeds the SXML generator.\n\nLicense\n=======\n\n``sxml-jaxp`` is Copyright (C) 2010-2013 Kyle Schaffrick.\n\nDistributed under the Eclipse Public License, the same as Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedarc%2Fsxml-jaxp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fedarc%2Fsxml-jaxp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedarc%2Fsxml-jaxp/lists"}