XMLで遊ぼう with xmlstarlet

XMLStarlet Command Line XML Toolkit: NewsXMLをいじくって遊ぼう。

インストール

$ sudo port install xmlstarlet

xmlstarletと毎回打つのは面倒なので、xmlにaliasしておく。

// .zshrc,.bashrcなどに
alias xml="xmlstarlet"

整形式(well-formed)であるかのチェック

まずは、XMLがwell-formedであるかのチェック。
これは要するに、タグの対応がとれているか、正しくネストされているかどうかなど、XMLとして最低限満たされる条件を満たしているかのチェック。

well-formedなXML

<?xml version="1.0" encoding="utf-8" ?>
<doc>
  <para>Hello World!!</para>
  <para>Second Line</para>
</doc>

well-formedでないXML

<?xml version="1.0" encoding="utf-8" ?>
<doc>
  <para>Hello World!!
  <para>Second Line</para>
</doc>

これは、xml valでチェックすることができる。

$ xml val valid.xml
valid.xml - valid

$ xml val invalid.xml
invalid.xml:5: parser error : Opening and ending tag mismatch: para line 3 and doc
</doc>
      ^
invalid.xml:6: parser error : Premature end of data in tag doc line 2

^
invalid.xml - invalid

DTDによる妥当性チェック

次は、DTDによる妥当なXML(vaild XML)かどうかのチェック。
これは、XMLになんらかの制限を付け加えて、その制限を満たしているかを調べる。
例えば、XMLのサブセットであるXHTMLはインライン要素の中にブロック要素を含むことはできない。

妥当なXML

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE doc [
<!ELEMENT doc (para+)>
<!ELEMENT para (#PCDATA)>
]>
<doc>
  <para>Hello World!!</para>
  <para>Second Line</para>
</doc>

妥当でないXML

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE doc [
<!ELEMENT doc (para+)>
<!ELEMENT para (#PCDATA)>
]>
<doc>
  <para>Hello World!!</para>
  <para>Second Line</para>
  <para><para>Invalid</para></para>
</doc>

これは、xml val --embed(埋め込まれたDTDによるチェック)かxml --dtd (外部DTDによるチェック)を使う。

$ xml val --embed dtd-valid.xml
dtd-valid.xml - valid

$ xml val --embed dtd-invalid.xml
dtd-invalid.xml:9: element para: validity error : /
Element para was declared #PCDATA but contains non text nodes
  <para><para>Invalid</para></para>
                                   ^
dtd-invalid.xml - valid

XSLTによる変換

最後は、XSLTによる変換。

<?xml version="1.0" encoding="utf-8" ?>
<doc>
  <para>Hello World!!</para>
  <para>Second Line</para>
</doc>
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="utf-8" />
  
  <xsl:template match="doc">
    <html>
      <head>
        <title>Test Page</title>
      </head>
      <body>
        <xsl:apply-templates />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="para">
    <p><xsl:apply-templates /></p>
  </xsl:template>
</xsl:stylesheet>

これは、xml tr を使う。

$ xml tr xslt.xsl doc.xml
<?xml version="1.0" encoding="utf-8"?>
<html><head><title>Test Page</title></head><body>
  <p>Hello World!!</p>
  <p>Second Line</p>
</body></html>

# あとは、XML-FOXSL-FOフォーマッタだけだ。