1 ;;;; xslide-process.el --- Process an XSL stylesheet
2 ;; $Id: xslide-process.el,v 1.3 2003/06/05 22:13:01 tonygraham Exp $
4 ;; Copyright (C) 1998, 1999, 2000, 2001 Tony Graham
6 ;; Author: Tony Graham <tkg@menteith.com>
8 ;;; This file is not part of GNU Emacs.
10 ;; This program is free software; you can redistribute it and/or
11 ;; modify it under the terms of the GNU General Public License
12 ;; as published by the Free Software Foundation; either version 2
13 ;; of the License, or (at your option) any later version.
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program; if not, write to the Free Software
22 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 ;; Originally copied almost wholesale from psgml.el by Lennart Staflin
29 ;; Send bugs to xslide-bug@menteith.com
30 ;; Use `xsl-submit-bug-report' for bug reports
37 (defcustom xsl-offer-save t
38 "*If non-nil, ask about saving modified buffers before \\[xsl-process] is run."
39 :type '(choice (const :tag "Yes" t) (const :tag "No" nil))
42 (defcustom xsl-process-browse-output nil
43 "*If non-nil, open output in browser after \\[xsl-process] is run."
44 :type '(choice (const :tag "Yes" t) (const :tag "No" nil))
47 (defcustom xsl-process-find-output nil
48 "*If non-nil, find output file after \\[xsl-process] is run."
49 :type '(choice (const :tag "Yes" t) (const :tag "No" nil))
52 (defcustom xsl-process-command
54 ;; XT Windows executable
57 "java com.jclark.xsl.Driver %i %s %o"
59 "java org.apache.xalan.xslt.Process -IN %i -XSL %s -OUT %o"
62 ;; Instant Saxon using xml-stylesheet PI
65 "java com.icl.saxon.StyleSheet -o %o %i %s"
66 ;; Saxon using xml-stylesheet PI
67 "java com.icl.saxon.StyleSheet -o %o %i"
69 "xsltproc -o %o %s %i"
71 "java jd.xml.xslt.Stylesheet -out %o %i %s"
72 ;; Oracle XDK for Java
73 "java oracle.xml.parser.v2.oraxsl %i %s %o"
75 "*The shell command to process an XSL document.
77 This is a `format' control string that by default should contain three
78 `%s' conversion specifications: the first will be replaced by the
79 value of `xsl-process-input-file' \(or the empty string, if nil\); the
80 second will be replaced by `xsl-process-stylesheet-file' \(or the empty
81 string, if nil\); the third will be replaced by
82 `xsl-process-output-file' \(or the empty string, if nil\).
84 If `xsl-process-files' is non-nil, the format string should contain
85 one `%s' conversion specification for each element of its result.
87 If `xsl-process-command' is a list, then every element should be a
88 string. The strings will be tried in order and %-sequences in the
89 string will be replaced according to the list below, if the string contains
90 %-sequences with no replacement value the next string will be tried.
92 %b means the visited file of the current buffer
93 %i means the value of `xsl-process-input-file'
94 %s means the value of `xsl-process-stylesheet-file'
95 %o means the value of `xsl-process-output-file'
97 :type '(repeat :tag "Commands" string)
100 (defvar xsl-process-files nil
101 "If non-nil, a function of no arguments that returns a list of file names.
102 These file names will serve as the arguments to the `xsl-process-command'
103 format control string instead of the defaults.")
105 (defcustom xsl-process-error-regexps
108 ;; file:///path/to/foo.xsl; Line 9; Column 12; ...
109 ("^file:\\([^;]+\\)\\; Line \\([0-9]+\\)\\;\\( Column \\([0-9]+\\)\\;\\)?"
113 ;; Error at xsl:output on line 9 of file:/path/to/foo.xsl:
114 ;; Error on line 9 column 5 of file:/path/to/foo.xsl:
115 ("^Error\\( at [^ ]+\\)? on line \\([0-9]+\\)\\( column \\([0-9]+\\)\\)? of file:\\(\\(/[A-Za-z]:\\)?[^:]+\\):$"
119 ;; file:/path/to/foo.xsl<Line 9, Column 17>: ...
120 ("^file:\\([^<]+\\)<Line \\([0-9]+\\)\\(, Column \\([0-9]+\\)\\)?>:"
124 ;; - uri = file:/path/to/foo.xsl
128 ;; - uri = file:/path/to/foo.xsl
129 ;; - element = xsl:output (line 9)
130 ("^- uri[ \t]+= file:\\(.+\\)\\([\r\n+]- \\(\\([^(]*?(\\)?line[ \t]+\\(= \\)?\\([0-9]+\\)\\)?\\)?\\([\r\n]+- column[ \t]+= \\([0-9]+\\)\\)?" 1 6 8)
133 (".*\\<file:\\(\\(/[A-Za-z]:\\)?[^:]+\\):[ \t]*\\(\\([0-9]+\\):[ \t]*\\(\\([0-9]+\\):\\)?\\)?"
135 (".*\\([^ ]+\\.x[ms]l\\):[ \t]*\\([0-9]+\\):[ \t]*\\(\\([0-9]+\\):\\)?"
137 ("^\\([^:]+\\): \\([0-9]+\\): error:"
140 "*Alist of regexps to recognize error messages from `xsl-process'.
141 See `compilation-error-regexp-alist'."
142 :type '(repeat :tag "Regexps"
143 (list (regexp :tag "Regexp")
144 (integer :tag "File index")
145 (integer :tag "Line index")
146 (choice :tag "Column index"
148 (const :tag "None" nil))))
151 (defvar xsl-xml-source nil
152 "*If non-nil, this is the name of the XML source file.")
153 (put 'xsl-xml-source 'xsl-type 'string)
155 (defvar xsl-xsl-result nil
156 "*If non-nil, this is the name of the XSL result file.")
157 (put 'xsl-xsl-result 'xsl-type 'string)
159 (defvar xsl-process-command-history nil
160 "The minibuffer history list for `xsl-process''s COMMAND argument.")
161 ;;(make-variable-buffer-local 'xsl-process-command-history)
164 (autoload 'compile-internal "compile" ""))
166 (defun xsl-subst-expand-char (c parts)
167 (cdr-safe (assq (downcase c) parts)))
169 (defun xsl-subst-expand (s parts)
170 (loop for i from 0 to (1- (length s))
173 (or (xsl-subst-expand-char (aref s (incf i)) parts)
175 (char-to-string (aref s i)))))
177 (defun xsl-populate-process-command-history ()
179 ((consp xsl-process-command)
182 (cons ?b (and (buffer-file-name)
183 (file-name-nondirectory (buffer-file-name))))
184 (cons ?i xsl-process-input-file)
185 (cons ?s xsl-process-stylesheet-file)
186 (cons ?o xsl-process-output-file))))
187 (setq xsl-process-command-history
190 (xsl-subst-expand x process-subst))
192 xsl-process-command-history))))
193 ;; (loop for template in xsl-process-command
195 ;; (xsl-subst-expand template process-subst)
197 ;; xsl-process-command-history)))
199 (apply 'format xsl-process-command
200 (if xsl-process-files
201 (funcall xsl-process-files)
202 (list (or xsl-xml-source "")
203 (let ((name (buffer-file-name)))
205 (file-name-nondirectory name)
207 (or xsl-xsl-result "")))))))
209 (defvar xsl-process-input-file nil
210 "Filename of input file for `xsl-process' command")
212 (defvar xsl-process-input-history nil
213 "The minibuffer history list for `xsl-get-process-parameters''s INPUT argument.")
215 (defvar xsl-process-stylesheet-file nil
216 "Filename of stylesheet file for `xsl-process' command")
218 (defvar xsl-process-stylesheet-history nil
219 "The minibuffer history list for `xsl-get-process-parameters''s STYLESHEET argument.")
221 (defvar xsl-process-output-file nil
222 "Filename of output file for `xsl-process' command")
224 (defvar xsl-process-output-history nil
225 "The minibuffer history list for `xsl-get-process-parameters''s OUTPUT argument.")
227 (defun xsl-get-process-parameters ()
228 "Get and set the parameters for the `xsl-process' command"
230 (setq xsl-process-input-file
231 (xsl-read-from-minibuffer "Input file: "
232 (concat (file-name-sans-extension
233 (file-name-nondirectory
236 'xsl-process-input-history))
237 (setq xsl-process-stylesheet-file
238 (xsl-read-from-minibuffer "Stylesheet file: "
239 (file-name-nondirectory
241 'xsl-process-stylesheet-history))
242 (setq xsl-process-output-file
243 (xsl-read-from-minibuffer "Output file: "
244 (concat (file-name-sans-extension
245 (file-name-nondirectory
246 xsl-process-input-file))
248 'xsl-process-output-history)))
250 (defun xsl-process (command)
251 "Process an XSL stylesheet.
253 Runs COMMAND, a shell command, in a separate process asynchronously
254 with output going to the buffer *XSL process*. You can then use the
255 command \\[next-error] to find the next error message and move to the
256 line in the XSL document that caused it.
258 The first time that the program is run and whenever you provide a
259 prefix argument, e.g. \\[universal-argument] \\[xsl-process], prompts
260 for input filename, stylesheet file, and output filename. Those
261 values are used with the templates in `xsl-process-command' to
262 populate this command's command history with the command lines to run
263 several XSLT processors using those values. Use M-p and M-n to step
264 through the predefined commands, edit a command if necessary, or enter
265 a new command line. The next time that this command is run, the
266 previously executed command is used as the default.
268 If `xsl-process-browse-output' is non-nil, the filename entered in
269 response to the \"Output file:\" prompt is opened in a browser using
272 If `xsl-process-view-output' is non-nil, the filename entered in
273 response to the \"Output file:\" prompt is opened in a buffer."
278 (null xsl-process-command-history))
280 (xsl-get-process-parameters)
281 (xsl-populate-process-command-history)))
282 (read-from-minibuffer "Process command: "
283 (car xsl-process-command-history)
285 'xsl-process-command-history))))
287 (save-some-buffers nil nil))
288 (compile-internal command "No more errors" "XSL process"
290 xsl-process-error-regexps)
291 (if xsl-process-browse-output
292 (browse-url xsl-process-output-file))
293 (if xsl-process-find-output
295 (find-file-noselect (expand-file-name xsl-process-output-file)))))
298 (provide 'xslide-process)