あるお客様からどうしてもDITAでMathMLを使いたいという話がありました.マニュアルで数式を使わなければならないからです.確かに世界を見渡せばいろいろ苦労して使っていらっしゃる方はいるみたいです.
http://tech.groups.yahoo.com/group/dita-users/message/21204
http://tech.groups.yahoo.com/group/dita-users/message/21213
http://tech.groups.yahoo.com/group/dita-users/message/20164
http://tech.groups.yahoo.com/group/dita-users/message/21213
http://tech.groups.yahoo.com/group/dita-users/message/20164
DITAの仕様では、<foreign>という要素が、「コンテンツはなんでもいいよ!」ということになっていて事実上MathMLとかSVGのコンテナになっています.でも実際にDTDで運用しようとすると、MathMLやSVGのDTDを用意してやらなければならずたぶん大変です.いわゆる「特殊化」をやらなければならないからです.DITAのDTDでは、<foreign>の箇所は、
<!ENTITY % foreign.content "ANY">
<!ELEMENT foreign %foreign.content;>
<!ELEMENT foreign %foreign.content;>
とはなっていますが、ANYは「DTDで宣言されたすべての要素を含むことができる」というもので、宣言もされていないMathMLの要素を書くことはできません.実際DITA-OTのディストリビューションにはMathMLのDTDなどついてこないのです.自力でDTDをつけて修正しなければなりません.やっぱりDTDは大変です.もっと簡便な方法がないかな~といろいろ考えました.XML Schemaの方を調べてみるとこうなっています.
<xs:element name="foreign">
<xs:annotation>
<xs:documentation>...省略...</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:complexContent>
<xs:extension base="foreign.class">
<xs:attribute ref="class" default="- topic/foreign "/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:complexType name="foreign.class">
<xs:sequence>
<xs:group ref="foreign.content"/>
</xs:sequence>
<xs:attributeGroup ref="foreign.attributes"/>
</xs:complexType>
<xs:group name="foreign.content">
<xs:sequence>
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any processContents="skip"/>
</xs:choice>
</xs:sequence>
</xs:sequence>
</xs:group>
<xs:annotation>
<xs:documentation>...省略...</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:complexContent>
<xs:extension base="foreign.class">
<xs:attribute ref="class" default="- topic/foreign "/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:complexType name="foreign.class">
<xs:sequence>
<xs:group ref="foreign.content"/>
</xs:sequence>
<xs:attributeGroup ref="foreign.attributes"/>
</xs:complexType>
<xs:group name="foreign.content">
<xs:sequence>
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any processContents="skip"/>
</xs:choice>
</xs:sequence>
</xs:sequence>
</xs:group>
ここの<xs:any processContents="skip"/>がミソですね.パーサーは<foreign>の中を検証しないのです.つまり何を書いてもOKのはずです.(まあ整形式くらいは必要でしょうが...)
そこで、次のようなtopicを作ってみました.今までは文書型宣言をつけているのが常識でしたが、今度はXMLスキーマのnoNamespaceSchemaLocation属性の指定です.mapも同じように変更しました.
<?xml version="1.0"?>
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:oasis:names:tc:dita:xsd:topic.xsd"
id="topic_9940DF80A456CF4C97AB5560">
<title>Foreign testing</title>
<shortdesc>The foeign (<foreign>) element allows the introduction of non-DITA content, for example, MathML, SVG, or Rich Text Format (RTF). </shortdesc>
<body>
<section>
<title>Foreign sample for MathML</title>
<foreign>
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML">
<mrow><mo>[</mo> <mrow>
...MathMLは長いので省略.
</mrow> <mo>]</mo></mrow>
</math>
</foreign>
</section>
</body>
</topic>
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:oasis:names:tc:dita:xsd:topic.xsd"
id="topic_9940DF80A456CF4C97AB5560">
<title>Foreign testing</title>
<shortdesc>The foeign (<foreign>) element allows the introduction of non-DITA content, for example, MathML, SVG, or Rich Text Format (RTF). </shortdesc>
<body>
<section>
<title>Foreign sample for MathML</title>
<foreign>
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML">
<mrow><mo>[</mo> <mrow>
...MathMLは長いので省略.
</mrow> <mo>]</mo></mrow>
</math>
</foreign>
</section>
</body>
</topic>
あとはスタイルシートです.XSL-FOばかりですみませんが、単純に<foreign>の中をチェックして、MathMLだったらfo:instream-foreign-objectを生成するようにしてみました.
<xsl:template match="*[contains(@class, ' topic/foreign ')]">
<xsl:variable name="childElem" select="child::*[1]" as="element()*"/>
<xsl:if test="exists($childElem) and (namespace-uri($childElem)='http://www.w3.org/1998/Math/MathML';)">
<fo:instream-foreign-object content-type="content-type:application/mathml+xml">
<xsl:copy-of select="$childElem"/>
</fo:instream-foreign-object>
</xsl:if>
</xsl:template>
<xsl:variable name="childElem" select="child::*[1]" as="element()*"/>
<xsl:if test="exists($childElem) and (namespace-uri($childElem)='http://www.w3.org/1998/Math/MathML';)">
<fo:instream-foreign-object content-type="content-type:application/mathml+xml">
<xsl:copy-of select="$childElem"/>
</fo:instream-foreign-object>
</xsl:if>
</xsl:template>
これでDITA-OTを通してPDFにした結果が以下のイメージです.おお!何とかMathMLが描画できています.
XML SchemaってDTDより楽ですね.お客様にこの方法を提案してみようと思います.