なんだこれは

はてなダイアリーから移転しました。

NOTICE.xml.gz から file-nameの値とcontentIdを取り出す Gauche編

NOTICE.xml.gz から file-nameの値とcontentIdを取り出す

NOTICE.xml.gz から file-nameの値とcontentIdを取り出す by gauche

gzip 圧縮された XMLファイル、NOTICE.xml.gz があったとします。それで XML ファイルのトップレベlicenses タグ内に file-name タグがあって、そのプロパティ contentId の値と その file-name の値を抽出してみるとします。

<licenses>
  <file-name contentId="1234567890abcdef">value</file-name>
  <file-name contentId="1234567890abcdef">value</file-name>
  <file-name contentId="1234567890abcdef">value</file-name>
  <file-content contentId="1234567890abcdef"><![CDATA[ここにライセンスファイルの中身]]></file-content>
</licenses>
<!-- contentId はライセンス文の md5ハッシュ値  -->

この NOTICE.xml.gz は AOSP の中で使われているライセンス情報を管理するファイルです。多分検索したら手にはいる。 これをパースしてみよう。

gauche way

gauche だと標準で含まれる rfc.zlib と sxml で gzip 解凍 と xml をサポートしているらしい。

  • gzip 解凍は open-inflating-port:window-bits 47 でいける。
  • xml は...
    • xml を sxml に変換
    • sxml を xpath ではなく、sxpath で操作
    • sxpath がそれほど強力ではなかったというか使いこなせなかったのでそのあとは、lisp でS式操作でやっつけ
(use rfc.zlib)
(use sxml.ssax)
(use sxml.sxpath)
(use sxml.tools)

(define (gz->raw gz-file raw-file)
  (call-with-input-file gz-file
    (lambda (in-port)
      (call-with-output-file raw-file
      (lambda (out-port)
          (copy-port 
              (open-inflating-port in-port :window-bits 47)
              out-port))))))

(define (read-xml-file filename)
  (call-with-input-file filename
    (lambda (port)
      (ssax:xml->sxml port '()))))

(define (extract-file-names sxml-data)
  ((sxpath '(licenses file-name)) sxml-data))

(define (extract-name-contentId record)
  (let ((content-id-value
     (cadar (filter (lambda (ll) (eq? 'contentId (car ll)))
            (cdadr record))))
     (file-name-value (caddr record)))
    (cons file-name-value content-id-value)))

;;;;

; gzip -d
(gz->raw "NOTICE.xml.gz" "NOTICE.xml")

; S式風xml に変換して file-name 部分を抽出
(define fns 
        (extract-file-names (read-xml-file "NOTICE.xml")))

; あとはS式なのでごにょごにょ
(map extract-name-contentId fns)