我使用cl-who来生成svg,它可以正常工作,直到需要一个混合case标记为止:
(with-html-output (*standard-output*)
(:defs
(:|radialGradient| :id "grad1" :cy "20" :fx "10%" :fy "50%" :r "8"
(:stop :offset "0%" :stop-color "#fff")
(:stop :offset "100%" :stop-color "#000"))))对于这种情况,有一个变量,*downcase-tokens*。工作起来有点困难:
(let ((*downcase-tokens-p* nil))
(with-html-output (*standard-output*)
(:defs
(:|radialGradient| :id "grad1" :cy "20" :fx "10%" :fy "50%" :r "8"))))输出:
<defs>
<radialgradient id='grad1' cy='20' fx='10%' fy='50%' r='8'>
</radialgradient>
</defs>使用let包装没有任何影响,因为*小写-令牌-p*显然是在宏展开时设置的T。
所以我们需要拉出伊娃:
(let ((*downcase-tokens-p* nil))
(eval
'(with-html-output (*standard-output*)
(:defs
(:|radialGradient| :id "grad1" :cy "20" :fx "10%" :fy "50%" :r "8")))))输出:
<DEFS>
<radialGradient ID='grad1' CY='20' FX='10%' FY='50%' R='8'>
</radialGradient>
</DEFS>这适用于radialGradient标记,但现在我需要将其他所有东西都包装起来。
有什么最简单的方法可以让radialGradient标记正确地显示,而不让其他东西单独显示呢?
编辑:示例添加。
发布于 2017-09-02 16:18:59
下面是一个通用的解决方案:
(defmethod convert-tag-to-string-list :around ((tag t) attr-list body body-fn)
(if (find-if #'lower-case-p (symbol-name tag))
(nconc (list* "<"
(symbol-name tag)
(convert-attributes attr-list))
(list ">")
(funcall body-fn body)
(list (format nil "</~a>" (symbol-name tag))))
(call-next-method)))结果:
CL-USER> (with-html-output (*standard-output*)
(:asdf
(:ASDF
(:|aSDf|
(:|ASDF|)))))
<asdf><asdf><aSDf><asdf></asdf></aSDf></asdf></asdf>发布于 2017-09-02 14:50:08
重写单个标记的呈现方法:
(defmethod convert-tag-to-string-list ((tag (eql :radialgradient))
attr-list body body-fn)
(nconc (cons "<radialGradient"
(convert-attributes attr-list))
(list ">")
(funcall body-fn body)
(list "</radialGradient>")))被移除:
(with-html-output (*standard-output*)
(:defs
(:radialGradient :id "grad1" :cy "20" :fx "10%" :fy "50%" :r "8")))输出:
<defs>
<radialGradient id='grad1' cy='20' fx='10%' fy='50%' r='8'
</radialGradient>
</defs>需要为正在使用的每个混合情况下的SVG标记定义转换标记到字符串列表的方法。
发布于 2017-09-02 17:59:48
你可以改变Lisp阅读器的情况。
保藏
(setf (readtable-case *readtable*) :preserve)从现在开始,所有CL符号都必须用大写形式编写,但您可以使用命名-可读性进行本地化更改,只在需要读取SVG树的文件中进行本地化。
(DEFPACKAGE :TWHO (:USE :CL :CL-WHO))
(IN-PACKAGE :TWHO)
(SETF *DOWNCASE-TOKENS-P* NIL)
(WITH-HTML-OUTPUT (*STANDARD-OUTPUT* *STANDARD-OUTPUT* :INDENT T)
(:defs
(:radialGradient :id "grad1" :cy "20" :fx "10%" :fy "50%" :r "8"
(:stop :offset "0%" :stop-color "#fff")
(:stop :offset "100%" :stop-color "#000"))))编写以下内容:
<defs>
<radialGradient id='grad1' cy='20' fx='10%' fy='50%' r='8'>
<stop offset='0%' stop-color='#fff'></stop>
<stop offset='100%' stop-color='#000'></stop>
</radialGradient>
</defs>倒置
我个人会使用:invert,但在这种情况下,您必须用大写写所有小写SVG符号。
(SETF (READTABLE-CASE *READTABLE*) :INVERT)
(with-html-output (*standard-output* *standard-output* :indent t)
(:DEFS
(:radialGradient :ID "grad1" :CY "20" :FX "10%" :FY "50%" :R "8"
(:STOP :OFFSET "0%" :STOP-COLOR "#fff")
(:STOP :OFFSET "100%" :STOP-COLOR "#000"))))写同样的东西:
<defs>
<radialGradient id='grad1' cy='20' fx='10%' fy='50%' r='8'>
<stop offset='0%' stop-color='#fff'></stop>
<stop offset='100%' stop-color='#000'></stop>
</radialGradient>
</defs>"但至少你的CL代码不需要大写。
宏和/或宏字符
您可以使用宏和宏字符在本地进行更改。
将所有内容重置为默认值:
(setf *downcase-tokens-p* t)
(setf (readtable-case *readtable*) :upcase)我个人并不介意在全球范围内更改*downcase-tokens-p*,但如果您真的想要改变,除了使用eval之外,另一种方法是手动进行宏展开。在这个例子中,我使用的是宏扩展-该死。
(ql:quickload "macroexpand-dammit")然后,定义一个自定义宏:
(defmacro with-svg-output ((stream) &body body)
(let ((*downcase-tokens-p* nil))
(let ((stream% (copy-symbol :stream)))
(macroexpand-dammit:macroexpand-dammit
`(let ((,stream% ,stream))
(with-html-output (,stream% ,stream% :indent t)
,@body))))))最后,要只在读取SVG表单时更改可读的情况,请定义一个自定义读取器函数;我将其绑定到#@字符序列:
(set-dispatch-macro-character
#\# #\@
(lambda (stream &rest args)
(declare (ignore args))
(let ((*readtable* (copy-readtable)))
(setf (readtable-case *readtable*) :invert)
(read stream t nil t))))该示例可以重写为:
(with-svg-output (*standard-output*)
#@(:DEFS
(:radialGradient :ID "grad1" :CY "20" :FX "10%" :FY "50%" :R "8"
(:STOP :OFFSET "0%" :STOP-COLOR "#fff")
(:STOP :OFFSET "100%" :STOP-COLOR "#000"))))这里的优点是您的更改只在本地应用,并且有一个非常独特的语法,它表明发生了一些不同的事情。如果您可以在SVG表达式内用大写字母编写代码,那么可以使用:preserve。这取决于什么对你更方便。
https://stackoverflow.com/questions/46010186
复制相似问题