pax_global_header00006660000000000000000000000064133762646300014524gustar00rootroot0000000000000052 comment=f05bcf4eedbe813945ee9005b53cb1b761aa5989 data.xml-data.xml-0.2.0-alpha6/000077500000000000000000000000001337626463000161125ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/.gitignore000066400000000000000000000002411337626463000200770ustar00rootroot00000000000000/target/ modules/xml/target/ modules/xml.pull-parser/target/ *~ /out/ /node_modules/ /nashorn_code_cache/ /figwheel_server.log /.nrepl-port /.cljs_nashorn_repl/ data.xml-data.xml-0.2.0-alpha6/CHANGES.md000066400000000000000000000044261337626463000175120ustar00rootroot00000000000000From 0.2.0-alpha3 to 0.2.0-alpha5 - Fix error check for builtin prefixes DXML-49 - Remove reflection cases DXML-46 From 0.2.0-alpha2 to 0.2.0-alpha3 - Minimum requirement is now clojure 1.7.0 - Print newline after preamble when pretty-printing (DXML-35) - Serialize built-in data types in XML Schema (DXML-27) - Reimplement namespace context tracking, due to bug in JDK - Various fixes in documentation and error messages (DXML-39) - Emit empty tags for elements with no content (DXML-25) - Add clojure.data.xml/element? predicate - Support empty protocol function on Element deftypes (DXML-44) - Reflection cleanup (DXML-42) From 0.2.0-alpha1 to 0.2.0-alpha2 - qname function now returns canonical (keyword) names - Remove QName defrecord from Clojurescript - Rename canonical-name to as-qname - Remove to-qname - xml nodes now implement map equality From 0.1.0-beta3 to 0.2.0-alpha1 - Define uniform mapping of xml namespaces to clojure namespaces via percent-encoding - Remove declare-ns and alias-ns - Introduce alias-uri - Clojurescript support - data.xml now requires Clojure 1.5.0+ (due to percent-sign in keywords) - Preserve whitespace by default From 0.1.0-beta2 to 0.1.0-beta3 - Fix emitter to keep non-namespaced xml names out of any set default namespace - Add support for location info in parser From 0.1.0-beta1 to 0.1.0-beta2 - Add support for emitting DOCTYPEs (DXML-10) - Fix issue emitting sibling namespaces (DXML-33) - Fix issue printing defaulted namespaces (DXML-30) From 0.0.8 to 0.1.0-beta1 - Add support for XML namespaces (DXML-4) - Fix pull-seq so it produces character events that work with emit-events (DXML-28) - Removed docs and references to JDK 1.5, data.xml now requires 1.6+ - data.xml now requires Clojure 1.4.0+ From 0.0.7 to 0.0.8 - Remove relection warnings in emit-cdata (DXML-16) - Added an EPL license file (DXML-19) - Fixed bug in the handling of CData end tags (DXML-17) - Added support for emitting booleans and numbers (DXML-14) From 0.0.6 to 0.0.7 - Fixed bug with args to the indentation function (DXML-7) - Strings now supported as tag names, previously was only kewords (DXML-8) - Add CDATA and comments support to sexp-as-element (DXML-11) - data.xml now properly handles CDATA records that contain an embedded ]]> by breaking it into two CDATA sections (DXML-12) data.xml-data.xml-0.2.0-alpha6/CONTRIBUTING.md000066400000000000000000000012201337626463000203360ustar00rootroot00000000000000This is a [Clojure contrib] project. Under the Clojure contrib [guidelines], this project cannot accept pull requests. All patches must be submitted via [JIRA]. See [Contributing] and the [FAQ] on the Clojure development [wiki] for more information on how to contribute. [Clojure contrib]: http://dev.clojure.org/display/doc/Clojure+Contrib [Contributing]: http://dev.clojure.org/display/community/Contributing [FAQ]: http://dev.clojure.org/display/community/Contributing+FAQ [JIRA]: http://dev.clojure.org/jira/browse/DXML [guidelines]: http://dev.clojure.org/display/community/Guidelines+for+Clojure+Contrib+committers [wiki]: http://dev.clojure.org/ data.xml-data.xml-0.2.0-alpha6/README.md000066400000000000000000000316251337626463000174000ustar00rootroot00000000000000# data.xml [data.xml](https://github.com/clojure/data.xml) is a Clojure library for reading and writing XML data. This library is the successor to [lazy-xml](http://clojure.github.com/clojure-contrib/lazy-xml-api.html). data.xml has the following features: * Parses XML documents into Clojure data structures * Emits XML from Clojure data structures * No additional dependencies if using JDK >= 1.6 * Uses StAX internally * lazy - should allow parsing and emitting of large XML documents ## API Reference Generated API docs for data.xml are available [here](http://clojure.github.com/data.xml). ## Bugs Please report bugs using JIRA [here](http://dev.clojure.org/jira/browse/DXML). ## Installation Latest stable release: `0.0.8` Latest preview release: `0.2.0-alpha5` (The main features of the `0.2.0` series are XML Namespace support and Clojurescript support) * [All Released Versions](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.clojure%22%20AND%20a%3A%22data.xml%22) * [Development Snapshot Versions](https://oss.sonatype.org/index.html#nexus-search;gav~org.clojure~data.xml~~~) ### Maven For Maven projects, add the following XML in your `pom.xml`'s `` section: For stable: org.clojure data.xml 0.0.8 --- For preview: org.clojure data.xml 0.2.0-alpha5 ### Leiningen Add the following to the `project.clj` dependencies: For stable: [org.clojure/data.xml "0.0.8"] --- For preview: [org.clojure/data.xml "0.2.0-alpha5"] ## Examples The examples below assume you have added a `:refer :all` for data.xml: (require '[clojure.data.xml :refer :all]) data.xml supports parsing and emitting XML. The parsing functions will read XML from a [Reader](http://docs.oracle.com/javase/6/docs/api/java/io/Reader.html) or [InputStream](http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html). (let [input-xml (java.io.StringReader. " The baz value")] (parse input-xml)) #clojure.data.xml.Element{:tag :foo, :attrs {}, :content (#clojure.data.xml.Element{:tag :bar, :attrs {}, :content (#clojure.data.xml.Element{:tag :baz, :attrs {}, :content ("The baz value")})})} The data is returned as defrecords and can be manipulated using the normal clojure data structure functions. Additional parsing options can be passed via key pairs: (parse-str "" :coalescing false) #clojure.data.xml.Element{:tag :a, :attrs {}, :content ("\nfoo bar\n" "\nbaz\n")} XML elements can be created using the typical defrecord constructor functions or the element function used below or just a plain map with :tag :attrs :content keys, and written using a [java.io.Writer](http://docs.oracle.com/javase/6/docs/api/java/io/Writer.html).: (let [tags (element :foo {:foo-attr "foo value"} (element :bar {:bar-attr "bar value"} (element :baz {} "The baz value")))] (with-open [out-file (java.io.FileWriter. "/tmp/foo.xml")] (emit tags out-file))) ;;-> Writes XML to /tmp/foo.xml The same can also be expressed using a more Hiccup-like style of defining the elements using sexp-as-element: (= (element :foo {:foo-attr "foo value"} (element :bar {:bar-attr "bar value"} (element :baz {} "The baz value"))) (sexp-as-element [:foo {:foo-attr "foo value"} [:bar {:bar-attr "bar value"} [:baz {} "The baz value"]]])) ;;-> true Comments and CDATA can also be emitted as an S-expression with the special tag names :-cdata and :-comment: (= (element :tag {:attr "value"} (element :body {} (cdata "not parsed true XML can be "round tripped" through the library: (let [tags (element :foo {:foo-attr "foo value"} (element :bar {:bar-attr "bar value"} (element :baz {} "The baz value")))] (with-open [out-file (java.io.FileWriter. "/tmp/foo.xml")] (emit tags out-file)) (with-open [input (java.io.FileInputStream. "/tmp/foo.xml")] (parse input))) #clojure.data.xml.Element{:tag :foo, :attrs {:foo-attr "foo value"}...} There are also some string based functions that are useful for debugging. (let [tags (element :foo {:foo-attr "foo value"} (element :bar {:bar-attr "bar value"} (element :baz {} "The baz value")))] (= tags (parse-str (emit-str tags)))) true Indentation is supported, but should be treated as a debugging feature as it's likely to be pretty slow: (print (indent-str (element :foo {:foo-attr "foo value"} (element :bar {:bar-attr "bar value"} (element :baz {} "The baz value1") (element :baz {} "The baz value2") (element :baz {} "The baz value3"))))) The baz value1 The baz value2 The baz value3 CDATA can be emitted: (emit-str (element :foo {} (cdata ""))) "]]>" But will be read as regular character data: (parse-str (emit-str (element :foo {} (cdata "")))) #clojure.data.xml.Element{:tag :foo, :attrs {}, :content ("")} Comments can also be emitted: (emit-str (element :foo {} (xml-comment "Just a goes here") (element :bar {} "and another element"))) "and another element" But are ignored when read: (emit-str (parse-str (emit-str (element :foo {} (xml-comment "Just a goes here") (element :bar {} "and another element"))))) "and another element" ## Namespace Support XML Namespaced names (QNames) are encoded into clojure keywords, by percent-encoding the (XML) namespace: `{http://www.w3.org/1999/xhtml}head` is encoded in data.xml as `:http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml/head`. Below is an example of parsing an XHTML document: (parse-str " ") #...Element{:tag :xmlns.http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml/html, :attrs {}, :content ()} Emitting namespaced XML is usually done by using `alias-uri` in combination with clojure's built-in `::kw-ns/shorthands`: (alias-uri 'xh "http://www.w3.org/1999/xhtml") (emit-str {:tag ::xh/html :content [{:tag ::xh/head} {:tag ::xh/body :content ["DOCUMENT"]}]}) DOCUMENT It is also allowable to use `javax.xml.namespace.QName` instances, as well as strings with the informal `{ns}n` encoding. (emit-str {:tag (qname "http://www.w3.org/1999/xhtml" "html")}) (emit-str {:tag "{http://www.w3.org/1999/xhtml}html"}) ### Namespace Prefixes Prefixes are mostly an artifact of xml serialisation. They can be customized by explicitly declaring them as attributes in the `xmlns` kw-namespace: (emit-str (element (qname "http://www.w3.org/1999/xhtml" "title") {:xmlns/foo "http://www.w3.org/1999/xhtml"} "Example title")) "Example title" Not specifying a namespace prefix will results in a prefix being generated: (emit-str (element ::xh/title {} "Example title")) "Example title" The above example auto assigns prefixes for the namespaces used. In this case it was named `a` by the emitter. Emitting several nested tags with the same namespace will use one prefix: (emit-str (element ::xh/html {} (element ::xh/head {} (element ::xh/title {} "Example title")))) "Example title" Note that the jdk QName ignores namespace prefixes for equality, but allows to preserve them for emitting. (= (parse-str "Example title") (parse-str "Example title")) In data.xml prefix mappings are (by default) retained in metadata on a tag record. If there is no metadata, new prefixes will be generated when emitting. (emit-str (parse-str "")) ## Location information as meta By default the parser attaches location information as element meta, `:character-offset`, `:column-number` and `:line-number` are available under the `:clojure.data.xml/location-info` key: (deftest test-location-meta (let [input "\n" location-meta (comp :clojure.data.xml/location-info meta)] (is (= 1 (-> input parse-str location-meta :line-number))) To elide location information, pass `:location-info false` to the parser: (parse-str your-input :location-info false) ## Clojurescript support The Clojurescript implementation uses the same namespace as the Clojure one `clojure.data.xml`. ### Native DOM support data.xml can directly work with native dom nodes. - To parse into DOM objects, call parse with `:raw true` - To use DOM objects like regular persistent maps, call `(extend-dom-as-data!)`. This extends the native dom node prototypes to Clojurescript collection protocols, such that you can treat them as data.xml parse trees. - To coerce to native dom use `element-node` - To coerce to records use `element-data` ### Missing Features, Patches Welcome #### Streaming data.xml on Clojurescript doesn't currently support streaming, hence only the `*-str` variants of `parse`/`emit` are implemented. Those are just wrappers for browser's native xml parsing/printing. Pull parsing doesn't seem the right solution for Clojurescript, because when code cannot block, the parser has no way of waiting on its input. For this reason, parsing in Clojurescript cannot be based around `event-seq`. Push parsing, on the other hand should not pose a problem, because when data arrives in a callback, it can be pushed on into the parser. Fortunately, clojure already has a nice push-based pendant for lazy sequences: transducers. #### Utilities Some utilities, like `process/*-xmlns`, `prxml/sexp-as-*`, `indent` aren't yet implemented. #### Immutable updates for dom types Make `extend-dom-as-data!` also support assoc, ... on dom nodes. #### Feel free to pick a [ticket](http://dev.clojure.org/jira/secure/IssueNavigator.jspa?reset=true&jqlQuery=project+%3D+DXML+AND+status+in+%28Open%2C+%22In+Progress%22%2C+Reopened%29) to work on ## License Licensed under the [Eclipse Public License](http://www.opensource.org/licenses/eclipse-1.0.php). ## Developer Information * [GitHub project](https://github.com/clojure/data.xml) * [Bug Tracker](http://dev.clojure.org/jira/browse/DXML) * [Continuous Integration](http://build.clojure.org/job/data.xml/) * [Compatibility Test Matrix](http://build.clojure.org/job/data.xml-test-matrix/) ## Contributing All contributions need to be made via patches attached to tickets in [JIRA](http://dev.clojure.org/jira/browse/DXML). Check the [Contributing to Clojure](http://clojure.org/contributing) page for more information. data.xml-data.xml-0.2.0-alpha6/dxml-nashorn.global.js000066400000000000000000000003141337626463000223170ustar00rootroot00000000000000global.console = { log: print, warn: print, error: print }; global.xmldom = require("xmldom"); global.DOMParser = global.xmldom.DOMParser; global.XMLSerializer = global.xmldom.XMLSerializer; data.xml-data.xml-0.2.0-alpha6/epl-v10.html000066400000000000000000000311651337626463000201720ustar00rootroot00000000000000 Eclipse Public License - Version 1.0

Eclipse Public License - v 1.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

"Contribution" means:

a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and

b) in the case of each subsequent Contributor:

i) changes to the Program, and

ii) additions to the Program;

where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.

"Contributor" means any person or entity that distributes the Program.

"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

"Program" means the Contributions distributed in accordance with this Agreement.

"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.

2. GRANT OF RIGHTS

a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.

b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.

c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.

d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.

3. REQUIREMENTS

A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:

a) it complies with the terms and conditions of this Agreement; and

b) its license agreement:

i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;

ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;

iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and

iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.

When the Program is made available in source code form:

a) it must be made available under this Agreement; and

b) a copy of this Agreement must be included with each copy of the Program.

Contributors may not remove or alter any copyright notices contained within the Program.

Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.

This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.

data.xml-data.xml-0.2.0-alpha6/package.json000066400000000000000000000003201337626463000203730ustar00rootroot00000000000000{ "scripts": { "build": "webpack" } , "devDependencies": { "webpack": "2.1.0-beta.27", "xmldom" : "0.1.27" "domino" : "" } , "name": "dxml-nashorn-api" } data.xml-data.xml-0.2.0-alpha6/pom.xml000066400000000000000000000053221337626463000174310ustar00rootroot00000000000000 4.0.0 data.xml 0.2.0-alpha6 data.xml jar Functions to parse XML into lazy sequences and lazy trees and emit these as text Chouser chouser@n01se.net http://chouser.n01se.net -5 Alan Malloy amalloy@4clojure.com -8 Ryan Senior senior.ryan@gmail.com -6 Herwig Hochleitner herwig@bendlas.net +1 org.clojure pom.contrib 0.2.2 org.clojure data.codec 0.1.0 compile org.clojure test.check 0.9.0 test org.clojure clojurescript 1.10.439 test ${project.basedir}/src/test/resources ${project.basedir}/src/test/clojurescript 1.7.0 clojars.org https://clojars.org/repo scm:git:git@github.com:clojure/data.xml.git scm:git:git@github.com:clojure/data.xml.git git@github.com:clojure/data.xml.git data.xml-0.2.0-alpha6 data.xml-data.xml-0.2.0-alpha6/project.clj000066400000000000000000000012621337626463000202530ustar00rootroot00000000000000(defproject org.clojure/data.xml "0-UE-DEVELOPMENT" :source-paths ["src/main/clojure"] :test-paths ["src/test/clojure" "src/test/clojurescript"] :resource-paths ["src/test/resources" "target/gen-resources"] :dependencies [[org.clojure/clojure "1.10.0-RC1"] [org.clojure/data.codec "0.1.0"] [org.clojure/clojurescript "1.10.439"] [com.cemerick/piggieback "0.2.2"] [org.clojure/tools.nrepl "0.2.13"] [org.clojure/test.check "0.9.0"] [figwheel-sidecar "0.5.10"] [binaryage/devtools "0.9.4"]] :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}) data.xml-data.xml-0.2.0-alpha6/src/000077500000000000000000000000001337626463000167015ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/000077500000000000000000000000001337626463000176255ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojure/000077500000000000000000000000001337626463000212705ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/000077500000000000000000000000001337626463000227335ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/000077500000000000000000000000001337626463000236445ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml.clj000066400000000000000000000151761337626463000251500ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns ^{:doc "Functions to parse XML into lazy sequences and lazy trees and emit these as text." :author "Chris Houser"} clojure.data.xml (:require (clojure.data.xml [process :as process] [impl :refer [export-api]] [node :as node] [prxml :as prxml] [name :as name] [event :as event]) (clojure.data.xml.jvm [pprint :refer [indent-xml]] [parse :refer [pull-seq string-source make-stream-reader]] [emit :refer [write-document string-writer]]) [clojure.data.xml.tree :refer [event-tree flatten-elements]])) (export-api node/element* node/element node/cdata node/xml-comment node/element? prxml/sexp-as-element prxml/sexps-as-fragment event/element-nss name/alias-uri name/parse-qname name/qname-uri name/qname-local name/qname name/as-qname name/uri-symbol name/symbol-uri name/uri-file name/print-uri-file-command! process/find-xmlns process/aggregate-xmlns) (def ^:private ^:const parser-opts-arg '{:keys [include-node? location-info coalescing supporting-external-entities allocator namespace-aware replacing-entity-references validating reporter resolver support-dtd] :or {include-node? #{:element :characters} location-info true coalescing true supporting-external-entities false}}) (defn event-seq "Parses an XML input source into a lazy sequence of pull events. Input source can be a java.io.InputStream or java.io.Reader Options: :include-node? can be a subset of #{:element :characters :comment} default #{:element :characters} :location-info pass false to skip generating location meta data See http://docs.oracle.com/javase/6/docs/api/javax/xml/stream/XMLInputFactory.html for documentation on options: {:allocator XMLInputFactory/ALLOCATOR :coalescing XMLInputFactory/IS_COALESCING :namespace-aware XMLInputFactory/IS_NAMESPACE_AWARE :replacing-entity-references XMLInputFactory/IS_REPLACING_ENTITY_REFERENCES :supporting-external-entities XMLInputFactory/IS_SUPPORTING_EXTERNAL_ENTITIES :validating XMLInputFactory/IS_VALIDATING :reporter XMLInputFactory/REPORTER :resolver XMLInputFactory/RESOLVER :support-dtd XMLInputFactory/SUPPORT_DTD}" {:arglists (list ['source parser-opts-arg])} [source opts] (let [props* (merge {:include-node? #{:element :characters} :coalescing true :supporting-external-entities false :location-info true} opts)] (pull-seq (make-stream-reader props* source) props* nil))) (defn parse "Parses an XML input source into a a tree of Element records. The element tree is realized lazily, so huge XML files can be streamed through a depth-first tree walk. Input source can be a java.io.InputStream or java.io.Reader Options: :include-node? can be a subset of #{:element :characters :comment} default #{:element :characters} :location-info pass false to skip generating location meta data See http://docs.oracle.com/javase/6/docs/api/javax/xml/stream/XMLInputFactory.html for documentation on options: {:allocator XMLInputFactory/ALLOCATOR :coalescing XMLInputFactory/IS_COALESCING :namespace-aware XMLInputFactory/IS_NAMESPACE_AWARE :replacing-entity-references XMLInputFactory/IS_REPLACING_ENTITY_REFERENCES :supporting-external-entities XMLInputFactory/IS_SUPPORTING_EXTERNAL_ENTITIES :validating XMLInputFactory/IS_VALIDATING :reporter XMLInputFactory/REPORTER :resolver XMLInputFactory/RESOLVER :support-dtd XMLInputFactory/SUPPORT_DTD}" {:arglists (list ['source '& parser-opts-arg])} [source & {:as opts}] (event-tree (event-seq source opts))) (defn parse-str "Parses an XML String into a a tree of Element records. Options: :include-node? can be a subset of #{:element :characters :comment} default #{:element :characters} :location-info pass false to skip generating location meta data See http://docs.oracle.com/javase/6/docs/api/javax/xml/stream/XMLInputFactory.html for documentation on options: {:allocator XMLInputFactory/ALLOCATOR :coalescing XMLInputFactory/IS_COALESCING :namespace-aware XMLInputFactory/IS_NAMESPACE_AWARE :replacing-entity-references XMLInputFactory/IS_REPLACING_ENTITY_REFERENCES :supporting-external-entities XMLInputFactory/IS_SUPPORTING_EXTERNAL_ENTITIES :validating XMLInputFactory/IS_VALIDATING :reporter XMLInputFactory/REPORTER :resolver XMLInputFactory/RESOLVER :support-dtd XMLInputFactory/SUPPORT_DTD}" {:arglists (list ['string '& parser-opts-arg])} [s & opts] (apply parse (string-source s) opts)) (defn emit "Prints the given Element tree as XML text to stream. Options: :encoding Character encoding to use :doctype Document type (DOCTYPE) declaration to use" [e writer & {:as opts}] (write-document writer (flatten-elements [e]) opts)) (defn emit-str "Emits the Element to String and returns it. Options: :encoding Character encoding to use :doctype Document type (DOCTYPE) declaration to use" ([e & opts] (let [sw (string-writer)] (apply emit e sw opts) (str sw)))) (defn indent "Emits the XML and indents the result. WARNING: this is slow it will emit the XML and read it in again to indent it. Intended for debugging/testing only." [e writer & opts] (indent-xml (apply emit-str e opts) writer)) (defn indent-str "Emits the XML and indents the result. Writes the results to a String and returns it" [e & opts] (let [sw (string-writer)] (apply indent e sw opts) (str sw))) ;; TODO implement ~normalize to simulate an emit-parse roundtrip ;; in terms of xmlns environment and keywords vs qnames data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml.cljs000066400000000000000000000032011337626463000253150ustar00rootroot00000000000000(ns clojure.data.xml (:require-macros [clojure.data.xml.impl :refer [export-api]]) (:require [clojure.data.xml.name :as name] [clojure.data.xml.node :as node] [clojure.data.xml.js.dom :as dom] [clojure.data.xml.protocols :refer [AsQName]])) (export-api name/parse-qname name/qname-uri name/qname-local name/qname name/as-qname name/uri-symbol name/symbol-uri node/element* node/element node/cdata node/xml-comment node/element? dom/extend-dom-as-data! dom/element-node dom/element-data) ;;;; ## TODO event-seq ;; This probably won't happen due to js' non-blocking semantics ;; Instead, for clojurescript, the machinery around event-seq could be implemented ;; as a transducer stack, such that a push-based source for parser events, like sax-js, ;; could be used. ;; TODO parse (use goog StringBuffer?) (defn parse-str "Use DOMParser to parse xml string" ;; TODO detect browser specific parsererror tags ;; see http://stackoverflow.com/questions/11563554/how-do-i-detect-xml-parsing-errors-when-using-javascripts-domparser-in-a-cross [s & {:keys [content-type on-error raw] :or {content-type "text/xml" on-error #(throw (ex-info "XML parser error" {:doc % :input s}))}}] (let [dom (. (js/DOMParser.) (parseFromString s content-type)) doc (.-documentElement dom)] (cond (= "parsererror" (.-nodeName doc)) (on-error doc) raw doc :else (element-data doc)))) ;; TODO emit (use goog StringBuffer?) (defn emit-str "Use XMLSerializer to render an xml string" [e & {:keys []}] (. (js/XMLSerializer.) (serializeToString (element-node e)))) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/000077500000000000000000000000001337626463000244445ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/event.clj000066400000000000000000000105721337626463000262640ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.event "Data type for xml pull events" {:author "Herwig Hochleitner"} (:require [clojure.data.xml.protocols :refer [EventGeneration gen-event next-events xml-str]] [clojure.data.xml.name :refer [separate-xmlns]] [clojure.data.xml.node :refer [element* cdata xml-comment]] [clojure.data.xml.impl :refer [extend-protocol-fns compile-if]] [clojure.data.xml.pu-map :as pu]) (:import (clojure.data.xml.node Element CData Comment) (clojure.lang Sequential IPersistentMap Keyword) (java.net URI URL) (java.util Date) (javax.xml.namespace QName))) (definline element-nss* [element] `(get (meta ~element) :clojure.data.xml/nss pu/EMPTY)) (defn element-nss "Get xmlns environment from element" [{:keys [attrs] :as element}] (separate-xmlns attrs #(pu/merge-prefix-map (element-nss* element) %2))) ; Represents a parse event. (defrecord StartElementEvent [tag attrs nss location-info]) (defrecord EmptyElementEvent [tag attrs nss location-info]) (defrecord CharsEvent [str]) (defrecord CDataEvent [str]) (defrecord CommentEvent [str]) (defrecord QNameEvent [qn]) ;; EndElementEvent doesn't have any data, so make it a singleton (deftype EndElementEvent []) (def end-element-event (EndElementEvent.)) (defn ->EndElementEvent [] end-element-event) ;; Event Generation for stuff to show up in generated xml (let [second-arg #(do %2) elem-event-generation {:gen-event (fn elem-gen-event [{:keys [tag attrs content] :as element}] (separate-xmlns attrs #((if (seq content) ->StartElementEvent ->EmptyElementEvent) tag %1 (pu/merge-prefix-map (element-nss* element) %2) nil))) :next-events (fn elem-next-events [{:keys [tag content]} next-items] (if (seq content) (list* content end-element-event next-items) next-items))} string-event-generation {:gen-event (comp ->CharsEvent #'xml-str) :next-events second-arg} qname-event-generation {:gen-event ->QNameEvent :next-events second-arg}] (extend-protocol-fns EventGeneration (StartElementEvent EmptyElementEvent EndElementEvent CharsEvent CDataEvent CommentEvent) {:gen-event identity :next-events second-arg} (String Boolean Number (Class/forName "[B") Date URI URL nil) string-event-generation (Keyword QName) qname-event-generation CData {:gen-event (comp ->CDataEvent :content) :next-events second-arg} Comment {:gen-event (comp ->CommentEvent :content) :next-events second-arg} (IPersistentMap Element) elem-event-generation) (compile-if (Class/forName "java.time.Instant") (extend java.time.Instant EventGeneration string-event-generation) nil)) (extend-protocol EventGeneration Sequential (gen-event [coll] (gen-event (first coll))) (next-events [coll next-items] (if-let [r (seq (rest coll))] (cons (next-events (first coll) r) next-items) (next-events (first coll) next-items)))) ;; Node Generation for events (defn event-element [event contents] (when (or (instance? StartElementEvent event) (instance? EmptyElementEvent event)) (element* (:tag event) (:attrs event) contents (if-let [loc (:location-info event)] {:clojure.data.xml/location-info loc :clojure.data.xml/nss (:nss event)} {:clojure.data.xml/nss (:nss event)})))) (defn event-node [event] (cond (instance? CharsEvent event) (:str event) (instance? CDataEvent event) (cdata (:str event)) (instance? CommentEvent event) (xml-comment (:str event)) :else (throw (ex-info "Illegal argument, not an event object" {:event event})))) (defn event-exit? [event] (identical? end-element-event event)) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/impl.clj000066400000000000000000000045661337626463000261120ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.impl "Shared private code for data.xml namespaces" {:author "Herwig Hochleitner"} (:require [clojure.data.codec.base64 :as b64])) (defn- var-form? [form] (and (seq? form) (= 'var (first form)))) (defn- export-form [var-name] (let [is-var (var-form? var-name) vsym (symbol (name (if is-var (second var-name) var-name)))] `[(def ~vsym ~var-name) (alter-meta! (var ~vsym) (constantly (assoc (meta ~(if is-var var-name `(var ~var-name))) :wrapped-by (var ~vsym))))])) (defmacro export-api "This creates vars, that take their (local) name, value and metadata from another var" [& names] (cons 'do (mapcat export-form names))) (defmacro static-case "Variant of case where keys are evaluated at compile-time" [val & cases] `(case ~val ~@(mapcat (fn [[field thunk]] [(eval field) thunk]) (partition 2 cases)) ~@(when (odd? (count cases)) [(last cases)]))) (defmacro extend-protocol-fns "Helper to many types to a protocol with a method map, similar to extend" [proto & types+mmaps] (assert (zero? (mod (count types+mmaps) 2))) (let [gen-extend (fn [type mmap] (list `extend type proto mmap))] `(do ~@(for [[type mmap] (partition 2 types+mmaps)] (if (coll? type) (let [mm (gensym "mm-")] `(let [~mm ~mmap] ~@(map gen-extend type (repeat mm)))) (gen-extend type mmap)))))) (defmacro compile-if "Evaluate `exp` and if it returns logical true and doesn't error, expand to `then`. Else expand to `else`. see clojure.core.reducers" [exp then else] (if (try (eval exp) (catch Throwable _ false)) `(do ~then) `(do ~else))) (defn b64-encode [ba] (String. ^bytes (b64/encode ba))) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/js/000077500000000000000000000000001337626463000250605ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/js/dom.cljs000066400000000000000000000217731337626463000265260ustar00rootroot00000000000000(ns clojure.data.xml.js.dom (:require [clojure.data.xml.name :refer [qname-uri qname-local qname xmlns-uri]] [clojure.data.xml.node :as node])) (def doc (.. (js/DOMParser.) (parseFromString "" "text/xml"))) (defn text-node "Create a Text node" [s] (.createTextNode doc s)) (defn element* "Create an xml element from a content collection and optional metadata" ([tag attrs content meta] (let [el (element* tag attrs content)] (specify! el IMeta (-meta [_] meta) IWithMeta (-with-meta [_ meta] (specify el IMeta (-meta [_] meta) IWithMeta (-with-meta [_ meta] (-with-meta el meta))))) el)) ([tag attrs content] (let [el (.createElementNS doc (qname-uri tag) (qname-local tag))] (reduce-kv (fn [_ k v] (let [uri (qname-uri k)] (if (= uri "http://www.w3.org/2000/xmlns/") (.setAttribute el (str "xmlns:" (qname-local k)) v) (.setAttributeNS el uri (qname-local k) v)))) nil attrs) (reduce (fn [_ n] (.appendChild el (if (string? n) (text-node n) n))) nil content) el))) (defn element "Create an xml Element from content varargs" ([tag] (element* tag nil nil)) ([tag attrs] (element* tag attrs nil)) ([tag attrs & content] (element* tag attrs content))) (defn cdata "Create a CData node" [content] (.createCDATASection doc content)) (defn xml-comment "Create a Comment node" [content] (.createComment doc content)) (declare element-node) (defn node-list "Create a NodeList" [elements] (let [f (.createDocumentFragment doc)] (doseq [el elements] (.appendChild f (element-node el))) (.-childNodes f))) ;; ## Types ;; we get these from reflection, to only depend only on js/DOMParser and js/XMLSerializer ;; these can easily be provided in nashorn, ... (def Text (type (text-node ""))) (def Element (type (element :e))) (def NamedNodeMap (type (.-attributes (element :e)))) (def NodeList (type (node-list []))) (def Attr (type (aget (.-attributes (element :e {:a "1"})) 0))) (def CData (type (cdata ""))) (def Comment (type (xml-comment ""))) ;; ## Coercions ;; ## -> DOM (defn element-node "Coerce xml elements to dom nodes" [el] (cond (string? el) (text-node el) (instance? node/CData el) (cdata (:content el)) (instance? node/Comment el) (xml-comment (:content el)) (instance? Element el) el (instance? CData el) el (instance? Comment el) el ;; stupid xmldom, (some? (.-item el)) #_(instance? NodeList el) (some? (.-item el)) el (instance? Text el) el (satisfies? ILookup el) (element* (:tag el) (:attrs el) (map element-node (:content el))) (satisfies? ISequential el) (node-list el) :else (throw (ex-info "Cannot coerce" {:form el})))) ;; ## -> DATA (defn- dom-element-tag [el] (qname (.-namespaceURI el) (.-localName el))) (defn- xmlns-attr? [a] (identical? xmlns-uri (.-namespaceURI a))) (def remove-xmlns-attrs-xf (remove xmlns-attr?)) (def remove-xmlns-attrs (partial into {} remove-xmlns-attrs-xf)) (def filter-xmlns-attrs-xf (filter xmlns-attr?)) (def filter-xmlns-attrs (partial into {} filter-xmlns-attrs-xf)) (defn dom-element-attrs ([el] (dom-element-attrs remove-xmlns-attrs-xf el)) ([xf el] (transduce xf (completing (fn [ta attr-node] (assoc! ta (dom-element-tag attr-node) (.-value attr-node))) persistent!) (transient {}) (array-seq el)))) (declare element-data) (defn- node-list-vec [nl] (into [] (map element-data) (array-seq nl))) (defn- as-node [n] (if (instance? Text n) (.-nodeValue n) ;; .-data n)) (defn element-data "Coerce xml elements to element maps / content vectors" [el] (cond (instance? Comment el) (node/xml-comment (.-data el)) (instance? CData el) (node/cdata (.-data el)) (instance? Text el) (.-nodeValue el) (instance? Element el) (node/element* (dom-element-tag el) (dom-element-attrs (.-attributes el)) (node-list-vec (.-childNodes el)) {:clojure.data.xml/nss (dom-element-attrs filter-xmlns-attrs-xf (.-attributes el))}) ;;(instance? NamedNodeMap el) (.-getNamedItemNS el) (dom-element-attrs el) (instance? NodeList el) (node-list-vec el) (string? el) el (satisfies? ILookup el) el (satisfies? ISequential el) el :else (throw (ex-info "Element cannot be converted to data" {:element el})))) (defn extend-dom-as-data! [] (extend-type Element IMap IMeta (-meta [el] {:clojure.data.xml/nss (filter-xmlns-attrs (.-attributes el))}) ILookup (-lookup ([el k] (case k :tag (dom-element-tag el) :attrs (.-attributes el) :content (.-childNodes el) (throw (ex-info "XML tag has no key" {:key k :el el})))) ([el k nf] #_(println "Element" k "=>" (case k :tag (dom-element-tag el) :attrs (.-attributes el) :content (.-childNodes el) nf)) (case k :tag (dom-element-tag el) :attrs (remove-xmlns-attrs (.-attributes el)) :content (.-childNodes el) nf))) ICounted (-count [nm] 3) IEquiv (-equiv [el0 el1] (if false #_(instance? Element el1) (do ;; we can't use .isEqualNode, since that has bugs with namespaces (.log js/console el0 el1) (println 'isEqualNode (.isEqualNode el0 el1)) (.isEqualNode el0 el1)) (and (= (:tag el0) (:tag el1)) (= (:attrs el0) (:attrs el1)) (= (:content el0) (:content el1)))))) (extend-type NamedNodeMap IMap ISeqable (-seq [nm] (array-seq nm)) ILookup (-lookup ([attrs attr] (if-let [i (.getNamedItemNS attrs (qname-uri attr) (qname-local attr))] (.-value i) nil)) ([attrs attr not-found] #_(println "Attrs" attr "=>" (if-let [i (.getNamedItemNS attrs (qname-uri attr) (qname-local attr))] (.-value i) not-found)) (if-let [i (.getNamedItemNS attrs (qname-uri attr) (qname-local attr))] (.-value i) not-found))) ICounted (-count [nm] (reduce (fn [acc attr] (if (xmlns-attr? attr) acc (inc acc))) 0 nm)) IKVReduce (-kv-reduce [nm f init] (reduce (fn [acc attr] (if (xmlns-attr? attr) acc (f acc (dom-element-tag attr) (.-value attr)))) init nm)) IEquiv (-equiv [nm0 nm1] #_(println "NamedNodeMap.-equiv" (identical? nm0 nm1) (count nm0) (count nm1)) (or (identical? nm0 nm1) (and (identical? (count nm0) (count nm1)) (reduce-kv (fn [_ qn v] #_(println "=" v 'qn qn '(get nm1 qn "") (get nm1 qn "")) (or (identical? v (get nm1 qn "")) (reduced false))) true nm0))))) (extend-type NodeList ;specify! (.. (node-list []) -constructor -prototype) ISeqable (-seq [nl] (seq (map as-node (array-seq nl)))) ISequential ICounted (-count [nl] (alength nl)) IIndexed (-nth ([nl n] (as-node (aget nl n))) ([nl n nf] (if (and (<= 0 n) (< n (alength nl))) (as-node (aget nl n)) nf))) IEquiv (-equiv [nl0 nl1] #_(println "NodeList.-equiv") (or (identical? nl0 nl1) (and (identical? (count nl0) (count nl1)) (reduce (fn [_ n] (or (= (nth nl0 n) (nth nl1 n)) (reduced false))) true (range (count nl0))))))) (extend-type Text IEquiv (-equiv [t0 t1] (identical? (.-nodeValue t0) (if (instance? Text t1) (.-nodeValue t1) t1)))) (extend-type Attr ISeqable (-seq [attr] (array-seq #js[(key attr) (key attr)])) IMapEntry (-key [attr] (dom-element-tag attr)) (-val [attr] (.-value attr)) ISequential ICounted (-count [_] 2) IIndexed (-nth ([attr n] (case n 0 (key attr) 1 (val attr))) ([attr n nf] (case n 0 (dom-element-tag attr) 1 (.-value attr) nf)))) {'Text Text 'Element Element 'NamedNodeMap NamedNodeMap 'NodeList NodeList}) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/js/name.cljs000066400000000000000000000007751337626463000266660ustar00rootroot00000000000000(ns clojure.data.xml.js.name (:require [clojure.data.xml.protocols :refer [AsQName qname-uri qname-local]] [clojure.string :as str])) (def parse-qname (memoize (partial re-matches #"(?:\{([^}]+)\})?([^{]*)"))) (defn decode-uri [ns] (js/decodeURIComponent ns)) (defn encode-uri [uri] (js/encodeURIComponent uri)) (extend-protocol AsQName string (qname-local [s] (let [[_ _ local] (parse-qname s)] local)) (qname-uri [s] (let [[_ uri _] (parse-qname s)] uri))) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/jvm/000077500000000000000000000000001337626463000252405ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/jvm/emit.clj000066400000000000000000000212451337626463000266740ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.jvm.emit "JVM implementation of the emitter details" {:author "Herwig Hochleitner"} (:require (clojure.data.xml [name :refer [qname-uri qname-local separate-xmlns gen-prefix *gen-prefix-counter*]] [pu-map :as pu] [protocols :refer [AsXmlString xml-str]] [impl :refer [extend-protocol-fns b64-encode compile-if]] event) [clojure.string :as str]) (:import (java.io OutputStreamWriter Writer StringWriter) (java.nio.charset Charset) (java.util.logging Logger Level) (javax.xml.namespace NamespaceContext QName) (javax.xml.stream XMLStreamWriter XMLOutputFactory) (javax.xml.transform OutputKeys Transformer TransformerFactory) (clojure.data.xml.event StartElementEvent EmptyElementEvent EndElementEvent CharsEvent CDataEvent CommentEvent QNameEvent) (clojure.lang BigInt) (java.net URI URL) (java.util Date) (java.text DateFormat SimpleDateFormat))) (def logger (Logger/getLogger "clojure.data.xml")) (defprotocol EventEmit (emit-event [event ^XMLStreamWriter writer prefix-uri-stack])) (defn check-stream-encoding [^OutputStreamWriter stream xml-encoding] (when (not= (Charset/forName xml-encoding) (Charset/forName (.getEncoding stream))) (throw (ex-info (str "Output encoding of writer (" (.getEncoding stream) ") doesn't match declaration (" xml-encoding ")") {:stream-encoding (.getEncoding stream) :declared-encoding xml-encoding})))) (defn- prefix-for [qn pu] (or (pu/get-prefix pu (qname-uri qn)) (throw (ex-info "Auto-generating prefixes is not supported for content-qnames. Please declare all URIs used in content qnames." {:qname qn :uri (qname-uri qn)})))) (defn- attr-str [value pu] (if (or (keyword? value) (instance? QName value)) (str (prefix-for value pu) ":" (qname-local value)) (xml-str value))) (defn- emit-attrs [^XMLStreamWriter writer pu attrs] (reduce-kv (fn [_ attr value] (let [uri (qname-uri attr) local (qname-local attr)] (if (str/blank? uri) (.writeAttribute writer local (attr-str value pu)) (.writeAttribute writer (pu/get-prefix pu uri) uri local (attr-str value pu)))) _) nil attrs)) (defn- emit-ns-attrs [^XMLStreamWriter writer parent-pu pu] (pu/reduce-diff (fn [_ pf uri] (if (str/blank? pf) (.writeDefaultNamespace writer uri) (.writeNamespace writer pf uri)) _) nil parent-pu pu)) (defn- compute-prefix [tpu uri suggested] (or (pu/get-prefix tpu uri) (loop [prefix (or suggested (gen-prefix))] (if (pu/get tpu prefix) (recur (gen-prefix)) prefix)))) (defn- compute-pu [pu elem-pu attr-uris tag-uri tag-local] (let [tpu (pu/transient pu) ;; add namespaces from current environment tpu (reduce-kv (fn [tpu ns-attr uri] (assert (string? ns-attr) (pr-str ns-attr uri)) (pu/assoc! tpu (compute-prefix tpu uri ns-attr) uri)) tpu (pu/prefix-map elem-pu)) ;; add implicit namespaces used by tag, attrs tpu (reduce (fn [tpu uri] (pu/assoc! tpu (compute-prefix tpu uri nil) uri)) tpu (if (str/blank? tag-uri) attr-uris (cons tag-uri attr-uris))) ;; rename default namespace, if tag is global (not in a namespace) tpu (if-let [uri (and (str/blank? tag-uri) (pu/get tpu ""))] (do (when (.isLoggable ^Logger logger Level/FINE) (.log ^Logger logger Level/FINE (format "Default `xmlns=\"%s\"` had to be replaced with a `xmlns=\"\"` because of global element `%s`" uri tag-local))) (-> tpu (pu/assoc! "" "") (as-> tpu (pu/assoc! tpu (compute-prefix tpu uri nil) uri)))) tpu)] (pu/persistent! tpu))) (defn- emit-start-tag [{:keys [attrs nss tag]} ^XMLStreamWriter writer prefix-uri-stack empty] (let [uri (qname-uri tag) local (qname-local tag) parent-pu (first prefix-uri-stack) pu (compute-pu parent-pu nss (map qname-uri (keys attrs)) uri local)] (if empty (do (if (str/blank? uri) (.writeEmptyElement writer local) (.writeEmptyElement writer (pu/get-prefix pu uri) local uri)) (emit-ns-attrs writer parent-pu pu) (emit-attrs writer pu attrs) prefix-uri-stack) (do (if (str/blank? uri) (.writeStartElement writer local) (.writeStartElement writer (pu/get-prefix pu uri) local uri)) (emit-ns-attrs writer parent-pu pu) (emit-attrs writer pu attrs) (cons pu prefix-uri-stack))))) (defn- emit-cdata [^String cdata-str ^XMLStreamWriter writer] (when-not (str/blank? cdata-str) (let [idx (.indexOf cdata-str "]]>")] (if (= idx -1) (.writeCData writer cdata-str ) (do (.writeCData writer (subs cdata-str 0 (+ idx 2))) (recur (subs cdata-str (+ idx 2)) writer)))))) (extend-protocol EventEmit StartElementEvent (emit-event [ev writer pu-stack] (emit-start-tag ev writer pu-stack false)) EmptyElementEvent (emit-event [ev writer pu-stack] (emit-start-tag ev writer pu-stack true)) EndElementEvent (emit-event [ev writer pu-stack] (assert (next pu-stack) "balanced tags") (.writeEndElement ^XMLStreamWriter writer) (next pu-stack)) CharsEvent (emit-event [{:keys [str]} writer s] (.writeCharacters ^XMLStreamWriter writer str) s) CDataEvent (emit-event [{:keys [str]} writer s] (emit-cdata str writer) s) CommentEvent (emit-event [{:keys [str]} writer s] (.writeComment ^XMLStreamWriter writer str) s) QNameEvent (emit-event [{:keys [qn]} ^XMLStreamWriter writer pu-stack] (.writeCharacters writer (prefix-for qn (first pu-stack))) (.writeCharacters writer ":") (.writeCharacters writer (qname-local qn)) pu-stack)) (def ^:private ^ThreadLocal thread-local-utc-date-format ;; SimpleDateFormat is not thread-safe, so we use a ThreadLocal proxy for access. ;; http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335 (proxy [ThreadLocal] [] (initialValue [] (doto (SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss.SSS-00:00") ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT) (.setTimeZone (java.util.TimeZone/getTimeZone "GMT")))))) (extend-protocol-fns AsXmlString String {:xml-str identity} (Boolean Byte Character Short Integer Long Float Double BigInteger BigDecimal BigInt URI URL nil) {:xml-str str}) (extend-protocol AsXmlString (Class/forName "[B") (xml-str [ba] (b64-encode ba)) Date (xml-str [d] (let [^DateFormat utc-format (.get thread-local-utc-date-format)] (.format utc-format d))) clojure.lang.Ratio (xml-str [r] (str (.decimalValue r)))) (compile-if (Class/forName "java.time.Instant") (extend-protocol AsXmlString java.time.Instant (xml-str [i] (xml-str (Date/from i)))) nil) ;; Writers (defn write-document "Writes the given event seq as XML text to writer. Options: :encoding Character encoding to use :doctype Document type (DOCTYPE) declaration to use" [^Writer swriter events opts] (binding [*gen-prefix-counter* 0] (let [^XMLStreamWriter writer (-> (XMLOutputFactory/newInstance) (.createXMLStreamWriter swriter))] (when (instance? OutputStreamWriter swriter) (check-stream-encoding swriter (or (:encoding opts) "UTF-8"))) (.writeStartDocument writer (or (:encoding opts) "UTF-8") "1.0") (when-let [doctype (:doctype opts)] (.writeDTD writer doctype)) (reduce #(emit-event %2 writer %1) [pu/EMPTY] events) (.writeEndDocument writer) swriter))) (defn string-writer [] (StringWriter.)) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/jvm/name.clj000066400000000000000000000023671337626463000266620ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.jvm.name (:require (clojure.data.xml [protocols :refer [AsQName qname-uri qname-local]]) [clojure.string :as str]) (:import java.io.Writer (javax.xml.namespace NamespaceContext QName) (java.net URLEncoder URLDecoder))) (extend-protocol AsQName QName (qname-local [qname] (.getLocalPart qname)) (qname-uri [qname] (.getNamespaceURI qname))) (def ^QName parse-qname (memoize (fn [s] ;; TODO weakly memoize this? (QName/valueOf s)))) (extend-protocol AsQName String (qname-local [s] (.getLocalPart (parse-qname s))) (qname-uri [s] (.getNamespaceURI (parse-qname s)))) (definline decode-uri [ns] `(URLDecoder/decode ~ns "UTF-8")) (definline encode-uri [uri] `(URLEncoder/encode ~uri "UTF-8")) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/jvm/parse.clj000066400000000000000000000130711337626463000270460ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.jvm.parse (:require [clojure.string :as str] [clojure.data.xml.event :refer [->StartElementEvent ->EmptyElementEvent ->EndElementEvent ->CharsEvent ->CDataEvent ->CommentEvent]] [clojure.data.xml.impl :refer [static-case]] [clojure.data.xml.name :refer [qname]] [clojure.data.xml.pu-map :as pu]) (:import (java.io InputStream Reader) (javax.xml.stream XMLInputFactory XMLStreamReader XMLStreamConstants) (clojure.data.xml.event EndElementEvent))) (def ^{:private true} input-factory-props {:allocator XMLInputFactory/ALLOCATOR :coalescing XMLInputFactory/IS_COALESCING :namespace-aware XMLInputFactory/IS_NAMESPACE_AWARE :replacing-entity-references XMLInputFactory/IS_REPLACING_ENTITY_REFERENCES :supporting-external-entities XMLInputFactory/IS_SUPPORTING_EXTERNAL_ENTITIES :validating XMLInputFactory/IS_VALIDATING :reporter XMLInputFactory/REPORTER :resolver XMLInputFactory/RESOLVER :support-dtd XMLInputFactory/SUPPORT_DTD}) (defn- attr-prefix [^XMLStreamReader sreader index] (let [p (.getAttributePrefix sreader index)] (when-not (str/blank? p) p))) (defn- attr-hash [^XMLStreamReader sreader] (persistent! (reduce (fn [tr i] (assoc! tr (qname (.getAttributeNamespace sreader i) (.getAttributeLocalName sreader i) (.getAttributePrefix sreader i)) (.getAttributeValue sreader i))) (transient {}) (range (.getAttributeCount sreader))))) (defn- nss-hash [^XMLStreamReader sreader parent-hash] (pu/persistent! (reduce (fn [tr ^long i] (pu/assoc! tr (.getNamespacePrefix sreader i) (.getNamespaceURI ^XMLStreamReader sreader i))) (pu/transient parent-hash) (range (.getNamespaceCount sreader))))) (defn- location-hash [^XMLStreamReader sreader] (when-let [location (.getLocation sreader)] {:character-offset (.getCharacterOffset location) :column-number (.getColumnNumber location) :line-number (.getLineNumber location)})) ; Note, sreader is mutable and mutated here in pull-seq, but it's ; protected by a lazy-seq so it's thread-safe. (defn pull-seq "Creates a seq of events. The XMLStreamConstants/SPACE clause below doesn't seem to be triggered by the JDK StAX parser, but is by others. Leaving in to be more complete." [^XMLStreamReader sreader {:keys [include-node? location-info skip-whitespace] :as opts} ns-envs] (lazy-seq (loop [] (let [location (when location-info (location-hash sreader))] (static-case (.next sreader) XMLStreamConstants/START_ELEMENT (if (include-node? :element) (let [ns-env (nss-hash sreader (or (first ns-envs) pu/EMPTY)) tag (qname (.getNamespaceURI sreader) (.getLocalName sreader) (.getPrefix sreader)) attrs (attr-hash sreader) next-events (pull-seq sreader opts (cons ns-env ns-envs))] ;; Can't emit EmptyElementEvent here, since ;; for seq-tree node and exit? are mutually exclusive (cons (->StartElementEvent tag attrs ns-env location) next-events)) (recur)) XMLStreamConstants/END_ELEMENT (if (include-node? :element) (do (assert (seq ns-envs) "Balanced end") (cons (->EndElementEvent) (pull-seq sreader opts (rest ns-envs)))) (recur)) XMLStreamConstants/CHARACTERS (if-let [text (and (include-node? :characters) (not (and skip-whitespace (.isWhiteSpace sreader))) (.getText sreader))] (if (zero? (.length ^CharSequence text)) (recur) (cons (->CharsEvent text) (pull-seq sreader opts ns-envs))) (recur)) XMLStreamConstants/COMMENT (if (include-node? :comment) (cons (->CommentEvent (.getText sreader)) (pull-seq sreader opts ns-envs)) (recur)) XMLStreamConstants/END_DOCUMENT nil ;; Consume and ignore comments, spaces, processing instructions etc (recur)))))) (defn- make-input-factory ^XMLInputFactory [props] (let [fac (XMLInputFactory/newInstance)] (doseq [[k v] props :when (contains? input-factory-props k) :let [prop (input-factory-props k)]] (.setProperty fac prop v)) fac)) (defn make-stream-reader [props source] (let [fac (make-input-factory props)] (cond (instance? Reader source) (.createXMLStreamReader fac ^Reader source) (instance? InputStream source) (.createXMLStreamReader fac ^InputStream source) :else (throw (IllegalArgumentException. "source should be java.io.Reader or java.io.InputStream"))))) (defn string-source [s] (java.io.StringReader. s)) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/jvm/pprint.clj000066400000000000000000000023441337626463000272510ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.jvm.pprint (:import (javax.xml.transform Transformer OutputKeys TransformerFactory) (java.io Writer StringReader StringWriter) (javax.xml.transform.stream StreamSource StreamResult))) (defn ^Transformer indenting-transformer [] (doto (-> (TransformerFactory/newInstance) .newTransformer) (.setOutputProperty OutputKeys/INDENT "yes") (.setOutputProperty OutputKeys/METHOD "xml") (.setOutputProperty "{http://xml.apache.org/xslt}indent-amount" "2") ;; print newline after preamble (.setOutputProperty OutputKeys/DOCTYPE_PUBLIC "yes"))) (defn indent-xml [xml-str ^Writer writer] (let [source (-> xml-str StringReader. StreamSource.) result (StreamResult. writer)] (.transform (indenting-transformer) source result))) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/name.cljc000066400000000000000000000163361337626463000262320ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.name #?@(:clj [(:require [clojure.string :as str] [clojure.data.xml.jvm.name :as jvm] (clojure.data.xml [impl :refer [export-api]] [protocols :as protocols :refer [AsQName]])) (:import (clojure.lang Namespace Keyword))] :cljs [(:require-macros [clojure.data.xml.impl :refer [export-api]]) (:require [clojure.string :as str] [clojure.data.xml.js.name :as jsn] [clojure.data.xml.protocols :as protocols :refer [AsQName]]) (:import (goog.string StringBuffer))])) (export-api #?@(:clj [jvm/parse-qname jvm/encode-uri jvm/decode-uri] :cljs [jsn/parse-qname jsn/encode-uri jsn/decode-uri])) ;; protocol functions can be redefined by extend-*, so we wrap ;; protocols/qname-uri protocols/qname-local within regular fns (defn uri-symbol [uri] (symbol (encode-uri (str "xmlns." uri)))) (defn symbol-uri [ss] (let [du (decode-uri (str ss))] (if (.startsWith du "xmlns.") (subs du 6) (throw (ex-info "Uri symbol not valid" {:sym ss}))))) (defn qname-uri "Get the namespace uri for this qname" [v] (protocols/qname-uri v)) (defn qname-local "Get the name for this qname" [v] (protocols/qname-local v)) (defn qname ([local] (qname "" local)) ([uri local] (keyword (when-not (str/blank? uri) (encode-uri (str "xmlns." uri))) local)) ([uri local prefix] (qname uri local))) ;; The empty string shall be equal to nil for xml names (defn namespaced? [qn] (not (str/blank? (qname-uri qn)))) (defn- clj-ns-name [ns] (cond (instance? Namespace ns) (ns-name ns) (keyword? ns) (name ns) :else (str ns))) ;; xmlns attributes get special treatment. they go into metadata, don't contribute to equality (def xmlns-uri "http://www.w3.org/2000/xmlns/") ;; TODO find out if xml prefixed names need any special treatment too (def xml-uri "http://www.w3.org/XML/1998/namespace") (extend-protocol AsQName Keyword (qname-local [kw] (name kw)) (qname-uri [kw] (if-let [ns (namespace kw)] (if (.startsWith ns "xmlns.") (decode-uri (subs ns 6)) (if (= "xmlns" ns) xmlns-uri (throw (ex-info "Keyword ns is not an xmlns. Needs to be in the form :xmlns./" {:kw kw})))) ""))) (defn as-qname [n] (qname (qname-uri n) (qname-local n))) (defn uri-file "Dummy file name for :require'ing xmlns uri" [uri] (str (str/replace (name (uri-symbol uri)) "." "/") ".cljc")) (defn print-uri-file-command! "Shell command to create a dummy file for xmlns. Execute from a source root." [uri] (println "echo \"(ns" (str (uri-symbol uri) ")\" >") (uri-file uri))) #?(:clj (defn alias-uri "Define a Clojure namespace aliases for xmlns uris. This sets up the current namespace for reading qnames denoted with Clojure's ::alias/keywords reader feature. ## Example (alias-uri :D \"DAV:\") ; similar in effect to ;; (require '[xmlns.DAV%3A :as D]) ; but required namespace is auto-created ; henceforth, shorthand keywords can be used {:tag ::D/propfind} ; ::D/propfind will be expanded to :xmlns.DAV%3A/propfind ; in the current namespace by the reader ## Clojurescript support Currently, namespaces can't be auto-created in Clojurescript. Dummy files for aliased uris have to exist. Have a look at `uri-file` and `print-uri-file-command!` to create those." {:arglists '([& {:as alias-nss}])} [& ans] (loop [[a n & rst :as ans] ans] (when (seq ans) (assert (<= (count ans)) (pr-str ans)) (let [xn (uri-symbol n) al (symbol (clj-ns-name a))] (create-ns xn) (alias al xn) (recur rst)))))) (defn xmlns-attr? "Is this qname an xmlns declaration?" [qn] (let [uri (qname-uri qn)] (or (= xmlns-uri uri) (and (str/blank? uri) (= "xmlns" (qname-local qn)))))) (defn xmlns-attr-prefix [qn] (let [uri (qname-uri qn)] (if (str/blank? uri) (do (when-not (= "xmlns" (qname-local qn)) (throw (ex-info "Not an xmlns-attr name" {:qname qn}))) "") (do (when-not (= xmlns-uri uri) (throw (ex-info "Not an xmlns-attr name" {:qname qn}))) (qname-local qn))))) (defn legal-xmlns-binding! [prefix uri] (when (not= (= "xml" prefix) (= xml-uri uri)) (throw (ex-info (str "The xmlns binding for prefix `xml` is fixed to `" xml-uri "`") {:attempted-mapping {:prefix prefix :uri uri}}))) (when (not= (= "xmlns" prefix) (= xmlns-uri uri)) (throw (ex-info (str "The xmlns binding for prefix `xmlns` is fixed to `" xmlns-uri "`") {:attempted-mapping {:prefix prefix :uri uri}})))) (defn separate-xmlns "Call cont with two args: attributes and xmlns attributes" [attrs cont] (loop [attrs* (transient {}) xmlns* (transient {}) [qn :as attrs'] (keys attrs)] (if (seq attrs') (let [val (get attrs qn)] (if (xmlns-attr? qn) (let [prefix (xmlns-attr-prefix qn)] (legal-xmlns-binding! prefix val) (recur attrs* (assoc! xmlns* prefix val) (next attrs'))) (recur (assoc! attrs* qn val) xmlns* (next attrs')))) (cont (persistent! attrs*) (persistent! xmlns*))))) ;(set! *warn-on-reflection* true) #?(:clj (def ^:private ^"[C" prefix-alphabet (char-array (map char (range (int \a) (inc (int \z)))))) :cljs (def ^:private prefix-alphabet (apply str (map js/String.fromCharCode (range (.charCodeAt "a" 0) (inc (.charCodeAt "z" 0))))))) (def ^{:dynamic true :doc "Thread local counter for a single document"} *gen-prefix-counter*) (defn gen-prefix "Generates an xml prefix. Zero-arity can only be called, when *gen-prefix-counter* is bound and will increment it." ([] (let [c *gen-prefix-counter*] #?(:cljs (when (undefined? c) (throw (ex-info "Not bound: *gen-prefix-counter*" {:v #'*gen-prefix-counter*})))) (set! *gen-prefix-counter* (inc c)) (gen-prefix c))) ([n] (let [cnt (alength prefix-alphabet) sb #?(:clj (StringBuilder.) :cljs (StringBuffer.))] (loop [n* n] (let [ch (mod n* cnt) n** (quot n* cnt)] (.append sb (aget prefix-alphabet ch)) (if (pos? n**) (recur n**) (str sb))))))) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/node.cljc000066400000000000000000000164651337626463000262420ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.node "Data types for xml nodes: Element, CData and Comment" {:author "Herwig Hochleitner"} (:require [clojure.data.xml.name :refer [as-qname]]) #?(:clj (:import (clojure.lang IHashEq IObj ILookup IKeywordLookup Counted Associative Seqable IPersistentMap APersistentMap RT MapEquivalence MapEntry) (java.io Serializable Writer) (java.util Map Iterator)))) ;; Parsed data format ;; Represents a node of an XML tree ;; We implement a custom deftype for elements ;; it is similar to (defrecord Element [tag attrs content]) ;; but we override its hash and equality to be compatible with ;; clojure's hash-maps ;; see http://dev.clojure.org/jira/browse/CLJ-2084 ;; also, elements don't have an extmap and degrade to hash-maps also ;; when assoc'ing unknown keys ;; FIXME hash caching cannot be used: http://dev.clojure.org/jira/browse/CLJ-2092 #? (:clj (deftype ElementIterator [el ^:volatile-mutable fields] Iterator (hasNext [_] (boolean (seq fields))) (next [_] (let [f (first fields)] (set! fields (next fields)) (MapEntry. f (get el f)))))) (deftype Element [tag attrs content meta] ;; serializing/cloning, hashing, equality, iteration #?@ (:clj [Serializable MapEquivalence IHashEq (hasheq [this] (APersistentMap/mapHasheq this)) Iterable (iterator [this] (ElementIterator. this '(:tag :attrs :content)))] :cljs [ICloneable (-clone [_] (Element. tag attrs content meta)) IHash (-hash [this] (hash-unordered-coll this)) IEquiv (-equiv [this other] (or (identical? this other) ^boolean (js/cljs.core.equiv_map this other))) IIterable (-iterator [this] (RecordIter. 0 this 3 [:tag :attrs :content] (nil-iter)))]) Object (toString [_] (let [qname (as-qname tag)] (apply str (concat ["<" qname] (mapcat (fn [[n a]] [" " (as-qname n) "=" (pr-str a)]) attrs) (if (seq content) (concat [">"] content [""]) ["/>"]))))) #?@(:clj [(hashCode [this] (APersistentMap/mapHash this)) (equals [this other] (APersistentMap/mapEquals this other)) IPersistentMap (equiv [this other] (APersistentMap/mapEquals this other))]) ;; Main collection interfaces, that are included in IPersistentMap, ;; but are separate protocols in cljs #?(:cljs ILookup) (#?(:clj valAt :cljs -lookup) [this k] (#?(:clj .valAt :cljs -lookup) this k nil)) (#?(:clj valAt :cljs -lookup) [this k nf] (case k :tag tag :attrs attrs :content content nf)) #?(:cljs ICounted) (#?(:clj count :cljs -count) [this] 3) #?(:cljs ICollection) (#?(:clj cons :cljs -conj) [this entry] (conj (with-meta {:tag tag :attrs attrs :content content} meta) entry)) #?(:cljs IAssociative) (#?(:clj assoc :cljs -assoc) [this k v] (case k :tag (Element. v attrs content meta) :attrs (Element. tag v content meta) :content (Element. tag attrs v meta) (with-meta {:tag tag :attrs attrs :content content k v} meta))) #?(:cljs IMap) (#?(:clj without :cljs -dissoc) [this k] (with-meta (case k :tag {:attrs attrs :content content} :attrs {:tag tag :content content} :content {:tag tag :attrs attrs} this) meta)) #?@(:cljs [ISeqable (-seq [this] (seq [[:tag tag] [:attrs attrs] [:content content]]))] :clj [(seq [this] (iterator-seq (.iterator this)))]) #?(:clj (empty [_] (Element. tag {} [] {}))) #?@(:cljs [IEmptyableCollection (-empty [_] (Element. tag {} [] {}))]) ;; j.u.Map and included interfaces #?@(:clj [Map (entrySet [this] (set this)) (values [this] (vals this)) (keySet [this] (set (keys this))) (get [this k] (.valAt this k)) (containsKey [this k] (case k (:tag :attrs :content) true false)) (containsValue [this v] (boolean (some #{v} (vals this)))) (isEmpty [this] false) (size [this] 3)]) ;; Metadata interface #?(:clj IObj :cljs IMeta) (#?(:clj meta :cljs -meta) [this] meta) #?(:cljs IWithMeta) (#?(:clj withMeta :cljs -with-meta) [this next-meta] (Element. tag attrs content next-meta)) ;; cljs printing is protocol-based #?@ (:cljs [IPrintWithWriter (-pr-writer [this writer opts] (-write writer "#xml/element{:tag ") (pr-writer tag writer opts) (when-not (empty? attrs) (-write writer ", :attrs ") (pr-writer attrs writer opts)) (when-not (empty? content) (-write writer ", :content ") (pr-sequential-writer writer pr-writer "[" " " "]" opts content)) (-write writer "}"))])) ;; clj printing is a multimethod #? (:clj (defmethod print-method Element [{:keys [tag attrs content]} ^Writer writer] (.write writer "#xml/element{:tag ") (print-method tag writer) (when-not (empty? attrs) (.write writer ", :attrs ") (print-method attrs writer)) (when-not (empty? content) (.write writer ", :content [") (print-method (first content) writer) (doseq [c (next content)] (.write writer " ") (print-method c writer)) (.write writer "]")) (.write writer "}"))) (defrecord CData [content]) (defrecord Comment [content]) (defn element* "Create an xml element from a content collection and optional metadata" ([tag attrs content meta] (Element. tag (or attrs {}) (remove nil? content) meta)) ([tag attrs content] (Element. tag (or attrs {}) (remove nil? content) nil))) #?(:clj ;; Compiler macro for inlining the two constructors (alter-meta! #'element* assoc :inline (fn ([tag attrs content meta] `(Element. ~tag (or ~attrs {}) (remove nil? ~content) ~meta)) ([tag attrs content] `(Element. ~tag (or ~attrs {}) (remove nil? ~content) nil))))) (defn element "Create an xml Element from content varargs" ([tag] (element* tag nil nil)) ([tag attrs] (element* tag attrs nil)) ([tag attrs & content] (element* tag attrs content))) (defn cdata "Create a CData node" [content] (CData. content)) (defn xml-comment "Create a Comment node" [content] (Comment. content)) (defn map->Element [{:keys [tag attrs content] :as el}] (element* tag attrs content (meta el))) (defn tagged-element [el] (cond (map? el) (map->Element el) ;; TODO support hiccup syntax :else (throw (ex-info "Unsupported element representation" {:element el})))) (defn element? [el] (and (map? el) (some? (:tag el)))) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/process.clj000066400000000000000000000031221337626463000266120ustar00rootroot00000000000000(ns clojure.data.xml.process (:require [clojure.data.xml.event :refer [element-nss] :as evt] [clojure.data.xml.name :as name :refer [gen-prefix *gen-prefix-counter* qname-uri]] [clojure.data.xml.node :refer [element] :as node] [clojure.data.xml.tree :refer [flatten-elements] :as tree] [clojure.string :as str] [clojure.data.xml.pu-map :as pu])) (defn- reduce-tree "Optimized reducer for in-order traversal of nodes, with reduce-like accumulator" [f init xml] (loop [result init {:as tree [child & next-children :as children] :content} xml [parent & next-parents :as parents] ()] (if (seq children) (recur (f result tree) child (concat next-children parents)) (if (seq parents) (recur (f result tree) parent next-parents) (f result tree))))) (defn- qname-uri-xf [xf] (fn [s el] (if (map? el) (reduce-kv (fn [s attr _] (xf s (qname-uri attr))) (xf s (qname-uri (:tag el))) (:attrs el)) s))) (defn find-xmlns "Find all xmlns occuring in a root" [xml] (persistent! (reduce-tree (qname-uri-xf conj!) (transient #{}) xml))) (defn aggregate-xmlns "Put all occurring xmlns into the root" [xml] (with-meta xml {:clojure.data.xml/nss (binding [*gen-prefix-counter* 0] (-> (fn [tm uri] (pu/assoc! tm (gen-prefix) uri)) qname-uri-xf (reduce-tree (pu/transient pu/EMPTY) xml) pu/persistent!))})) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/protocols.cljc000066400000000000000000000023501337626463000273250ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.protocols) ;; XML names can be any data type that has at least a namespace uri and a name slot (defprotocol AsQName (qname-local [qname] "Get the name for this qname") (qname-uri [qname] "Get the namespace uri for this qname")) (defprotocol EventGeneration "Protocol for generating new events based on element type" (gen-event [item] "Function to generate an event for e.") (next-events [item next-items] "Returns the next set of events that should occur after e. next-events are the events that should be generated after this one is complete.")) (defprotocol AsElements (as-elements [expr] "Return a seq of elements represented by an expression.")) (defprotocol AsXmlString (xml-str [node] "Serialize atribute value or content node")) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/prxml.clj000066400000000000000000000047141337626463000263060ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.prxml (:require [clojure.data.xml.protocols :refer [AsElements as-elements]] [clojure.data.xml.node :refer [cdata xml-comment element* element]])) (defn sexp-element [tag attrs child] (cond (= :-cdata tag) (cdata (first child)) (= :-comment tag) (xml-comment (first child)) :else (element* tag attrs (mapcat as-elements child)))) (extend-protocol AsElements clojure.lang.IPersistentVector (as-elements [v] (let [[tag & [attrs & after-attrs :as content]] v [attrs content] (if (map? attrs) [(into {} (for [[k v] attrs] [k (str v)])) after-attrs] [{} content])] [(sexp-element tag attrs content)])) clojure.lang.ISeq (as-elements [s] (mapcat as-elements s)) clojure.lang.Keyword (as-elements [k] [(element k)]) java.lang.String (as-elements [s] [s]) nil (as-elements [_] nil) java.lang.Object (as-elements [o] [(str o)])) (defn sexps-as-fragment "Convert a compact prxml/hiccup-style data structure into the more formal tag/attrs/content format. A seq of elements will be returned, which may not be suitable for immediate use as there is no root element. See also sexp-as-element. The format is [:tag-name attr-map? content*]. Each vector opens a new tag; seqs do not open new tags, and are just used for inserting groups of elements into the parent tag. A bare keyword not in a vector creates an empty element. To provide XML conversion for your own data types, extend the AsElements protocol to them." ([] nil) ([sexp] (as-elements sexp)) ([sexp & sexps] (mapcat as-elements (cons sexp sexps)))) (defn sexp-as-element "Convert a single sexp into an Element" [sexp] (let [[root & more] (sexps-as-fragment sexp)] (when more (throw (IllegalArgumentException. "Cannot have multiple root elements; try creating a fragment instead"))) root)) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/pu_map.cljc000066400000000000000000000067711337626463000265750ustar00rootroot00000000000000(ns clojure.data.xml.pu-map "Provides a bidirectional mapping for keeping track of prefix->uri mappings in xml namespaces. This has the semantics of a basic key -> multiple values map + two special features, both of which are dictated by the xml standard: - instead of a special dissoc, there is assoc to empty string or nil - there are two fixed, unique mappings: - \"xml\" <-> [\"http://www.w3.org/2000/xmlns/\"] - \"xmlns\" <-> [\"http://www.w3.org/XML/1998/namespace\"]" (:require [clojure.data.xml.name :as name] [clojure.string :as str] [clojure.core :as core]) (:refer-clojure :exclude [assoc! dissoc! transient persistent! get assoc merge])) (def prefix-map :p->u) (def uri-map :u->ps) ;; TODO replace this with a deftype for memory savings (def EMPTY {:u->ps {name/xml-uri ["xml"] name/xmlns-uri ["xmlns"]} :p->u {"xml" name/xml-uri "xmlns" name/xmlns-uri}}) ;; TODO implement valid? with internal consistency check (defn transient [pu] (let [{:keys [u->ps p->u] :as pu*} (or pu EMPTY)] (assert (and u->ps p->u) (str "Not a pu-map " (pr-str pu*))) (core/assoc! (core/transient {}) :p->u (core/transient p->u) :u->ps (core/transient u->ps)))) (defn persistent! [put] (core/persistent! (core/assoc! put :p->u (core/persistent! (core/get put :p->u)) :u->ps (core/persistent! (core/get put :u->ps))))) (defn- assoc-uri! [u->ps uri prefix] (core/assoc! u->ps uri (if-let [ps (core/get u->ps uri)] (conj ps prefix) [prefix]))) (defn- dissoc-uri! [u->ps uri prefix] (if-let [ps (seq (remove #{prefix} (core/get u->ps uri)))] (core/assoc! u->ps uri (vec ps)) (core/dissoc! u->ps uri))) (defn assoc! [{:as put :keys [p->u u->ps]} prefix uri] (name/legal-xmlns-binding! prefix uri) (let [prefix* (str prefix) prev-uri (core/get p->u prefix*)] (core/assoc! put :p->u (if (str/blank? uri) (core/dissoc! p->u prefix*) (core/assoc! p->u prefix* uri)) :u->ps (if (str/blank? uri) (dissoc-uri! u->ps prev-uri prefix*) (cond (= uri prev-uri) u->ps (not prev-uri) (assoc-uri! u->ps uri prefix*) :else (-> u->ps (dissoc-uri! prev-uri prefix*) (assoc-uri! uri prefix*))))))) (defn get [{:keys [p->u]} prefix] (core/get p->u (str prefix))) (defn get-prefixes [{:keys [u->ps]} uri] (core/get u->ps uri)) (def get-prefix (comp first get-prefixes)) (defn assoc [put & {:as kvs}] (persistent! (reduce-kv assoc! (transient put) kvs))) (defn reduce-diff "A high-performance diffing operation, that reduces f over changed and removed prefixes" [f s {ppu :p->u} {pu :p->u}] (let [s (reduce-kv (fn [s p _] (if (contains? pu p) s (f s p ""))) s ppu) s (reduce-kv (fn [s p u] (if (= u (core/get ppu p)) s (f s p u))) s pu)] s)) (defn merge-prefix-map "Merge a prefix map into pu-map" [pu pm] (persistent! (reduce-kv assoc! (transient pu) pm))) (defn merge "Merge two pu-maps, left to right" [pu {:keys [:p->u]}] (merge-prefix-map pu p->u)) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/clojure/data/xml/tree.clj000066400000000000000000000056431337626463000261050ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns clojure.data.xml.tree (:require [clojure.data.xml.protocols :refer [gen-event next-events]] [clojure.data.xml.event :refer [event-element event-node event-exit?]])) (defn seq-tree "Takes a seq of events that logically represents a tree by each event being one of: enter-sub-tree event, exit-sub-tree event, or node event. Returns a lazy sequence whose first element is a sequence of sub-trees and whose remaining elements are events that are not siblings or descendants of the initial event. The given exit? function must return true for any exit-sub-tree event. parent must be a function of two arguments: the first is an event, the second a sequence of nodes or subtrees that are children of the event. parent must return nil or false if the event is not an enter-sub-tree event. Any other return value will become a sub-tree of the output tree and should normally contain in some way the children passed as the second arg. The node function is called with a single event arg on every event that is neither parent nor exit, and its return value will become a node of the output tree. (seq-tree #(when (= %1 :<) (vector %2)) #{:>} str [1 2 :< 3 :< 4 :> :> 5 :> 6]) ;=> ((\"1\" \"2\" [(\"3\" [(\"4\")])] \"5\") 6)" [parent exit? node coll] (lazy-seq (when-let [[event] (seq coll)] (let [more (rest coll)] (if (exit? event) (cons nil more) (let [tree (seq-tree parent exit? node more)] (if-let [p (parent event (lazy-seq (first tree)))] (let [subtree (seq-tree parent exit? node (lazy-seq (rest tree)))] (cons (cons p (lazy-seq (first subtree))) (lazy-seq (rest subtree)))) (cons (cons (node event) (lazy-seq (first tree))) (lazy-seq (rest tree)))))))))) ;; # Break circular dependency of emitter-parser common infrastructure ;; "Parse" events off the in-memory representation (defn flatten-elements "Flatten a collection of elements to an event seq" [elements] (when (seq elements) (lazy-seq (let [e (first elements)] (cons (gen-event e) (flatten-elements (next-events e (rest elements)))))))) ;; "Emit" events to the in-memory representation (defn event-tree "Returns a lazy tree of Element objects for the given seq of Event objects. See source-seq and parse." [events] (ffirst (seq-tree event-element event-exit? event-node events))) data.xml-data.xml-0.2.0-alpha6/src/main/clojure/data_readers.cljc000066400000000000000000000001341337626463000245410ustar00rootroot00000000000000{xml/ns clojure.data.xml.name/uri-symbol xml/element clojure.data.xml.node/tagged-element} data.xml-data.xml-0.2.0-alpha6/src/main/clojurescript/000077500000000000000000000000001337626463000225155ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojurescript/xmlns/000077500000000000000000000000001337626463000236565ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojurescript/xmlns/http%3A%2F%2Fwww/000077500000000000000000000000001337626463000263255ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojurescript/xmlns/http%3A%2F%2Fwww/w3/000077500000000000000000000000001337626463000266565ustar00rootroot00000000000000org%2F2000%2Fxmlns%2F.cljc000066400000000000000000000004331337626463000325360ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojurescript/xmlns/http%3A%2F%2Fwww/w3(ns xmlns.http%3A%2F%2Fwww.w3.org%2F2000%2Fxmlns%2F "Require - able uri namespace for the `xmlns` prefix. This uri is special, in that it is predefined in every xml vocabulary and has the prefix `xmlns` reserved for it, which cannot be redefined" {:fixed-prefix "xmlns"}) org%2FXML%2F1998%2Fnamespace.cljc000066400000000000000000000004341337626463000337440ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/clojurescript/xmlns/http%3A%2F%2Fwww/w3(ns xmlns.http%3A%2F%2Fwww.w3.org%2FXML%2F1998%2Fnamespace "Require - able uri namespace for the `xml` prefix. This uri is special, in that it is predefined in every xml vocabulary and has the prefix `xml` reserved for it, which cannot be redefined" {:fixed-prefix "xml"}) data.xml-data.xml-0.2.0-alpha6/src/main/resources/000077500000000000000000000000001337626463000216375ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/resources/clojure/000077500000000000000000000000001337626463000233025ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/resources/clojure/data/000077500000000000000000000000001337626463000242135ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/resources/clojure/data/xml/000077500000000000000000000000001337626463000250135ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/main/resources/clojure/data/xml/spec.cljc000066400000000000000000000051051337626463000266030ustar00rootroot00000000000000(ns clojure.data.xml.spec (:require [clojure.spec :as s] [#?(:cljs cljs.spec.impl.gen :clj clojure.spec.gen) :as gen] clojure.test.check.generators [clojure.data.xml :as xml] [clojure.data.xml.name :as name] [clojure.data.xml.name :as node] #?@(:cljs [[clojure.data.xml.js.dom :as dom]]) [clojure.string :as str])) (s/def ::qname-conformer (s/and (s/conformer (fn [qn] (try {:uri (name/qname-uri qn) :local (name/qname-local qn)} (catch :default e (.error js/console e "Could not conform to qname:" qn) ::s/invalid))) (fn [{:keys [uri local] :as arg}] (.log js/console arg) (name/qname uri local))) #(not (str/blank? (:local %))))) (s/def ::name/qname (-> (s/or :global (s/or :kw (s/and simple-keyword? ::qname-conformer) :str (s/and string? ::qname-conformer #(str/blank? (:uri %)))) :qualified (s/or :kw (s/and qualified-keyword? ::qname-conformer) :str (s/and string? ::qname-conformer))) (s/with-gen #(gen/fmap (fn [[uri local]] (name/qname uri local)) (gen/tuple (gen/fmap (fn [s] (when-not (str/blank? s) (str "urn:" s))) (gen/string-alphanumeric)) (gen/fmap (partial str "G") (gen/string-alphanumeric))))))) (s/def ::node/Element (s/keys :req-un [::node/tag] :opt-un [::node/attrs ::node/content])) #?(:cljs (do (s/def ::dom/Element (s/with-gen (partial instance? dom/Element) #(gen/fmap dom/element-node (s/gen ::node/Element)))) (s/def ::dom/Text (s/with-gen (partial instance? dom/Text) #(gen/fmap dom/text-node (gen/string-ascii)))))) (s/def ::xml/Element #?(:clj ::node/Element :cljs (s/or :dom ::dom/Element :rec ::node/Element))) (s/def ::xml/Text (s/or :blank (s/with-gen str/blank? #(s/gen #{"" nil})) :str string? #?@(:cljs [:text ::dom/Text]))) (s/def ::xml/Node (s/or :text ::xml/Text :elem ::xml/Element)) (s/def ::node/tag ::name/qname) (s/def ::node/attrs (s/map-of ::name/qname string? :conform-keys true)) (s/def ::node/content (s/coll-of ::xml/Node)) (comment (s/conform (s/coll-of ::name/qname) [:foo :xmlns/foo]) (require '[clojure.spec.gen :as gen]) (s/exercise ::name/qname) ) data.xml-data.xml-0.2.0-alpha6/src/test/000077500000000000000000000000001337626463000176605ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/test/clojure/000077500000000000000000000000001337626463000213235ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/000077500000000000000000000000001337626463000227665ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/000077500000000000000000000000001337626463000236775ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/000077500000000000000000000000001337626463000244775ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_cljs.clj000066400000000000000000000037211337626463000271660ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns ^{:doc "Clojurescript tests for data.xml"} clojure.data.xml.test-cljs (:require [clojure.test :refer :all])) (deftest clojurescript-test-suite (try (require 'clojure.data.xml.cljs-testsuite) (eval '(clojure.data.xml.cljs-testsuite/run-testsuite! "target/cljs-test-nashorn")) (when (not (neg? (compare (System/getProperty "java.runtime.version") "1.9"))) (println "CELEBRATION: CLJS-2377 has been fixed. Hooray! Please add jdk >= 1.9 back to the test matrix")) (catch Exception e (if (or (neg? (compare ((juxt :major :minor) *clojure-version*) [1 8])) (neg? (compare (System/getProperty "java.runtime.version") "1.8")) (not (neg? (compare (System/getProperty "java.runtime.version") "1.9")))) (println "WARN: ignoring cljs testsuite error on clojure < 1.8 or jdk < 1.8 also on jdk >= 1.9, see CLJS-2377" *clojure-version* (System/getProperty "java.runtime.name") (System/getProperty "java.vm.version") (System/getProperty "java.runtime.version") \newline (str e)) (do (println "ERROR: cljs nashorn test suite should be able to run on clojure >= 1.8 and jdk >= 1.8" *clojure-version* (System/getProperty "java.runtime.name") (System/getProperty "java.vm.version") (System/getProperty "java.runtime.version")) (throw e)))))) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_emit.clj000066400000000000000000000275611337626463000272010ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns ^{:doc "Tests for emit to print XML text." :author "Chris Houser"} clojure.data.xml.test-emit (:require [clojure.test :refer :all] [clojure.data.xml :refer :all] [clojure.data.xml.test-utils :refer [test-stream lazy-parse*]] [clojure.data.xml.impl :refer [compile-if]] [clojure.data.xml.name :as name] [clojure.data.xml.pu-map :as pu]) (:import (javax.xml.namespace QName))) (def deep-tree (lazy-parse* (str "" " t1t2" " t3t4" " t5t6" " t7" " t8t10t11" " t12t13t14" ""))) (deftest test-defaults (testing "basic parsing" (let [expect (str "" "" " t1t2" " t3t4" " t5t6" " t7" " t8t10t11" " t12t13t14" "")] (is (= expect (emit-str deep-tree))))) (testing "namespaced defaults" (let [expect (str "done")] (is (= expect (emit-str (element "{DAV:}bar" {"{DAV:}item" 1 :xmlns/D "DAV:"} [(element "{DAV:}baz" {:xmlns.DAV%3A/item 2} "done")])))) (is (= expect (emit-str {:tag "{DAV:}bar" :attrs {"{DAV:}item" 1 :xmlns/D "DAV:"} :content [{:tag "{DAV:}baz" :attrs {:xmlns.DAV%3A/item 2} :content "done"}]})))))) (deftest mixed-quotes (is (= (lazy-parse* (str "" "")) (lazy-parse* (emit-str (element :mixed {:single "'single'quotes'here" :double "\"double\"quotes\"here\""})))))) (defn emit-char-seq [xml-tree encoding] (with-open [bos (java.io.ByteArrayOutputStream.) stream (java.io.OutputStreamWriter. bos encoding)] (emit xml-tree stream :encoding encoding) (.flush stream) (map #(if (pos? %) (char %) %) (.toByteArray bos)))) (deftest encoding (let [input-tree (lazy-parse* "Übercool")] (is (= (concat "" "" [-61 -100] "bercool") (emit-char-seq input-tree "UTF-8"))) (is (= (concat "" "" [-36] "bercool") (emit-char-seq input-tree "ISO-8859-1"))))) (deftest encoding-assertion (is (thrown? Exception (let [stream (java.io.ByteArrayOutputStream.)] (binding [*out* (java.io.OutputStreamWriter. stream "UTF-8")] (emit (element :foo) *out* :encoding "ISO-8859-1")))))) (deftest doctype (let [input-tree (lazy-parse* "cool") doctype-html "" doctype-html-401-transitional "" doctype-xhtml-10-strict ""] (is (= (str "" doctype-html "cool") (emit-str input-tree :doctype doctype-html))) (is (= (str "" doctype-html-401-transitional "cool") (emit-str input-tree :doctype doctype-html-401-transitional))) (is (= (str "" doctype-xhtml-10-strict "cool") (emit-str input-tree :doctype doctype-xhtml-10-strict))))) (deftest emitting-cdata (testing "basic cdata" (is (= (str "" "]]>") (emit-str (element :cdata-stuff {} (cdata "")))))) (testing "cdata with ]]> chars" (is (= (str "" "]]]]>]]>") (emit-str (element :cdata-stuff {} (cdata "]]>")))))) (testing "cdata with ]]> chars and newlines" (is (= (str "" "\n\n\n]]]]>]]>") (emit-str (element :cdata-stuff {} (cdata "\n\n\n]]>"))))))) (deftest emitting-cdata-with-embedded-end (is (= (str "" "]]]]>]]>") (emit-str (element :cdata-stuff {} (cdata "]]>"))))) ) (deftest emitting-comment (is (= (str "" "comment not here") (emit-str (element :comment-stuff {} "comment " (xml-comment " goes here ") " not here"))))) (deftest test-indent (let [nested-xml (lazy-parse* (str "foo")) expect (str "\n \n \n foo\n \n \n\n") sw (java.io.StringWriter.) _ (indent nested-xml sw) result (.toString sw)] (is (= expect (subs result (.indexOf result "")))))) (deftest test-indent-str (let [nested-xml (lazy-parse* (str "foo")) expect (str "\n \n \n foo\n \n \n\n") result (indent-str nested-xml)] (is (= expect (subs result (.indexOf result "")))))) (deftest test-indent-str-with-doctype (let [nested-xml (lazy-parse* (str "foo")) doctype "" expect "\n\n \n \n foo\n \n \n\n" result (indent-str nested-xml :doctype doctype) offset-dt (.indexOf result "" offset-dt))] (is (= expect (subs result offset-res))))) (defmacro are-serializable [group-description extra-attrs & {:as data-strings}] `(testing ~group-description (testing "in content" ~@(for [[data string] data-strings] `(is (= (parse-str (emit-str (element :e ~extra-attrs ~string))) (parse-str (emit-str (element :e ~extra-attrs ~data))))))) (testing "in attrs" ~@(for [[data string] data-strings] `(is (= (emit-str (element :e ~(assoc extra-attrs :a string))) (emit-str (element :e ~(assoc extra-attrs :a data))))))))) (deftest test-datatypes ;; https://www.w3.org/TR/xmlschema-2/#built-in-datatypes (testing "serializing" (are-serializable "booleans" {} true "true" false "false") (are-serializable "numbers" {} 1 "1" 1.2 "1.2" 3/4 "0.75" (int 0) "0" (float 1.4) "1.4" 1.25M "1.25" (BigInteger. "42424242424242424242424242424242") "42424242424242424242424242424242" 42424242424242424242424242424242 "42424242424242424242424242424242") (are-serializable "byte-arrays" {} (byte-array [0 1 2 3 4]) "AAECAwQ=") (are-serializable "uris" {} (java.net.URI. "S:l") "S:l" (java.net.URL. "http://foo") "http://foo") (are-serializable "dates" {} (java.util.Date. 0) "1970-01-01T00:00:00.000-00:00") (compile-if (Class/forName "java.time.Instant") (are-serializable "instants" {} (java.time.Instant/ofEpochMilli 0) "1970-01-01T00:00:00.000-00:00") nil) (are-serializable "qnames" {:xmlns/p "U:"} :xmlns.U%3A/qn "p:qn" (QName. "U:" "qn") "p:qn") (testing "qnames generated" (is (thrown? Exception (emit-str (element :e {} :xmlns.U%3A/qn)))) (is (thrown? Exception (emit-str (element :e {:a :xmlns.U%3A/qn})))) (is (thrown? Exception (emit-str (element :e {} (QName. "U:" "qn"))))) (is (thrown? Exception (emit-str (element :e {:a (QName. "U:" "qn")}))))))) (deftest test-event-seq-emit (is (= "123" (emit-str (event-seq (java.io.StringReader. "123") {}))))) (deftest test-sibling-xmlns (let [el (element (as-qname "{NS1}top") {} (element (as-qname "{NS2}foo")) (element (as-qname "{NS2}bar")))] (is (= (parse-str (emit-str el)) el)))) (alias-uri :xml name/xml-uri) (deftest test-default-xmlns (let [nss-meta (comp :clojure.data.xml/nss meta)] (is (= (pu/merge-prefix-map nil {"" "NS"}) (nss-meta (parse-str "")) (nss-meta (parse-str (emit-str (parse-str ""))))))) (is (thrown? Exception (emit-str {:tag :el :attrs {(name/qname name/xmlns-uri "xml") "foo"}}))) (is (thrown? Exception (emit-str {:tag :el :attrs {(name/qname name/xmlns-uri "xmlns") "foo"}}))) (is (thrown? Exception (emit-str {:tag :el :attrs {:xmlns/xml "foo"}}))) (is (thrown? Exception (emit-str {:tag :el :attrs {:xmlns/xmlns "foo"}}))) (is (thrown? Exception (parse-str "")) "TODO: find out if this is standard conforming, or a bug in StAX") (is (= (emit-str {:tag :el :attrs {:xmlns/xmlns "http://www.w3.org/2000/xmlns/"}}) "")) (is (= (emit-str {:tag :el :attrs {:xmlns/xml "http://www.w3.org/XML/1998/namespace" ::xml/lang "en"}}) ""))) (deftest test-empty-elements (is (= (emit-str {:tag :a :content []}) "")) (is (= (emit-str {:tag :a :content [""]}) ""))) (deftest test-roundtrip (is (= (emit-str (with-meta (parse-str "") nil)) "")) (is (= (emit-str (parse-str "")) "")) (is (= (emit-str (parse-str "")) "")) ; builtins (is (= (emit-str (parse-str "")) "")) (is (thrown? Exception (parse-str "")) "TODO: find out if this is standard conforming, or a bug in StAX")) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_entities.clj000066400000000000000000000040561337626463000300610ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns ^{:doc "Test that external entities are not resolved by default, see https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing" :author "Carlo Sciolla"} clojure.data.xml.test-entities (:require [clojure.java.io :as io] [clojure.test :refer :all] [clojure.data.xml :refer :all])) (defn vulnerable-input "Creates an XML with an external entity referring to the given URL" [file-url] (str "" "" " ]>" "&xxe;")) (defn secret-file "Returns the URL to the secret file containing the server root password" [] (io/resource "secret.txt")) (defn parse-vulnerable-file "Parses the vulnerable file, optionally passing the given options to the parser" ([] (parse-str (vulnerable-input (secret-file)))) ([& options] (apply parse-str (vulnerable-input (secret-file)) options))) (deftest prevent-xxe-by-default (testing "To prevent XXE attacks, exernal entities by default resolve to nil" (let [parsed (parse-vulnerable-file) expected {:tag :foo :attrs {} :content ()}] (is (= expected parsed))))) (deftest allow-external-entities-if-required (testing "If explicitly enabled, external entities are property resolved" (let [parsed (parse-vulnerable-file :supporting-external-entities true) expected {:tag :foo :attrs {} :content ["root_password\n"]}] (is (= expected parsed))))) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_equiv.cljc000066400000000000000000000011031337626463000275170ustar00rootroot00000000000000(ns clojure.data.xml.test-equiv (:require [clojure.data.xml :refer [element qname]] [clojure.test :refer [deftest is are testing]])) (deftest test-node-equivalence (are [repr1 repr2] (and (is (= repr1 repr2)) (is (= (hash repr1) (hash repr2)))) (element :foo) {:tag :foo :attrs {} :content []} (element (qname "DAV:" "foo")) {:tag (qname "DAV:" "foo") :attrs {} :content []} (element :foo {:a "b"}) {:tag :foo :attrs {:a "b"} :content []} (element :foo {:a "b"} "a" "b") {:tag :foo :attrs {:a "b"} :content ["a" "b"]})) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_names.clj000066400000000000000000000042071337626463000273360ustar00rootroot00000000000000(ns clojure.data.xml.test-names (:require [clojure.data.xml :refer :all] [clojure.test :refer :all])) (alias-uri :U "uri-u:" :D "DAV:" 'V "uri-v:" "W" "uri-w:") (deftest test-types (are [vals values] (every? true? (for [v values] (is (= vals [(qname-uri v) (qname-local v)]) (str "Interpreted QName: " (pr-str v))))) ["" "name"] ["name" :name (parse-qname "name")] ["uri-u:" "name"] [::U/name "{uri-u:}name" (parse-qname "{uri-u:}name") (as-qname "{uri-u:}name")] ["uri-v:" "vname"] [::V/vname "{uri-v:}vname" (parse-qname "{uri-v:}vname")] ["uri-w:" "wname"] [::W/wname "{uri-w:}wname" (parse-qname "{uri-w:}wname")] ;; ["http://www.w3.org/XML/1998/namespace" "name"] [:xml/name] ["http://www.w3.org/2000/xmlns/" "name"] [:xmlns/name])) (deftest test-emit-raw (are [node result] (= (emit-str node) result) {:tag ::D/limit :attrs {:xmlns/D "DAV:"} :content [{:tag ::D/nresults :content ["100"]}]} "100")) (deftest test-parse-raw (are [xml result] (= (parse-str xml) result) "100" (element ::D/limit {} (element ::D/nresults nil "100")))) (deftest qnames (is (= (qname "foo") (as-qname :foo)))) (deftest test-gen-prefix (are [node] (= (parse-str (emit-str node)) node) (element ::D/limit {::V/moo "gee"} (element ::D/nresults nil "100")))) (deftest test-reassign-prefix (are [node reparsed] (= (parse-str (emit-str node)) reparsed) (element ::D/limit {:xmlns/D "DAV:"} ;; because of outer binding, "uri-v:" will be bound to ;; generated xmlns:a instead of xmlns:D (element ::V/other {:xmlns/D "uri-v:"})) (element ::D/limit {} (element ::V/other)))) (deftest test-preserve-empty-ns (are [el] (= el (parse-str (emit-str (assoc-in el [:attrs :xmlns] "DAV:")))) (element :top-level) (element ::D/local-root {} (element :top-level)))) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_parse.clj000066400000000000000000000125071337626463000273470ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns ^{:doc "Tests for XML parsing functions." :author "Chris Houser"} clojure.data.xml.test-parse (:require [clojure.test :refer :all] [clojure.data.xml :refer [parse-str element]] [clojure.data.xml.test-utils :refer [test-stream lazy-parse*]])) (deftest simple (let [input "This is bold test" expected (element :html {} (element :body {:bg "red"} "This is " (element :b {} "bold") " test"))] (is (= expected (lazy-parse* input))))) (deftest deep (let [input (str "" " t1t2" " t3t4" " t5t6" " t7" " t8t10t11" " t12t13t14" "") expected (element :a {:h "1", :i "2", :j "3"} " t1" (element :b {:k "4"} "t2") " t3" (element :c {} "t4") " t5" (element :d {} "t6") " t7" (element :e {:l "5" :m "6"} " t8" (element :f {} "t10") "t11") " t12" (element :g {} "t13") "t14")] (is (= expected (lazy-parse* input))) (is (= expected (parse-str input))))) (deftest test-xml-with-whitespace (let [input (str "\n123\n1 2 3\n\n") expected (element :a {} "\n" (element :b {:with-attr "s p a c e"} "123") "\n" (element :c {} "1 2 3") "\n\n")] (is (= expected (lazy-parse* input))))) (deftest test-cdata-parse (let [input "]]>" expected (element :cdata {} (element :is {} (element :here {} "")))] (is (= expected (lazy-parse* input))))) (deftest test-comment-parse (let [input "there" expected (element :comment {} (element :is {} (element :here {} "there")))] (is (= expected (lazy-parse* input))))) (deftest test-parsing-processing-instructions (let [input " With Stuff" expected (element :ATag {} "With Stuff")] (is (= expected (parse-str input))))) (deftest test-parsing-doctypes (let [input "

Heading Stuff

" expected (element :html {} (element :h1 {} "Heading Stuff"))] (is (= expected (parse-str input))))) (deftest test-coalescing (let [input ""] (is (= ["\nfoo bar\n\nbaz\n"] (:content (parse-str input)))) (is (= ["\nfoo bar\n" "\nbaz\n"] (:content (parse-str input :coalescing false)))))) (deftest test-location-meta (let [input "\n" location-meta (comp :clojure.data.xml/location-info meta)] ;the numbers look 1 based (is (= 1 (-> input parse-str location-meta :line-number))) (is (= 1 (-> input parse-str location-meta :column-number))) (is (= 1 (-> input parse-str :content first location-meta :line-number))) (is (= 4 (-> input parse-str :content first location-meta :column-number))) (is (= 2 (-> input (parse-str :skip-whitespace true) :content second location-meta :line-number))) (is (nil? (-> input (parse-str :location-info false) location-meta))))) (deftest test-ignorable-whitespace ;; FIXME implement clojure.lang.MapEquivalence for records (clojure.lang.APersistentMap/mapEquals (parse-str " ]> lookupSymbol Clojure XML <3 ") {:tag :methodCall, :attrs {}, :content [{:tag :methodName, :attrs {}, :content ["lookupSymbol"]} {:tag :params, :attrs {}, :content [{:tag :param, :attrs {}, :content [{:tag :value, :attrs {}, :content [{:tag :string, :attrs {}, :content ["\n Clojure XML <3 \n "]}]}]}]}]})) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_pprint.clj000066400000000000000000000015561337626463000275530ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns ^{:doc "Tests for emit to print XML text." :author "Herwig Hochleitner"} clojure.data.xml.test-pprint (:require [clojure.test :refer :all] [clojure.data.xml :refer :all])) (def xml "") (def indented-xml (str "" "\n" " ")) (deftest test-indent (is (= indented-xml (indent-str (parse-str xml))))) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_process.cljc000066400000000000000000000022061337626463000300510ustar00rootroot00000000000000(ns clojure.data.xml.test-process (:require [clojure.data.xml :refer [element qname element? #?@(:clj [element-nss aggregate-xmlns find-xmlns])]] [clojure.test :refer [deftest is]] [clojure.walk :as w] [clojure.string :as str] [clojure.data.xml.pu-map :as pu])) (def test-data (element :foo nil (with-meta (element :bar {:xmlns "MOO:"} "some" "content") {:clojure.data.xml/nss (pu/merge-prefix-map nil {"p" "PAR:"})}) "more content" (element (qname "GOO:" "ho") {(qname "GEE:" "hi") "ma"} "ii") "end")) #? (:clj (deftest process (is (= (find-xmlns test-data) #{"" "GEE:" "GOO:"})) (let [nss (set (vals (:p->u (element-nss (aggregate-xmlns test-data)))))] (is (every? #(contains? nss %) ["GEE:" "GOO:"]))))) (deftest walk-test (is (= {:tag :FOO, :attrs {}, :content ()} (w/postwalk (fn [e] (if (element? e) (update e :tag (comp keyword str/upper-case name)) e)) (element :foo))))) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_pu.cljc000066400000000000000000000053621337626463000270250ustar00rootroot00000000000000(ns clojure.data.xml.test-pu (:require [clojure.data.xml.pu-map :as pu] [clojure.data.xml.name :as name] [clojure.test :refer [deftest is are testing]])) (deftest builtin-mappings (is (= name/xml-uri (pu/get pu/EMPTY "xml"))) (is (= name/xmlns-uri (pu/get pu/EMPTY "xmlns"))) (is (= ["xml"] (pu/get-prefixes pu/EMPTY name/xml-uri))) (is (= ["xmlns"] (pu/get-prefixes pu/EMPTY name/xmlns-uri))) (are [p u] (thrown? #?(:clj Exception :cljs js/Error) (pu/assoc pu/EMPTY p u)) "xml" "_" "xmlns" "_" "_" name/xml-uri "_" name/xmlns-uri)) (deftest basic-operation (are [associated-groups expected-uris expected-prefixes] (let [pu (reduce (fn [pu* group] (apply pu/assoc pu* group)) pu/EMPTY associated-groups)] (every? true? (apply concat (for [[prefix uri] (partition 2 expected-uris)] (is (= uri (pu/get pu prefix)))) (for [[uri prefixes] (partition 2 expected-prefixes)] [(is (= prefixes (pu/get-prefixes pu uri))) (is (= (first prefixes) (pu/get-prefix pu uri)))])))) [] ["wrong-prefix" nil "xml" name/xml-uri "xmlns" name/xmlns-uri] ["wrong-uri" nil name/xml-uri ["xml"] name/xmlns-uri ["xmlns"]] [[nil "FIN:"]] ["wrong-prefix" nil "xml" name/xml-uri "xmlns" name/xmlns-uri "" "FIN:" nil "FIN:"] ["wrong-uri" nil "FIN:" [""] name/xml-uri ["xml"] name/xmlns-uri ["xmlns"]] [["p" "U:" "q" "V:"]] ["wrong-prefix" nil "xml" name/xml-uri "xmlns" name/xmlns-uri "p" "U:" "q" "V:"] ["wrong-uri" nil name/xml-uri ["xml"] name/xmlns-uri ["xmlns"] "U:" ["p"] "V:" ["q"]] [["p" "U:" "q" "V:"] ["r" "U:" "s" "V:"] ["t" "U:"] ["p" "" "q" ""]] ["p" nil "q" nil "r" "U:"] ["U:" ["r" "t"] "V:" ["s"]] [["xml" name/xml-uri "xmlns" name/xmlns-uri]] ["xml" name/xml-uri "xmlns" name/xmlns-uri] [name/xml-uri ["xml"] name/xmlns-uri ["xmlns"]])) (deftest assoc-nil (let [pu (pu/assoc nil nil "NIL")] (is (= "NIL" (pu/get pu nil) (pu/get pu ""))) (is (= "" (pu/get-prefix pu "NIL"))))) (deftest direct-access (is (= {"" "NIL" "a" "A" "xml" name/xml-uri "xmlns" name/xmlns-uri} (pu/prefix-map (pu/assoc nil "a" "A" nil "NIL"))))) (deftest diffing (is (= {"c" "d"} (pu/reduce-diff assoc {} (pu/assoc pu/EMPTY "a" "b") (pu/assoc pu/EMPTY "a" "b" "c" "d"))))) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_seq_tree.clj000066400000000000000000000043311337626463000300400ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns ^{:doc "Tests for seq-tree, building a lazy tree from lazy seq." :author "Chris Houser"} clojure.data.xml.test-seq-tree (:require [clojure.test :refer :all] [clojure.data.xml.tree :refer [seq-tree]]) (:import (java.lang.ref WeakReference))) (def tt (partial #'seq-tree #(when (= %1 :<) (vector %2)) #{:>} str)) (deftest example (is (= '(("1" "2" [("3" [("4")])] "5") 6) (tt [1 2 :< 3 :< 4 :> :> 5 :> 6])))) (defn limit [& args] (tt (concat args (lazy-seq (throw (Exception. "not lazy enough")))))) (deftest lazy-top-level (is (= '() (take 0 (first (limit 1))))) ; should do better! (is (= '("1") (take 1 (first (limit 1))))) (is (= '("1" "2") (take 2 (first (limit 1 2))))) (is (= '("1" "2" "3") (take 3 (first (limit 1 2 3)))))) (deftest lazy-top-level2 (is (= "1" (reduce nth (limit 1) [0 0]))) (is (= "2" (reduce nth (limit 1 2) [0 1]))) (is (= "3" (reduce nth (limit 1 2 3) [0 2])))) (deftest lazy-child (is (coll? (reduce nth (limit 1 :<) [0 1 0]))) (is (= "2" (reduce nth (limit 1 :< 2) [0 1 0 0]))) (is (= "2" (reduce nth (limit 1 :< 2 :>) [0 1 0 0]))) (is (= "3" (reduce nth (limit 1 :< 2 :> 3) [0 2])))) (deftest lazy-end-of-tree (is (= 3 (count (first (limit 1 :< 2 :> 3 :>))))) (is (= 3 (count (first (limit 1 :< 2 :> 3 :> 4)))))) (deftest release-head-top (let [input (range 10) input-ref (WeakReference. input) output (doall (drop 5 (first (tt input))))] (System/gc) (is (= nil (.get input-ref))) output)) (deftest release-head-nested-late (let [input (list 1 2 :< 3 4 5 :>) input-ref (WeakReference. input) output (doall (drop 2 (first (tt input))))] (System/gc) (is (= nil (.get input-ref))) output)) data.xml-data.xml-0.2.0-alpha6/src/test/clojure/clojure/data/xml/test_sexp.clj000066400000000000000000000054751337626463000272220ustar00rootroot00000000000000; Copyright (c) Rich Hickey. All rights reserved. ; The use and distribution terms for this software are covered by the ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ; which can be found in the file epl-v10.html at the root of this distribution. ; By using this software in any fashion, you are agreeing to be bound by ; the terms of this license. ; You must not remove this notice, or any other, from this software. (ns ^{:doc "Tests for reading [:tag {:attr 'value} body*] as XML." :author "Alan Malloy"} clojure.data.xml.test-sexp (:require [clojure.test :refer :all] [clojure.data.xml :refer :all] [clojure.data.xml.test-utils :refer (test-stream lazy-parse*)])) (deftest as-element (let [xml-input "" sexp-input [:tag {:attr "value"} :body]] (is (= (lazy-parse* xml-input) (sexp-as-element sexp-input))))) (deftest as-fragment (let [input (list [:tag1 "stuff"] [:tag2 "other"])] (is (= (sexps-as-fragment input) (map sexp-as-element input))) (is (thrown? Exception (sexp-as-element input))))) (deftest with-cdata (let [xml-input (element :tag {:attr "value"} (element :body {} (cdata "not parsed " (let [xml-input (element :tag {:attr "value"} (element :body {} (cdata "not parsed more not parsed more not parsed ")) (xml/element-data (xml/element-node (xml/element :foo))) ) (deftest roundtrips (are [dxml xml] (do (is (= dxml (xml/parse-str xml))) (is (= dxml (xml/parse-str (xml/emit-str dxml))))) (xml/element :foo) "" (xml/element :xmlns.DAV%3A/foo) "" (xml/element :foo {} (xml/cdata "" (xml/element :foo {} (xml/xml-comment " bar> ")) "")) (deftest printing (are [node ps] (is (= ps (pr-str node))) (xml/element :foo) "#xml/element{:tag :foo}" (xml/element :foo {:a "2"}) "#xml/element{:tag :foo, :attrs {:a \"2\"}}" (xml/element :foo {} (xml/element :bar)) "#xml/element{:tag :foo, :content [#xml/element{:tag :bar}]}" (xml/element :foo {} "bar") "#xml/element{:tag :foo, :content [\"bar\"]}")) data.xml-data.xml-0.2.0-alpha6/src/test/clojurescript/clojure/data/xml/test_cljs_extended.cljs000066400000000000000000000040771337626463000324630ustar00rootroot00000000000000(ns clojure.data.xml.test-cljs-extended (:require [cljs.test :as test :refer [deftest is are]] [clojure.data.xml :as xml :refer [parse-str emit-str element element-data element-node]] [clojure.data.xml.node :as node] [clojure.data.xml.js.dom :as dom])) (comment (= (xml/element :foo) (xml/element-node (xml/element :foo))) (= (xml/element-node (xml/element :foo)) (xml/element :foo)) (= (xml/element-node (xml/element :foo)) {:tag :foo :attrs {} :content []}) (= {:tag :foo :attrs {} :content []} (xml/element-node (xml/element :foo))) (= {:lala "1" :oo "a"} (:attrs (xml/element-node (xml/element :foo {:lala "1" :oo "a"})))) (= {} (:attrs (xml/element-node (xml/element :foo)))) (= ["a"] (:content (xml/element-node (xml/element :foo {} "a")))) (= (xml/element :foo {} "a") (xml/element-node (xml/element :foo {} "a"))) (= (xml/element :foo {} "a") {:tag :foo :attrs {} :content ["a"]}) (= (xml/element :foo {} "a") (xml/element :foo {} "a")) (= () []) ( (:content (xml/element-node (xml/element :foo)))) (= ["a"] (dom/node-list ["a"])) (= [] (dom/node-list [])) PersistentArrayMap PersistentVector (xml/emit-str (xml/element "{DAV:}name" {})) (xml/parse-str "") (meta (xml/parse-str "")) (= (element-node (xml/element :xmlns.DAV%3A/foo)) (xml/parse-str "" :raw true) ) (.log js/console (element-node (xml/element :xmlns.DAV%3A/foo))) (xml/emit-str (element-node (xml/element :xmlns.DAV%3A/foo))) (xml/emit-str (xml/parse-str "" :raw true)) ) (deftest extended-equalities (are [dxml xml] (do (is (= dxml (xml/parse-str xml :raw true))) (is (= (element-node dxml) (xml/parse-str (xml/emit-str dxml)))) (is (= (element-node dxml) (xml/parse-str xml :raw true))) (is (= (element-node dxml) (xml/parse-str (xml/emit-str dxml) :raw true)))) (xml/element :foo) "" (xml/element :xmlns.DAV%3A/foo) "")) data.xml-data.xml-0.2.0-alpha6/src/test/resources/000077500000000000000000000000001337626463000216725ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/test/resources/clojure/000077500000000000000000000000001337626463000233355ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/test/resources/clojure/data/000077500000000000000000000000001337626463000242465ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/test/resources/clojure/data/xml/000077500000000000000000000000001337626463000250465ustar00rootroot00000000000000data.xml-data.xml-0.2.0-alpha6/src/test/resources/clojure/data/xml/cljs_testsuite.clj000066400000000000000000000033621337626463000306100ustar00rootroot00000000000000(ns clojure.data.xml.cljs-testsuite (:require [clojure.test :refer :all] [cljs.repl :as repl] [cljs.repl.nashorn :as repl-nh] [cljs.closure :as closure] [cljs.build.api :as bapi] [clojure.string :as str] [clojure.java.io :as io]) (:import java.nio.file.Files java.nio.file.attribute.FileAttribute)) (defn tempdir [] (str (Files/createTempDirectory "cljs-nashorn-" (into-array FileAttribute [])))) (defn compile-testsuite! [dir] (let [out (io/file dir "tests.js") inputs ["src/main/clojure" "src/test/clojure" "src/test/clojurescript"]] (println "INFO" "Compiling cljs testsuite from" inputs "into" (str out)) (bapi/build (apply bapi/inputs inputs) {:output-to (str out) :output-dir dir :main 'clojure.data.xml.test-cljs :optimizations :advanced :pseudo-names true :pretty-print true :preamble ["dxml-nashorn.generated.js"]}))) (defn run-testsuite! [dir] (System/setProperty "nashorn.persistent.code.cache" "target/nashorn_code_cache") (let [engine (repl-nh/create-engine)] (compile-testsuite! dir) (println "INFO" "Running cljs tests in nashorn with persistent code cache in" (System/getProperty "nashorn.persistent.code.cache")) (.eval engine (io/reader (io/file dir "tests.js"))) (let [{:as res :keys [fail error]} (read-string (.eval engine "clojure.data.xml.test_cljs._main_nashorn()"))] (is (and (zero? fail) (zero? error)) (pr-str res))))) (comment (def td (tempdir)) (def engine (:engine (repl-nh/repl-env))) (run-testsuite! td) (.eval engine (io/reader (io/file td "tests.reopt.js"))) (.eval engine "clojure.data.xml.test_cljs._main()") ) data.xml-data.xml-0.2.0-alpha6/src/test/resources/dxml-nashorn.generated.js000066400000000000000000001776541337626463000266230ustar00rootroot00000000000000/******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.l = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // identity function for calling harmory imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ // define getter function for harmory exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ }; /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 4); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports) { /* * DOM Level 2 * Object DOMException * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html */ function copy(src,dest){ for(var p in src){ dest[p] = src[p]; } } /** ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));? ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));? */ function _extends(Class,Super){ var pt = Class.prototype; if(Object.create){ var ppt = Object.create(Super.prototype) pt.__proto__ = ppt; } if(!(pt instanceof Super)){ function t(){}; t.prototype = Super.prototype; t = new t(); copy(pt,t); Class.prototype = pt = t; } if(pt.constructor != Class){ if(typeof Class != 'function'){ console.error("unknow Class:"+Class) } pt.constructor = Class } } var htmlns = 'http://www.w3.org/1999/xhtml' ; // Node Types var NodeType = {} var ELEMENT_NODE = NodeType.ELEMENT_NODE = 1; var ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2; var TEXT_NODE = NodeType.TEXT_NODE = 3; var CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4; var ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5; var ENTITY_NODE = NodeType.ENTITY_NODE = 6; var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7; var COMMENT_NODE = NodeType.COMMENT_NODE = 8; var DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9; var DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10; var DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11; var NOTATION_NODE = NodeType.NOTATION_NODE = 12; // ExceptionCode var ExceptionCode = {} var ExceptionMessage = {}; var INDEX_SIZE_ERR = ExceptionCode.INDEX_SIZE_ERR = ((ExceptionMessage[1]="Index size error"),1); var DOMSTRING_SIZE_ERR = ExceptionCode.DOMSTRING_SIZE_ERR = ((ExceptionMessage[2]="DOMString size error"),2); var HIERARCHY_REQUEST_ERR = ExceptionCode.HIERARCHY_REQUEST_ERR = ((ExceptionMessage[3]="Hierarchy request error"),3); var WRONG_DOCUMENT_ERR = ExceptionCode.WRONG_DOCUMENT_ERR = ((ExceptionMessage[4]="Wrong document"),4); var INVALID_CHARACTER_ERR = ExceptionCode.INVALID_CHARACTER_ERR = ((ExceptionMessage[5]="Invalid character"),5); var NO_DATA_ALLOWED_ERR = ExceptionCode.NO_DATA_ALLOWED_ERR = ((ExceptionMessage[6]="No data allowed"),6); var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]="No modification allowed"),7); var NOT_FOUND_ERR = ExceptionCode.NOT_FOUND_ERR = ((ExceptionMessage[8]="Not found"),8); var NOT_SUPPORTED_ERR = ExceptionCode.NOT_SUPPORTED_ERR = ((ExceptionMessage[9]="Not supported"),9); var INUSE_ATTRIBUTE_ERR = ExceptionCode.INUSE_ATTRIBUTE_ERR = ((ExceptionMessage[10]="Attribute in use"),10); //level2 var INVALID_STATE_ERR = ExceptionCode.INVALID_STATE_ERR = ((ExceptionMessage[11]="Invalid state"),11); var SYNTAX_ERR = ExceptionCode.SYNTAX_ERR = ((ExceptionMessage[12]="Syntax error"),12); var INVALID_MODIFICATION_ERR = ExceptionCode.INVALID_MODIFICATION_ERR = ((ExceptionMessage[13]="Invalid modification"),13); var NAMESPACE_ERR = ExceptionCode.NAMESPACE_ERR = ((ExceptionMessage[14]="Invalid namespace"),14); var INVALID_ACCESS_ERR = ExceptionCode.INVALID_ACCESS_ERR = ((ExceptionMessage[15]="Invalid access"),15); function DOMException(code, message) { if(message instanceof Error){ var error = message; }else{ error = this; Error.call(this, ExceptionMessage[code]); this.message = ExceptionMessage[code]; if(Error.captureStackTrace) Error.captureStackTrace(this, DOMException); } error.code = code; if(message) this.message = this.message + ": " + message; return error; }; DOMException.prototype = Error.prototype; copy(ExceptionCode,DOMException) /** * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177 * The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live. * The items in the NodeList are accessible via an integral index, starting from 0. */ function NodeList() { }; NodeList.prototype = { /** * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive. * @standard level1 */ length:0, /** * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null. * @standard level1 * @param index unsigned long * Index into the collection. * @return Node * The node at the indexth position in the NodeList, or null if that is not a valid index. */ item: function(index) { return this[index] || null; }, toString:function(isHTML,nodeFilter){ for(var buf = [], i = 0;i=0){ var lastIndex = list.length-1 while(i0 || key == 'xmlns'){ // return null; // } //console.log() var i = this.length; while(i--){ var attr = this[i]; //console.log(attr.nodeName,key) if(attr.nodeName == key){ return attr; } } }, setNamedItem: function(attr) { var el = attr.ownerElement; if(el && el!=this._ownerElement){ throw new DOMException(INUSE_ATTRIBUTE_ERR); } var oldAttr = this.getNamedItem(attr.nodeName); _addNamedNode(this._ownerElement,this,attr,oldAttr); return oldAttr; }, /* returns Node */ setNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR var el = attr.ownerElement, oldAttr; if(el && el!=this._ownerElement){ throw new DOMException(INUSE_ATTRIBUTE_ERR); } oldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName); _addNamedNode(this._ownerElement,this,attr,oldAttr); return oldAttr; }, /* returns Node */ removeNamedItem: function(key) { var attr = this.getNamedItem(key); _removeNamedNode(this._ownerElement,this,attr); return attr; },// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR //for level2 removeNamedItemNS:function(namespaceURI,localName){ var attr = this.getNamedItemNS(namespaceURI,localName); _removeNamedNode(this._ownerElement,this,attr); return attr; }, getNamedItemNS: function(namespaceURI, localName) { var i = this.length; while(i--){ var node = this[i]; if(node.localName == localName && node.namespaceURI == namespaceURI){ return node; } } return null; } }; /** * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490 */ function DOMImplementation(/* Object */ features) { this._features = {}; if (features) { for (var feature in features) { this._features = features[feature]; } } }; DOMImplementation.prototype = { hasFeature: function(/* string */ feature, /* string */ version) { var versions = this._features[feature.toLowerCase()]; if (versions && (!version || version in versions)) { return true; } else { return false; } }, // Introduced in DOM Level 2: createDocument:function(namespaceURI, qualifiedName, doctype){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR var doc = new Document(); doc.implementation = this; doc.childNodes = new NodeList(); doc.doctype = doctype; if(doctype){ doc.appendChild(doctype); } if(qualifiedName){ var root = doc.createElementNS(namespaceURI,qualifiedName); doc.appendChild(root); } return doc; }, // Introduced in DOM Level 2: createDocumentType:function(qualifiedName, publicId, systemId){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR var node = new DocumentType(); node.name = qualifiedName; node.nodeName = qualifiedName; node.publicId = publicId; node.systemId = systemId; // Introduced in DOM Level 2: //readonly attribute DOMString internalSubset; //TODO:.. // readonly attribute NamedNodeMap entities; // readonly attribute NamedNodeMap notations; return node; } }; /** * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247 */ function Node() { }; Node.prototype = { firstChild : null, lastChild : null, previousSibling : null, nextSibling : null, attributes : null, parentNode : null, childNodes : null, ownerDocument : null, nodeValue : null, namespaceURI : null, prefix : null, localName : null, // Modified in DOM Level 2: insertBefore:function(newChild, refChild){//raises return _insertBefore(this,newChild,refChild); }, replaceChild:function(newChild, oldChild){//raises this.insertBefore(newChild,oldChild); if(oldChild){ this.removeChild(oldChild); } }, removeChild:function(oldChild){ return _removeChild(this,oldChild); }, appendChild:function(newChild){ return this.insertBefore(newChild,null); }, hasChildNodes:function(){ return this.firstChild != null; }, cloneNode:function(deep){ return cloneNode(this.ownerDocument||this,this,deep); }, // Modified in DOM Level 2: normalize:function(){ var child = this.firstChild; while(child){ var next = child.nextSibling; if(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){ this.removeChild(next); child.appendData(next.data); }else{ child.normalize(); child = next; } } }, // Introduced in DOM Level 2: isSupported:function(feature, version){ return this.ownerDocument.implementation.hasFeature(feature,version); }, // Introduced in DOM Level 2: hasAttributes:function(){ return this.attributes.length>0; }, lookupPrefix:function(namespaceURI){ var el = this; while(el){ var map = el._nsMap; //console.dir(map) if(map){ for(var n in map){ if(map[n] == namespaceURI){ return n; } } } el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode; } return null; }, // Introduced in DOM Level 3: lookupNamespaceURI:function(prefix){ var el = this; while(el){ var map = el._nsMap; //console.dir(map) if(map){ if(prefix in map){ return map[prefix] ; } } el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode; } return null; }, // Introduced in DOM Level 3: isDefaultNamespace:function(namespaceURI){ var prefix = this.lookupPrefix(namespaceURI); return prefix == null; } }; function _xmlEncoder(c){ return c == '<' && '<' || c == '>' && '>' || c == '&' && '&' || c == '"' && '"' || '&#'+c.charCodeAt()+';' } copy(NodeType,Node); copy(NodeType,Node.prototype); /** * @param callback return true for continue,false for break * @return boolean true: break visit; */ function _visitNode(node,callback){ if(callback(node)){ return true; } if(node = node.firstChild){ do{ if(_visitNode(node,callback)){return true} }while(node=node.nextSibling) } } function Document(){ } function _onAddAttribute(doc,el,newAttr){ doc && doc._inc++; var ns = newAttr.namespaceURI ; if(ns == 'http://www.w3.org/2000/xmlns/'){ //update namespace el._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value } } function _onRemoveAttribute(doc,el,newAttr,remove){ doc && doc._inc++; var ns = newAttr.namespaceURI ; if(ns == 'http://www.w3.org/2000/xmlns/'){ //update namespace delete el._nsMap[newAttr.prefix?newAttr.localName:''] } } function _onUpdateChild(doc,el,newChild){ if(doc && doc._inc){ doc._inc++; //update childNodes var cs = el.childNodes; if(newChild){ cs[cs.length++] = newChild; }else{ //console.log(1) var child = el.firstChild; var i = 0; while(child){ cs[i++] = child; child =child.nextSibling; } cs.length = i; } } } /** * attributes; * children; * * writeable properties: * nodeValue,Attr:value,CharacterData:data * prefix */ function _removeChild(parentNode,child){ var previous = child.previousSibling; var next = child.nextSibling; if(previous){ previous.nextSibling = next; }else{ parentNode.firstChild = next } if(next){ next.previousSibling = previous; }else{ parentNode.lastChild = previous; } _onUpdateChild(parentNode.ownerDocument,parentNode); return child; } /** * preformance key(refChild == null) */ function _insertBefore(parentNode,newChild,nextChild){ var cp = newChild.parentNode; if(cp){ cp.removeChild(newChild);//remove and update } if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){ var newFirst = newChild.firstChild; if (newFirst == null) { return newChild; } var newLast = newChild.lastChild; }else{ newFirst = newLast = newChild; } var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild; newFirst.previousSibling = pre; newLast.nextSibling = nextChild; if(pre){ pre.nextSibling = newFirst; }else{ parentNode.firstChild = newFirst; } if(nextChild == null){ parentNode.lastChild = newLast; }else{ nextChild.previousSibling = newLast; } do{ newFirst.parentNode = parentNode; }while(newFirst !== newLast && (newFirst= newFirst.nextSibling)) _onUpdateChild(parentNode.ownerDocument||parentNode,parentNode); //console.log(parentNode.lastChild.nextSibling == null) if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) { newChild.firstChild = newChild.lastChild = null; } return newChild; } function _appendSingleChild(parentNode,newChild){ var cp = newChild.parentNode; if(cp){ var pre = parentNode.lastChild; cp.removeChild(newChild);//remove and update var pre = parentNode.lastChild; } var pre = parentNode.lastChild; newChild.parentNode = parentNode; newChild.previousSibling = pre; newChild.nextSibling = null; if(pre){ pre.nextSibling = newChild; }else{ parentNode.firstChild = newChild; } parentNode.lastChild = newChild; _onUpdateChild(parentNode.ownerDocument,parentNode,newChild); return newChild; //console.log("__aa",parentNode.lastChild.nextSibling == null) } Document.prototype = { //implementation : null, nodeName : '#document', nodeType : DOCUMENT_NODE, doctype : null, documentElement : null, _inc : 1, insertBefore : function(newChild, refChild){//raises if(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){ var child = newChild.firstChild; while(child){ var next = child.nextSibling; this.insertBefore(child,refChild); child = next; } return newChild; } if(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){ this.documentElement = newChild; } return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild; }, removeChild : function(oldChild){ if(this.documentElement == oldChild){ this.documentElement = null; } return _removeChild(this,oldChild); }, // Introduced in DOM Level 2: importNode : function(importedNode,deep){ return importNode(this,importedNode,deep); }, // Introduced in DOM Level 2: getElementById : function(id){ var rtv = null; _visitNode(this.documentElement,function(node){ if(node.nodeType == ELEMENT_NODE){ if(node.getAttribute('id') == id){ rtv = node; return true; } } }) return rtv; }, //document factory method: createElement : function(tagName){ var node = new Element(); node.ownerDocument = this; node.nodeName = tagName; node.tagName = tagName; node.childNodes = new NodeList(); var attrs = node.attributes = new NamedNodeMap(); attrs._ownerElement = node; return node; }, createDocumentFragment : function(){ var node = new DocumentFragment(); node.ownerDocument = this; node.childNodes = new NodeList(); return node; }, createTextNode : function(data){ var node = new Text(); node.ownerDocument = this; node.appendData(data) return node; }, createComment : function(data){ var node = new Comment(); node.ownerDocument = this; node.appendData(data) return node; }, createCDATASection : function(data){ var node = new CDATASection(); node.ownerDocument = this; node.appendData(data) return node; }, createProcessingInstruction : function(target,data){ var node = new ProcessingInstruction(); node.ownerDocument = this; node.tagName = node.target = target; node.nodeValue= node.data = data; return node; }, createAttribute : function(name){ var node = new Attr(); node.ownerDocument = this; node.name = name; node.nodeName = name; node.localName = name; node.specified = true; return node; }, createEntityReference : function(name){ var node = new EntityReference(); node.ownerDocument = this; node.nodeName = name; return node; }, // Introduced in DOM Level 2: createElementNS : function(namespaceURI,qualifiedName){ var node = new Element(); var pl = qualifiedName.split(':'); var attrs = node.attributes = new NamedNodeMap(); node.childNodes = new NodeList(); node.ownerDocument = this; node.nodeName = qualifiedName; node.tagName = qualifiedName; node.namespaceURI = namespaceURI; if(pl.length == 2){ node.prefix = pl[0]; node.localName = pl[1]; }else{ //el.prefix = null; node.localName = qualifiedName; } attrs._ownerElement = node; return node; }, // Introduced in DOM Level 2: createAttributeNS : function(namespaceURI,qualifiedName){ var node = new Attr(); var pl = qualifiedName.split(':'); node.ownerDocument = this; node.nodeName = qualifiedName; node.name = qualifiedName; node.namespaceURI = namespaceURI; node.specified = true; if(pl.length == 2){ node.prefix = pl[0]; node.localName = pl[1]; }else{ //el.prefix = null; node.localName = qualifiedName; } return node; } }; _extends(Document,Node); function Element() { this._nsMap = {}; }; Element.prototype = { nodeType : ELEMENT_NODE, hasAttribute : function(name){ return this.getAttributeNode(name)!=null; }, getAttribute : function(name){ var attr = this.getAttributeNode(name); return attr && attr.value || ''; }, getAttributeNode : function(name){ return this.attributes.getNamedItem(name); }, setAttribute : function(name, value){ var attr = this.ownerDocument.createAttribute(name); attr.value = attr.nodeValue = "" + value; this.setAttributeNode(attr) }, removeAttribute : function(name){ var attr = this.getAttributeNode(name) attr && this.removeAttributeNode(attr); }, //four real opeartion method appendChild:function(newChild){ if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){ return this.insertBefore(newChild,null); }else{ return _appendSingleChild(this,newChild); } }, setAttributeNode : function(newAttr){ return this.attributes.setNamedItem(newAttr); }, setAttributeNodeNS : function(newAttr){ return this.attributes.setNamedItemNS(newAttr); }, removeAttributeNode : function(oldAttr){ //console.log(this == oldAttr.ownerElement) return this.attributes.removeNamedItem(oldAttr.nodeName); }, //get real attribute name,and remove it by removeAttributeNode removeAttributeNS : function(namespaceURI, localName){ var old = this.getAttributeNodeNS(namespaceURI, localName); old && this.removeAttributeNode(old); }, hasAttributeNS : function(namespaceURI, localName){ return this.getAttributeNodeNS(namespaceURI, localName)!=null; }, getAttributeNS : function(namespaceURI, localName){ var attr = this.getAttributeNodeNS(namespaceURI, localName); return attr && attr.value || ''; }, setAttributeNS : function(namespaceURI, qualifiedName, value){ var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName); attr.value = attr.nodeValue = "" + value; this.setAttributeNode(attr) }, getAttributeNodeNS : function(namespaceURI, localName){ return this.attributes.getNamedItemNS(namespaceURI, localName); }, getElementsByTagName : function(tagName){ return new LiveNodeList(this,function(base){ var ls = []; _visitNode(base,function(node){ if(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){ ls.push(node); } }); return ls; }); }, getElementsByTagNameNS : function(namespaceURI, localName){ return new LiveNodeList(this,function(base){ var ls = []; _visitNode(base,function(node){ if(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){ ls.push(node); } }); return ls; }); } }; Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName; Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS; _extends(Element,Node); function Attr() { }; Attr.prototype.nodeType = ATTRIBUTE_NODE; _extends(Attr,Node); function CharacterData() { }; CharacterData.prototype = { data : '', substringData : function(offset, count) { return this.data.substring(offset, offset+count); }, appendData: function(text) { text = this.data+text; this.nodeValue = this.data = text; this.length = text.length; }, insertData: function(offset,text) { this.replaceData(offset,0,text); }, appendChild:function(newChild){ throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR]) }, deleteData: function(offset, count) { this.replaceData(offset,count,""); }, replaceData: function(offset, count, text) { var start = this.data.substring(0,offset); var end = this.data.substring(offset+count); text = start + text + end; this.nodeValue = this.data = text; this.length = text.length; } } _extends(CharacterData,Node); function Text() { }; Text.prototype = { nodeName : "#text", nodeType : TEXT_NODE, splitText : function(offset) { var text = this.data; var newText = text.substring(offset); text = text.substring(0, offset); this.data = this.nodeValue = text; this.length = text.length; var newNode = this.ownerDocument.createTextNode(newText); if(this.parentNode){ this.parentNode.insertBefore(newNode, this.nextSibling); } return newNode; } } _extends(Text,CharacterData); function Comment() { }; Comment.prototype = { nodeName : "#comment", nodeType : COMMENT_NODE } _extends(Comment,CharacterData); function CDATASection() { }; CDATASection.prototype = { nodeName : "#cdata-section", nodeType : CDATA_SECTION_NODE } _extends(CDATASection,CharacterData); function DocumentType() { }; DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE; _extends(DocumentType,Node); function Notation() { }; Notation.prototype.nodeType = NOTATION_NODE; _extends(Notation,Node); function Entity() { }; Entity.prototype.nodeType = ENTITY_NODE; _extends(Entity,Node); function EntityReference() { }; EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE; _extends(EntityReference,Node); function DocumentFragment() { }; DocumentFragment.prototype.nodeName = "#document-fragment"; DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE; _extends(DocumentFragment,Node); function ProcessingInstruction() { } ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE; _extends(ProcessingInstruction,Node); function XMLSerializer(){} XMLSerializer.prototype.serializeToString = function(node,isHtml,nodeFilter){ return nodeSerializeToString.call(node,isHtml,nodeFilter); } Node.prototype.toString = nodeSerializeToString; function nodeSerializeToString(isHtml,nodeFilter){ var buf = []; var refNode = this.nodeType == 9?this.documentElement:this; var prefix = refNode.prefix; var uri = refNode.namespaceURI; if(uri && prefix == null){ //console.log(prefix) var prefix = refNode.lookupPrefix(uri); if(prefix == null){ //isHTML = true; var visibleNamespaces=[ {namespace:uri,prefix:null} //{namespace:uri,prefix:''} ] } } serializeToString(this,buf,isHtml,nodeFilter,visibleNamespaces); //console.log('###',this.nodeType,uri,prefix,buf.join('')) return buf.join(''); } function needNamespaceDefine(node,isHTML, visibleNamespaces) { var prefix = node.prefix||''; var uri = node.namespaceURI; if (!prefix && !uri){ return false; } if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" || uri == 'http://www.w3.org/2000/xmlns/'){ return false; } var i = visibleNamespaces.length //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces) while (i--) { var ns = visibleNamespaces[i]; // get namespace prefix //console.log(node.nodeType,node.tagName,ns.prefix,prefix) if (ns.prefix == prefix){ return ns.namespace != uri; } } //console.log(isHTML,uri,prefix=='') //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){ // return false; //} //node.flag = '11111' //console.error(3,true,node.flag,node.prefix,node.namespaceURI) return true; } function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){ if(nodeFilter){ node = nodeFilter(node); if(node){ if(typeof node == 'string'){ buf.push(node); return; } }else{ return; } //buf.sort.apply(attrs, attributeSorter); } switch(node.nodeType){ case ELEMENT_NODE: if (!visibleNamespaces) visibleNamespaces = []; var startVisibleNamespaces = visibleNamespaces.length; var attrs = node.attributes; var len = attrs.length; var child = node.firstChild; var nodeName = node.tagName; isHTML = (htmlns === node.namespaceURI) ||isHTML buf.push('<',nodeName); for(var i=0;i'); //if is cdata child node if(isHTML && /^script$/i.test(nodeName)){ while(child){ if(child.data){ buf.push(child.data); }else{ serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces); } child = child.nextSibling; } }else { while(child){ serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces); child = child.nextSibling; } } buf.push(''); }else{ buf.push('/>'); } // remove added visible namespaces //visibleNamespaces.length = startVisibleNamespaces; return; case DOCUMENT_NODE: case DOCUMENT_FRAGMENT_NODE: var child = node.firstChild; while(child){ serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces); child = child.nextSibling; } return; case ATTRIBUTE_NODE: return buf.push(' ',node.name,'="',node.value.replace(/[<&"]/g,_xmlEncoder),'"'); case TEXT_NODE: return buf.push(node.data.replace(/[<&]/g,_xmlEncoder)); case CDATA_SECTION_NODE: return buf.push( ''); case COMMENT_NODE: return buf.push( ""); case DOCUMENT_TYPE_NODE: var pubid = node.publicId; var sysid = node.systemId; buf.push(''); }else if(sysid && sysid!='.'){ buf.push(' SYSTEM "',sysid,'">'); }else{ var sub = node.internalSubset; if(sub){ buf.push(" [",sub,"]"); } buf.push(">"); } return; case PROCESSING_INSTRUCTION_NODE: return buf.push( ""); case ENTITY_REFERENCE_NODE: return buf.push( '&',node.nodeName,';'); //case ENTITY_NODE: //case NOTATION_NODE: default: buf.push('??',node.nodeName); } } function importNode(doc,node,deep){ var node2; switch (node.nodeType) { case ELEMENT_NODE: node2 = node.cloneNode(false); node2.ownerDocument = doc; //var attrs = node2.attributes; //var len = attrs.length; //for(var i=0;i','amp':'&','quot':'"','apos':"'"} if(locator){ domBuilder.setDocumentLocator(locator) } sax.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator); sax.domBuilder = options.domBuilder || domBuilder; if(/\/x?html?$/.test(mimeType)){ entityMap.nbsp = '\xa0'; entityMap.copy = '\xa9'; defaultNSMap['']= 'http://www.w3.org/1999/xhtml'; } defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace'; if(source){ sax.parse(source,defaultNSMap,entityMap); }else{ sax.errorHandler.error("invalid doc source"); } return domBuilder.doc; } function buildErrorHandler(errorImpl,domBuilder,locator){ if(!errorImpl){ if(domBuilder instanceof DOMHandler){ return domBuilder; } errorImpl = domBuilder ; } var errorHandler = {} var isCallback = errorImpl instanceof Function; locator = locator||{} function build(key){ var fn = errorImpl[key]; if(!fn && isCallback){ fn = errorImpl.length == 2?function(msg){errorImpl(key,msg)}:errorImpl; } errorHandler[key] = fn && function(msg){ fn('[xmldom '+key+']\t'+msg+_locator(locator)); }||function(){}; } build('warning'); build('error'); build('fatalError'); return errorHandler; } //console.log('#\n\n\n\n\n\n\n####') /** * +ContentHandler+ErrorHandler * +LexicalHandler+EntityResolver2 * -DeclHandler-DTDHandler * * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2 * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html */ function DOMHandler() { this.cdata = false; } function position(locator,node){ node.lineNumber = locator.lineNumber; node.columnNumber = locator.columnNumber; } /** * @see org.xml.sax.ContentHandler#startDocument * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html */ DOMHandler.prototype = { startDocument : function() { this.doc = new DOMImplementation().createDocument(null, null, null); if (this.locator) { this.doc.documentURI = this.locator.systemId; } }, startElement:function(namespaceURI, localName, qName, attrs) { var doc = this.doc; var el = doc.createElementNS(namespaceURI, qName||localName); var len = attrs.length; appendElement(this, el); this.currentElement = el; this.locator && position(this.locator,el) for (var i = 0 ; i < len; i++) { var namespaceURI = attrs.getURI(i); var value = attrs.getValue(i); var qName = attrs.getQName(i); var attr = doc.createAttributeNS(namespaceURI, qName); this.locator &&position(attrs.getLocator(i),attr); attr.value = attr.nodeValue = value; el.setAttributeNode(attr) } }, endElement:function(namespaceURI, localName, qName) { var current = this.currentElement var tagName = current.tagName; this.currentElement = current.parentNode; }, startPrefixMapping:function(prefix, uri) { }, endPrefixMapping:function(prefix) { }, processingInstruction:function(target, data) { var ins = this.doc.createProcessingInstruction(target, data); this.locator && position(this.locator,ins) appendElement(this, ins); }, ignorableWhitespace:function(ch, start, length) { }, characters:function(chars, start, length) { chars = _toString.apply(this,arguments) //console.log(chars) if(chars){ if (this.cdata) { var charNode = this.doc.createCDATASection(chars); } else { var charNode = this.doc.createTextNode(chars); } if(this.currentElement){ this.currentElement.appendChild(charNode); }else if(/^\s*$/.test(chars)){ this.doc.appendChild(charNode); //process xml } this.locator && position(this.locator,charNode) } }, skippedEntity:function(name) { }, endDocument:function() { this.doc.normalize(); }, setDocumentLocator:function (locator) { if(this.locator = locator){// && !('lineNumber' in locator)){ locator.lineNumber = 0; } }, //LexicalHandler comment:function(chars, start, length) { chars = _toString.apply(this,arguments) var comm = this.doc.createComment(chars); this.locator && position(this.locator,comm) appendElement(this, comm); }, startCDATA:function() { //used in characters() methods this.cdata = true; }, endCDATA:function() { this.cdata = false; }, startDTD:function(name, publicId, systemId) { var impl = this.doc.implementation; if (impl && impl.createDocumentType) { var dt = impl.createDocumentType(name, publicId, systemId); this.locator && position(this.locator,dt) appendElement(this, dt); } }, /** * @see org.xml.sax.ErrorHandler * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html */ warning:function(error) { console.warn('[xmldom warning]\t'+error,_locator(this.locator)); }, error:function(error) { console.error('[xmldom error]\t'+error,_locator(this.locator)); }, fatalError:function(error) { console.error('[xmldom fatalError]\t'+error,_locator(this.locator)); throw error; } } function _locator(l){ if(l){ return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']' } } function _toString(chars,start,length){ if(typeof chars == 'string'){ return chars.substr(start,length) }else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)") if(chars.length >= start+length || start){ return new java.lang.String(chars,start,length)+''; } return chars; } } /* * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html * used method of org.xml.sax.ext.LexicalHandler: * #comment(chars, start, length) * #startCDATA() * #endCDATA() * #startDTD(name, publicId, systemId) * * * IGNORED method of org.xml.sax.ext.LexicalHandler: * #endDTD() * #startEntity(name) * #endEntity(name) * * * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html * IGNORED method of org.xml.sax.ext.DeclHandler * #attributeDecl(eName, aName, type, mode, value) * #elementDecl(name, model) * #externalEntityDecl(name, publicId, systemId) * #internalEntityDecl(name, value) * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html * IGNORED method of org.xml.sax.EntityResolver2 * #resolveEntity(String name,String publicId,String baseURI,String systemId) * #resolveEntity(publicId, systemId) * #getExternalSubset(name, baseURI) * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html * IGNORED method of org.xml.sax.DTDHandler * #notationDecl(name, publicId, systemId) {}; * #unparsedEntityDecl(name, publicId, systemId, notationName) {}; */ "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){ DOMHandler.prototype[key] = function(){return null} }) /* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */ function appendElement (hander,node) { if (!hander.currentElement) { hander.doc.appendChild(node); } else { hander.currentElement.appendChild(node); } }//appendChild and setAttributeNS are preformance key //if(typeof require == 'function'){ var XMLReader = __webpack_require__(3).XMLReader; var DOMImplementation = exports.DOMImplementation = __webpack_require__(0).DOMImplementation; exports.XMLSerializer = __webpack_require__(0).XMLSerializer ; exports.DOMParser = DOMParser; //} /***/ }, /* 3 */ /***/ function(module, exports) { //[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] //[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040] //[5] Name ::= NameStartChar (NameChar)* var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]///\u10000-\uEFFFF var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]"); var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$'); //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/ //var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',') //S_TAG, S_ATTR, S_EQ, S_ATTR_NOQUOT_VALUE //S_ATTR_SPACE, S_ATTR_END, S_TAG_SPACE, S_TAG_CLOSE var S_TAG = 0;//tag name offerring var S_ATTR = 1;//attr name offerring var S_ATTR_SPACE=2;//attr name end and space offer var S_EQ = 3;//=space? var S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only) var S_ATTR_END = 5;//attr value end and no space(quot end) var S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer) var S_TAG_CLOSE = 7;//closed el function XMLReader(){ } XMLReader.prototype = { parse:function(source,defaultNSMap,entityMap){ var domBuilder = this.domBuilder; domBuilder.startDocument(); _copy(defaultNSMap ,defaultNSMap = {}) parse(source,defaultNSMap,entityMap, domBuilder,this.errorHandler); domBuilder.endDocument(); } } function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){ function fixedFromCharCode(code) { // String.prototype.fromCharCode does not supports // > 2 bytes unicode chars directly if (code > 0xffff) { code -= 0x10000; var surrogate1 = 0xd800 + (code >> 10) , surrogate2 = 0xdc00 + (code & 0x3ff); return String.fromCharCode(surrogate1, surrogate2); } else { return String.fromCharCode(code); } } function entityReplacer(a){ var k = a.slice(1,-1); if(k in entityMap){ return entityMap[k]; }else if(k.charAt(0) === '#'){ return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x'))) }else{ errorHandler.error('entity not found:'+a); return a; } } function appendText(end){//has some bugs if(end>start){ var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer); locator&&position(start); domBuilder.characters(xt,0,end-start); start = end } } function position(p,m){ while(p>=lineEnd && (m = linePattern.exec(source))){ lineStart = m.index; lineEnd = lineStart + m[0].length; locator.lineNumber++; //console.log('line++:',locator,startPos,endPos) } locator.columnNumber = p-lineStart+1; } var lineStart = 0; var lineEnd = 0; var linePattern = /.*(?:\r\n?|\n)|.*$/g var locator = domBuilder.locator; var parseStack = [{currentNSMap:defaultNSMapCopy}] var closeMap = {}; var start = 0; while(true){ try{ var tagStart = source.indexOf('<',start); if(tagStart<0){ if(!source.substr(start).match(/^\s*$/)){ var doc = domBuilder.doc; var text = doc.createTextNode(source.substr(start)); doc.appendChild(text); domBuilder.currentElement = text; } return; } if(tagStart>start){ appendText(tagStart); } switch(source.charAt(tagStart+1)){ case '/': var end = source.indexOf('>',tagStart+3); var tagName = source.substring(tagStart+2,end); var config = parseStack.pop(); if(end<0){ tagName = source.substring(tagStart+2).replace(/[\s<].*/,''); //console.error('#@@@@@@'+tagName) errorHandler.error("end tag name: "+tagName+' is not complete:'+config.tagName); end = tagStart+1+tagName.length; }else if(tagName.match(/\s locator&&position(tagStart); end = parseInstruction(source,tagStart,domBuilder); break; case '!':// start){ start = end; }else{ //TODO: 这里有可能sax回退,有位置错误风险 appendText(Math.max(tagStart,start)+1); } } } function copyLocator(f,t){ t.lineNumber = f.lineNumber; t.columnNumber = f.columnNumber; return t; } /** * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack); * @return end of the elementStartPart(end of elementEndPart for selfClosed el) */ function parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){ var attrName; var value; var p = ++start; var s = S_TAG;//status while(true){ var c = source.charAt(p); switch(c){ case '=': if(s === S_ATTR){//attrName attrName = source.slice(start,p); s = S_EQ; }else if(s === S_ATTR_SPACE){ s = S_EQ; }else{ //fatalError: equal must after attrName or space after attrName throw new Error('attribute equal must after attrName'); } break; case '\'': case '"': if(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE ){//equal if(s === S_ATTR){ errorHandler.warning('attribute value must after "="') attrName = source.slice(start,p) } start = p+1; p = source.indexOf(c,start) if(p>0){ value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer); el.add(attrName,value,start-1); s = S_ATTR_END; }else{ //fatalError: no end quot match throw new Error('attribute value no end \''+c+'\' match'); } }else if(s == S_ATTR_NOQUOT_VALUE){ value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer); //console.log(attrName,value,start,p) el.add(attrName,value,start); //console.dir(el) errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!'); start = p+1; s = S_ATTR_END }else{ //fatalError: no equal before throw new Error('attribute value must after "="'); } break; case '/': switch(s){ case S_TAG: el.setTagName(source.slice(start,p)); case S_ATTR_END: case S_TAG_SPACE: case S_TAG_CLOSE: s =S_TAG_CLOSE; el.closed = true; case S_ATTR_NOQUOT_VALUE: case S_ATTR: case S_ATTR_SPACE: break; //case S_EQ: default: throw new Error("attribute invalid close char('/')") } break; case ''://end document //throw new Error('unexpected end of input') errorHandler.error('unexpected end of input'); if(s == S_TAG){ el.setTagName(source.slice(start,p)); } return p; case '>': switch(s){ case S_TAG: el.setTagName(source.slice(start,p)); case S_ATTR_END: case S_TAG_SPACE: case S_TAG_CLOSE: break;//normal case S_ATTR_NOQUOT_VALUE://Compatible state case S_ATTR: value = source.slice(start,p); if(value.slice(-1) === '/'){ el.closed = true; value = value.slice(0,-1) } case S_ATTR_SPACE: if(s === S_ATTR_SPACE){ value = attrName; } if(s == S_ATTR_NOQUOT_VALUE){ errorHandler.warning('attribute "'+value+'" missed quot(")!!'); el.add(attrName,value.replace(/&#?\w+;/g,entityReplacer),start) }else{ if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)){ errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!') } el.add(value,value,start) } break; case S_EQ: throw new Error('attribute value missed!!'); } // console.log(tagName,tagNamePattern,tagNamePattern.test(tagName)) return p; /*xml space '\x20' | #x9 | #xD | #xA; */ case '\u0080': c = ' '; default: if(c<= ' '){//space switch(s){ case S_TAG: el.setTagName(source.slice(start,p));//tagName s = S_TAG_SPACE; break; case S_ATTR: attrName = source.slice(start,p) s = S_ATTR_SPACE; break; case S_ATTR_NOQUOT_VALUE: var value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer); errorHandler.warning('attribute "'+value+'" missed quot(")!!'); el.add(attrName,value,start) case S_ATTR_END: s = S_TAG_SPACE; break; //case S_TAG_SPACE: //case S_EQ: //case S_ATTR_SPACE: // void();break; //case S_TAG_CLOSE: //ignore warning } }else{//not space //S_TAG, S_ATTR, S_EQ, S_ATTR_NOQUOT_VALUE //S_ATTR_SPACE, S_ATTR_END, S_TAG_SPACE, S_TAG_CLOSE switch(s){ //case S_TAG:void();break; //case S_ATTR:void();break; //case S_ATTR_NOQUOT_VALUE:void();break; case S_ATTR_SPACE: var tagName = el.tagName; if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)){ errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead2!!') } el.add(attrName,attrName,start); start = p; s = S_ATTR; break; case S_ATTR_END: errorHandler.warning('attribute space is required"'+attrName+'"!!') case S_TAG_SPACE: s = S_ATTR; start = p; break; case S_EQ: s = S_ATTR_NOQUOT_VALUE; start = p; break; case S_TAG_CLOSE: throw new Error("elements closed character '/' and '>' must be connected to"); } } }//end outer switch //console.log('p++',p) p++; } } /** * @return true if has new namespace define */ function appendElement(el,domBuilder,currentNSMap){ var tagName = el.tagName; var localNSMap = null; //var currentNSMap = parseStack[parseStack.length-1].currentNSMap; var i = el.length; while(i--){ var a = el[i]; var qName = a.qName; var value = a.value; var nsp = qName.indexOf(':'); if(nsp>0){ var prefix = a.prefix = qName.slice(0,nsp); var localName = qName.slice(nsp+1); var nsPrefix = prefix === 'xmlns' && localName }else{ localName = qName; prefix = null nsPrefix = qName === 'xmlns' && '' } //can not set prefix,because prefix !== '' a.localName = localName ; //prefix == null for no ns prefix attribute if(nsPrefix !== false){//hack!! if(localNSMap == null){ localNSMap = {} //console.log(currentNSMap,0) _copy(currentNSMap,currentNSMap={}) //console.log(currentNSMap,1) } currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value; a.uri = 'http://www.w3.org/2000/xmlns/' domBuilder.startPrefixMapping(nsPrefix, value) } } var i = el.length; while(i--){ a = el[i]; var prefix = a.prefix; if(prefix){//no prefix attribute has no namespace if(prefix === 'xml'){ a.uri = 'http://www.w3.org/XML/1998/namespace'; }if(prefix !== 'xmlns'){ a.uri = currentNSMap[prefix || ''] //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)} } } } var nsp = tagName.indexOf(':'); if(nsp>0){ prefix = el.prefix = tagName.slice(0,nsp); localName = el.localName = tagName.slice(nsp+1); }else{ prefix = null;//important!! localName = el.localName = tagName; } //no prefix element has default namespace var ns = el.uri = currentNSMap[prefix || '']; domBuilder.startElement(ns,localName,tagName,el); //endPrefixMapping and startPrefixMapping have not any help for dom builder //localNSMap = null if(el.closed){ domBuilder.endElement(ns,localName,tagName); if(localNSMap){ for(prefix in localNSMap){ domBuilder.endPrefixMapping(prefix) } } }else{ el.currentNSMap = currentNSMap; el.localNSMap = localNSMap; //parseStack.push(el); return true; } } function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){ if(/^(?:script|textarea)$/i.test(tagName)){ var elEndStart = source.indexOf('',elStartEnd); var text = source.substring(elStartEnd+1,elEndStart); if(/[&<]/.test(text)){ if(/^script$/i.test(tagName)){ //if(!/\]\]>/.test(text)){ //lexHandler.startCDATA(); domBuilder.characters(text,0,text.length); //lexHandler.endCDATA(); return elEndStart; //} }//}else{//text area text = text.replace(/&#?\w+;/g,entityReplacer); domBuilder.characters(text,0,text.length); return elEndStart; //} } } return elStartEnd+1; } function fixSelfClosed(source,elStartEnd,tagName,closeMap){ //if(tagName in closeMap){ var pos = closeMap[tagName]; if(pos == null){ //console.log(tagName) pos = source.lastIndexOf('') if(pos',start+4); //append comment source.substring(4,end)//