diff --git a/src/stencil/model.clj b/src/stencil/model.clj index 72997693..151531ff 100644 --- a/src/stencil/model.clj +++ b/src/stencil/model.clj @@ -12,7 +12,8 @@ [stencil.model.common :refer [unix-path ->xml-writer resource-copier]] [stencil.ooxml :as ooxml] [stencil.model [numbering :as numbering] [relations :as relations] [style :as style] [content-types :as content-types]] - [stencil.cleanup :as cleanup])) + [stencil.cleanup :as cleanup] + [stencil.model.content-types :as content-types])) (set! *warn-on-reflection* true) @@ -105,18 +106,19 @@ (assert (some? fragments)) (binding [*inserted-fragments* (atom #{}) *all-fragments* (into {} fragments)] - (style/with-styles-context template-model - (numbering/with-numbering-context template-model - (let [evaluate (fn [m] - (relations/with-extra-files-context - (let [result (eval-model-part m data functions) - fragment-names (set (:fragment-names result))] - (-> m - (relations/model-assoc-extra-files fragment-names) - (assoc :result result)))))] - (-> template-model - (update-in [:main :headers+footers] (partial mapv evaluate)) - (update :main evaluate))))))) + (content-types/with-content-types + (style/with-styles-context template-model + (numbering/with-numbering-context template-model + (let [evaluate (fn [m] + (relations/with-extra-files-context + (let [result (eval-model-part m data functions) + fragment-names (set (:fragment-names result))] + (-> m + (relations/model-assoc-extra-files fragment-names) + (assoc :result result)))))] + (-> template-model + (update-in [:main :headers+footers] (partial mapv evaluate)) + (update :main evaluate)))))))) (defn- model-seq [model] diff --git a/src/stencil/model/content_types.clj b/src/stencil/model/content_types.clj index 04978814..10fd0ec9 100644 --- a/src/stencil/model/content_types.clj +++ b/src/stencil/model/content_types.clj @@ -1,11 +1,50 @@ (ns stencil.model.content-types - (:require [clojure.java.io :refer [file]]) + (:require [clojure.java.io :refer [file]] + [clojure.data.xml :as xml] + [clojure.java.io :refer [file input-stream]] + [stencil.ooxml :as ooxml] + [stencil.model.common :refer [->xml-writer]]) (:import [java.io File])) +(def xmlns "http://schemas.openxmlformats.org/package/2006/content-types") + +(def tag-types :xmlns.http%3A%2F%2Fschemas.openxmlformats.org%2Fpackage%2F2006%2Fcontent-types/Types) +(def tag-override :xmlns.http%3A%2F%2Fschemas.openxmlformats.org%2Fpackage%2F2006%2Fcontent-types/Override) +(def tag-default :xmlns.http%3A%2F%2Fschemas.openxmlformats.org%2Fpackage%2F2006%2Fcontent-types/Default) + +(def attr-extension :Extension) +(def attr-part-name :PartName) +(def attr-content-type :ContentType) + +;; return a map of +(defn- parse-ct-file [content-types-file] + (with-open [reader (input-stream (file content-types-file))] + (let [parsed (xml/parse reader)] + (assert (= "Types" (name (:tag parsed)))) + (reduce (fn [m elem] + ;(println :! (:tag elem) elem (pr-str elem)) + (println :! (:attrs elem)) + (case (name (:tag elem)) + "Default" (assoc-in m [::default (attr-extension (:attrs elem))] (attr-content-type (:attrs elem))) + "Override" (assoc-in m [::override (attr-part-name (:attrs elem))] (attr-content-type (:attrs elem))))) + {} (remove string? (:content parsed)))))) ;; rm empty strings + (defn parse-content-types [^File dir] (assert (.isDirectory dir)) (let [cts (file dir "[Content_Types].xml")] (assert (.exists cts)) (assert (.isFile cts)) - {:source-file cts + {;:source-file cts + :parsed (parse-ct-file cts) :stencil.model/path (.getName cts)})) + +(defn with-content-types [model] + (let [parsed (-> model :content-types :parsed) + _ (println :! parsed) + tree {:tag tag-types + :attrs {:xmlns xmlns} + :content (concat (for [[k v] (::default parsed)] + {:tag tag-default :attrs {attr-extension k attr-content-type v}}) + (for [[k v] (::override parsed)] + {:tag tag-override :attrs {attr-part-name k attr-content-type v}}))}] + (assoc-in model [:content-types :result :writer] (->xml-writer tree)))) diff --git a/src/stencil/model/numbering.clj b/src/stencil/model/numbering.clj index 5d71d32b..7848971c 100644 --- a/src/stencil/model/numbering.clj +++ b/src/stencil/model/numbering.clj @@ -15,13 +15,21 @@ (defn -initial-numbering-context [template-model] (let [xml-tree (-> template-model :main :stencil.model/numbering :parsed)] {:extra-elems (atom []) ;; elems added during evaluation in context - :counter (atom (apply max 0 (for [e (:content xml-tree)] - (->int (or (-> e :attrs ooxml/xml-abstract-num-id) - (-> e :attrs ooxml/attr-numId)))))) + :counter1 (atom (apply max 0 (for [e (:content xml-tree)] + (-> e :attrs ooxml/attr-numId (or "0") ->int)))) + :counter2 (atom (apply max 0 (for [e (:content xml-tree)] + (-> e :attrs ooxml/xml-abstract-num-id (or "0") ->int)))) :parsed xml-tree})) (defn- gen-numbering-id [] - (str (swap! (:counter *numbering*) inc))) + (str (swap! (:counter1 *numbering*) inc))) + +(defn- gen-abstract-numbering-id [] + (str (swap! (:counter2 *numbering*) inc))) + + +(def ^:private ignorable-tag :xmlns.http%3A%2F%2Fschemas.openxmlformats.org%2Fmarkup-compatibility%2F2006/Ignorable) + (defn -add-extra-elems [evaluated-model extra-elems] (-> evaluated-model @@ -30,8 +38,11 @@ (if (:stencil.model/path nr#) (dissoc nr# :source-file) (assoc nr# - :parsed {:tag ooxml/tag-numbering :content []} + :parsed {:tag ooxml/tag-numbering :attrs {ignorable-tag ""} :content []} :stencil.model/path "word/numbering.xml")))) + ;; TODO: make it conditional + (assoc-in [:content-types :parsed :stencil.model.content-types/override "/word/numbering.xml"] + "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml") (update-in [:main :stencil.model/numbering :parsed :content] concat extra-elems) (update-in [:main :stencil.model/numbering] (fn [nr#] (assoc nr# :result {:writer (->xml-writer (:parsed nr#))}))) @@ -65,7 +76,7 @@ (if (contains? (:abstract-num-id-rename cache) abstract-nr-id) cache (let [elem (id->abstract-numbering abstract-nr-id) - new-id (gen-numbering-id)] + new-id (gen-abstract-numbering-id)] (add-numbering-entry! (assoc-in elem [:attrs ooxml/xml-abstract-num-id] new-id)) (assoc-in cache [:abstract-num-id-rename abstract-nr-id] new-id)))) copy-nring (fn [cache numbering-id] diff --git a/src/stencil/spec.clj b/src/stencil/spec.clj index f54ffe22..e2df025f 100644 --- a/src/stencil/spec.clj +++ b/src/stencil/spec.clj @@ -55,7 +55,7 @@ (s/def :stencil.model/content-types (s/keys :req [:stencil.model/path] - :req-un [::source-file])) + :opt-un [::source-file])) (s/def :stencil.model/model (s/keys :req []