2009年2月8日日曜日

XMLを扱う (その20) [Common Lisp]

cxmlでschemaを扱う。


* : [cl][xml][cxml][xml catalog]

XML関係のディレクトリのまとめ。

~/local/lib/catalog/
; カタログ関係置き場
~/local/lib/catalog/catalog
; XML Catalogのcatalog xmlファイル。
; cxmlもこれを使う。
~/local/lib/schema
; rnc置き場。nxml-modeで参照している。
~/local/lib/xml
; linuxから移植したもの。
;declaration
;entities
;misc
;schema
;という4つのディレクトリを持つ。
;これら4つの名称から、XMLの外部エンティティ格納用だろう。
~/local/lib/xml-core
; linuxから移植したもの。
; なんのために存在するのかいまいちわからない。

将来再整備すべきだが、現状はこんな感じ。


* : [cl][xml][cxml][xml catalog]

さて、cxmlにおけるschemaとvalidationの話。

まずXML仕様で定義しているschemaはDTDのみである。なので、XML仕様に
準拠したXML processorである、といったときにはDTDは取り扱えなければ
ならないし、他の形式のSchemaを取り扱える必要はない。

DTDにはinternal subsetとexternal subsetがある。
ポイントは、共通のDTDをexternal subsetとしたときにそれをどう取り扱
うかだろう。

まず第一にはXML文書にsystem idが記載されており、そのURIが、使って
いるXML processorが取得対応している形式ならば、そこから取得すると
いうやり方。

cxmlの場合はローカルのファイルシステムからは取得できるが、そのまま
ではhttpに対応していないため、httpをスキーマとするURIについてはエ
ラーとなる。

cxmlでは、これをエラーとしないための迂回作が2つある。

ひとつは、entity resoloverで、ローカルファイルで差し替えちゃう方法。

---
(flet ((resolver (pubid sysid)
(declare (ignore pubid sysid))
(flexi-streams:make-in-memory-input-stream nil)))
(cxml:parse-file "dtdexample.xml" (cxml-dom:make-dom-builder)
:entity-resolver #'resolver))
---

もうひとつは、entity resoloverで、そのURIから取ってきちゃう方法。

---
(flet ((resolver (pubid sysid)
(declare (ignore pubid))
(when (eq (puri:uri-scheme sysid) :http)
(drakma:http-request sysid :want-stream t))))
(cxml:parse-file "dtdexample.xml" (cxml-dom:make-dom-builder)
:entity-resolver #'resolver))
---

ここではdrakmaというライブラリを使用している。

さて、第二の方法はXML Catalogsを使う方法である。
これはXML processorがXML Catalogsに対応している必要がある。
XML Catalogsの仕様はOASISで標準化されており、

http://www.oasis-open.org/committees/entity/spec-2001-08-06.html

が仕様書である。

XML Catalogsというのは、簡単にいえば、XML文書の中に現われるpublic
identifierやsystem identifierやURIの代替をXML processorに渡すため
の設定ファイルである。

現在、私の環境のcatalogファイルは次のとおり。

---
<?xml version="1.0"?>
<!DOCTYPE catalog PUBLIC "-//OASIS//DTD XML Catalogs V1.0//EN"
"file:///Users/aka/local/lib/xml/schema/xml-core/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<delegatePublic publicIdStartString="-//OASIS//DTD XML Catalogs V1.0//EN" catalog="file:///Users/aka/local/lib/xml/schema/xml-core.xml"/>
<delegateSystem systemIdStartString="http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd" catalog="file:///Users/aka/local/lib/catalog/xml-core.xml"/>
<group xml:base="file:///Users/aka/local/lib/xml/schema/xhtml1.0/">
<puublic publicId="-//W3C//DTD XHTML 1.0 Strict//EN" uri="xhtml1-strict.dtd"/>
<public publicId="-//W3C//ENTITIES Latin 1 for XHTML//EN" uri="xhtml-lat1.ent"/>
<public publicId="-//W3C//ENTITIES Symbols for XHTML//EN" uri="xhtml-symbol.ent"/>
<public publicId="-//W3C//ENTITIES Special for XHTML//EN" uri="xhtml-special.ent"/>
<system systemId="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" uri="xhtml1-strict.dtd"/>
</group>
</catalog>
---

cxmlでは次のようにこれを利用できる。

---
;;catalogを使わずにxhtmlをパース
(setf cxml:*catalog* nil)
(cxml:parse #p"test.xhtml" (stp:make-builder)) ; error,DTDを取得できない。

;;catalogを使ってxhtmlをパース
(setf cxml:*catalog* nil)
(setf cxml:*catalog* (cxml:make-catalog (list "/Users/aka/local/lib/catalog/catalog")))
(cxml:parse #p"test.xhtml" (stp:make-builder)) ; errorにならない。
---

次回はcxml-rng。

こつこつ。

0 件のコメント: