пятница, 21 ноября 2008 г.

cl-libxml2-0.2

Сегодня выпустил cl-libxml2 версии 0.2

Основное внимание при разработке этого релиза было уделено возможностям расширения, это:
  • Custom URL resolve

  • XPath extension functions

  • XSLT extension elements

Custom URL resolve

Позволяет подсовывать парсеру, когда он желает загрузить какие-то внешние данные, свои данные. Это может потребоваться для реализации какого-то нестандартного протокола, либо, например, для поддержки авторизации, ну да много для чего. Выглядит это примерно так:
CL-USER> (in-package #:libxml2.tree)
#<PACKAGE "LIBXML2.TREE">
TREE> (defun my-resolve-1 (url id ctxt)
(declare (ignore url id))
(resolve-string "<node />" ctxt))

MY-RESOLVE-1
TREE> (defun my-resolve-2 (url id ctxt)
(declare (ignore id))
(if (eql (puri:uri-scheme url) :my)
(resolve-string (format nil "<node>~A</node>" url) ctxt)))

MY-RESOLVE-2
TREE> (with-custom-resolvers (#'my-resolve-2 #'my-resolve-1)
(with-parse-document (doc "<root xmlns:xi=\"http://www.w3.org/2001/XInclude\">
<xi:include href=\"my:doc\" />
<xi:include href=\"my2:doc\" />
</root>")
(process-xinclude doc)
(serialize doc :to-string)))

"<?xml version=\"1.0\" encoding=\"utf-8\"?>
<root xmlns:xi=\"http://www.w3.org/2001/XInclude\">
<node>my://doc</node>
<node/>
</root>
"

XPath extension functions

XPath мощный инструмент, но часто встроенной функциональности не хватает. В таком случае можно добавить пару своих функций:

TREE> (in-package #:libxml2.xpath)
#<PACKAGE "LIBXML2.XPATH">
XPATH> (define-xpath-function hello-world ()
"Hello world!")

HELLO-WORLD
XPATH> (define-xpath-function echo (msg)
msg)

ECHO
XPATH> (define-xpath-function join (delimiter &rest strs)
(iter (for str in strs)
(reducing str
by (lambda (s x) (concatenate 'string s delimiter x)))))

JOIN
XPATH> (with-xpath-functions ((hello-world "hello-world")
(echo "echo")
(join "join"))
(with-parse-document (doc "<root />")
(find-string doc "join('//', hello-world(), '---', echo('Buy!'))")))

"Hello world!//---//Buy!"

XSLT extension elements

Я очень люблю писать на XSLT, совершенно удивительный инструмент, однако и здесь набор имеющихся средств далеко не полон. Не беда, дописать необходимые элементы можно и самому. Например, встроенную функцию copy-of можно реализовать так:

XPATH> (in-package #:libxml2.xslt)
#<PACKAGE "LIBXML2.XSLT">
XSLT> (define-xslt-element copy-of (self input output)
(iter (for node in-xpath-result (attribute-value self "select") on input)
(append-child output (copy node))))

COPY-OF
XSLT> (with-xslt-elements ((copy-of "copy-of" "www.sample.org"))
(with-stylesheet (style "<?xml version=\"1.0\"?>
<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:my=\"www.sample.org\" extension-element-prefixes=\"my\" version=\"1.0\">
<xsl:template match=\"/root\">
<result><my:copy-of select=\"node()[@attr]\" /></result>
</xsl:template>
</xsl:stylesheet>")
(with-parse-document (doc "<root><a attr=\"1\"/><b /><c attr=\"2\"/><d /></root>")
(with-transfom-result (res (style doc))
(serialize res :to-string)))))

"<?xml version=\"1.0\" encoding=\"utf-8\"?>
<result>
<a attr="1"/>
<c attr="2"/>
</result>

Резюме

Кстати, "custom URL resolving" и "XPath extension functions" работают и внутри XSLT.
Когда-то меня впечатлили соответствующие возможности библиотеки lxml: оказалось что реализовать сопоставимый функционал не так уж и сложно :-)

Комментариев нет:

Отправить комментарий