XMLは難しい。。。それ以上に文字コードは難しい。文字コードそのもの、
というよりも、EmacsなどのUIで文字を取り扱っているときは、すでにた
くさんのプログラムがそれぞれに文字コードを取り扱った集積としてのこ
となので、本当に理解するにはそれぞれがどのように文字コードを扱って
いるのかをちゃんと知っていなければならない。今の私は、Emacsがどの
ように文字コードを扱っているのか、そしてTerminalがどうなのかがわか
らない。なのでとてもちゃんと理解できるとは思えない。
まあ、それは将来の課題としよう。
cxmlを使い「始める」のに十分な程度には理解できたと思う。(使いこな
す、ではない)
さて、自分なりの現時点でのcxmlのまとめを。はじめのターゲットは、
SAX、Klacks、DOM、XMLS。
XML形式と別の形式を相互変換するには、SAXまたはKlacksを用いる。
XML形式から別の何かへ。
XMLファイルを準備する。
--- example-100.xml ---
<!DOCTYPE test [
<!ELEMENT test (foo,bar*)>
<!ATTLIST test a CDATA #IMPLIED>
<!ELEMENT foo #PCDATA>
<!ELEMENT bar (foo?)>
<!ATTLIST bar xml:space (default|preserve) "default">
]>
<test a='b'>
<foo> </foo>
<bar> </bar>
<bar xml:space="preserve"> </bar>
</test>
---
まず、SAX。
SAXの中心的な概念は、eventsとhandlersだ。SAX parserはXML文書を読み
進めるにしたがってeventsを上げる。それを処理するhandlersがいろいろ
用意されているし、自分でも書ける。
---
;; parsing a file
(defparameter *example*
(cxml:parse-file "example-100.xml" (cxml-dom:make-dom-builder)))
---
この例ではcxml-dom:make-dom-builderがhanlerを生成している。その
handlerはDOMを生成するようなものだ。
xmlsを生成するには次のようにする。
---
;; parsing a file to xmls
(cxml:parse-file "example-100.xml" (cxml-xmls:make-xmls-builder))
---
さて、この結果は、
---
("test" (("a" "b")) "
" ("child" NIL) "
")
---
となる。多くの場合、ここでの改行はXMLファイルの可読性のためであり、
データとしての意味はないだろう。こういう場合は、
---
(cxml:parse-file "example-100.xml"
(cxml:make-whitespace-normalizer (cxml-xmls:make-xmls-builder))
:validate t)
---
というようにhandlerを段積みにして回避できたりする。
ここで大事なのはhandlerの基本形は、eventを受け取るものでもあり、
eventを投げるものでもあるということ。なので、うまく設計すれば、こ
こでのnormalizerのような汎用的なhandler部品ができる。
さて、eventを受け取るだけで、決してeventを投げないhandlerをsinkと
呼ぶ。(以前の私の理解は間違いであった)
なので、ここでのdom-builderやxmls-builderはsinkである。
sinkは大抵の場合、XMLとは別の表現を出力する。
続いてKlacks。
Klacksの中心的な概念は、pull-based (peek/consume)だ。
XML形式を読み込んで何か処理をする場合は、push-basedなSAXよりも
Klacksの方が書きやすい。peek、peek-next、find-element, skipなど、
bufferをもっているKlacksならではの制御機能が用意されている。
---
(klacks:with-open-source ; on REPL
(s (cxml:make-source #p"example-100.xml"))
(loop
for key = (klacks:peek s)
while key
do
(case key
(:start-element
(format t "~A {" (klacks:current-qname s)))
(:end-element
(format t "}")))
(klacks:consume s)))
---
なので、XMLの文書の一部の情報のみ利用して出力を構成するときなど、
Klacksがいいかもしれない。まるまる変換する場合は、SAXまたはいった
んDOMまたはXMLSにしてそれらをCLで変換というのがよいかもしれない。
続いて別の何かからXMLへ。すなわちSerialization。
これもSAXでもKlacksでも実現できる。SAXで実現できるというのは奇異で
ある。本来のJavaのSAXはSerializationには使えない。cxmlのSAXは、DOM
やxmlsをeventの源泉にすることができるのでSerializationに使える。
---
(with-open-file (out "example-100.out" :direction :output :element-type '(unsigned-byte 8) :if-exists :supersede)
(dom:map-document (cxml:make-octet-stream-sink out) *example*))
---
---
(with-open-file (out "example-100-xmls.out" :direction :output :element-type '(unsigned-byte 8) :if-exists :supersede)
(cxml-xmls:map-node (cxml:make-octet-stream-sink out)
'("test" (("a" "b")) ("child" nil))
:include-namespace-uri nil))
---
ここで、map-documentとmap-nodeがSAX eventを生成している。
make-octet-stream-sinkがそのeventを受け取るhandlerである。
sinkの処理としてstreamにXML形式を出力する。
さて、続いてin memoryな表現とその取り扱い。
まず、DOM。DOM自体は先程SAXとdom-builderを使って作成した。
DOMのインターフェイスはCORBA IDLで定義されており、cxmlでは、それを
独自なマッピングでCLにもってきている。ドキュメントはなさそう。
ただ、DOMのインターフェイスの名称はdescriptiveなので、ソースを見れ
ばすぐにわかる。
---
(dom:parent-node *example*)
(dom:child-nodes *example*)
(dom:first-child *example*)
(dom:node-name (dom:first-child *example*))
---
などなど。
次にXMLS。XMLS自体は先程SAXとxmls-builderで生成方法を確認した。
リスト、なので操作についての説明は割愛する。いくつかユーティリティ
がある。例えば、XMLSノードを作る便利関数などがある、が別にいらんよ
うな、、、リストだし。
---
(cxml-xmls:make-node :name "hoge" :ns "http://piyo" :attrs '(("att1" . "value1") ("att2" . "value2")))
---
とりあえず、今はこれだけ。
こつこつ。
0 件のコメント:
コメントを投稿