目次


ヒント: XSLTスタイルシートの空白を制御する

空白を除去する方法を理解することによって、望みどおりの文書を作成する

注:この記事の内容は、XSLTプロセッサー (XalanまたはSaxonanなど)、またはブラウザー・ベースのソリューション (Microsoft Internet ExplorerまたはMozillaなど) などに使用できます。

空白の除去の規則

XSLTプロセッサーは、変換を行なう前にスタイルシートとソース文書を分析して、空白ノードを適切に除去します。その後、文書を処理して、残りのノードから結果ツリーを作成します。

では、ここで基本的な変換を見てみましょう。ソース文書には、別のアプリケーションで処理できるように、他のXML構造に変換される生のFAQ情報が入っています。

リスト1. ソース文書
<?xml version="1.0"?>
<?xml-stylesheet href="style.xsl" type="text/xsl"?>
<faqs>
   <question>
      <questiontitle>Output DOM object?</questiontitle>
      <questiontext>
        Is there an easy way to send a DOM Document to the screen?
        <address>confused@example.com</address>
      </questiontext>
      <answer>
          <answertext>
              <line>Yes, as a matter of fact, there is. </line>
              <line>All you have to do is transform the </line>
              <line>Document, but don't add a style sheet:</line>
          </answertext>
          <codesection><codeline>...</codeline>
          <codeline>  DOMSource source = new DOMSource(myDocObject);</codeline>
          <codeline>  StreamResult result = new StreamResult(System.out);</codeline>
          <codeline>  TransformerFactory transFactory = </codeline>
          <codeline>                         TransformerFactory.newInstance();</codeline>
          <codeline>  Transformer transformer = transFactory.newTransformer();</codeline>
          <codeline>  transformer.transform(source, result);</codeline>
          <codeline>...</codeline></codesection>       </answer>
   </question>
</faqs>

以下に示す、この変換のためのスタイルシートは、個々の行を結合することを意図していますが、最終的にはコード・セクションに空白を残します。

リスト2. 基本のスタイルシート
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<faqoutput>
    <info>
       <title>
         <xsl:value-of select="faqs/question/questiontitle"/>
       </title>
    </info>
    <xsl:apply-templates/>
</faqoutput>
</xsl:template>
<xsl:template match="question">
<issue><xsl:value-of select="questiontext"/></issue>
<solution><xsl:apply-templates select="answer"/></solution>
</xsl:template>
<xsl:template match="answertext">
<answered><xsl:apply-templates/></answered>
</xsl:template>
<xsl:template match="codesection">
<code>
<xsl:apply-templates/>
</code>
</xsl:template>
</xsl:stylesheet>

文書を変換すると、空白を除去するデフォルトの規則が適用され、以下のような結果になります。

リスト3. 結果
<?xml version="1.0" encoding="UTF-8"?>
<faqoutput><info><title>Output DOM object?</title></info>
   <issue>
        Is there an easy way to send a DOM Document to the screen?
        confused@wisconsin.com
</issue><solution>
          <answered>
Yes, as a matter of fact, there is.
              All you have to do is transform the
              Document, but don't add a style sheet:
          </answered>
          <code>...
            DOMSource source = new DOMSource(myDocObject);
            StreamResult result = new StreamResult(System.out);
            TransformerFactory transFactory = TransformerFactory.newInstance();
            Transformer transformer = transFactory.newTransformer();
            transformer.transform(source, result);
          ...</code>
      </solution>
</faqoutput>

個々のテンプレート (たとえば、メインのテンプレート) 内の空白ノードは除去されていますが、ソース文書内のノード (たとえば、answertext 内のline 要素間) は残されていることに注目してください。こうした問題を解決するには、いくつかの方法があります。

ソース内の空白を制御する

プロセッサーが要素から空白を除去する場合、プロセッサーはまず最初にその要素が空白保存要素のリストにあるかどうかを確認します。デフォルトでは、すべてのソース・ノードがこのリストに追加されますが、特定のノードをxsl:strip-space 要素に追加することによって、リストから除去することができます。たとえば、questionまたはanswertext内の応答を圧縮するために、以下のようにしてquestion 要素からすべての空白を除去することができます。

リスト4. question要素からの空白の除去
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="question"/>
<xsl:template match="/">
<faqoutput>
    <info>
       <title>
...

必要であれば、空白除去リストを使用して、さらに他の要素名をelements 属性に追加できます。この強引な方法では、以下のようにすべての空白ノードが除去されます(訳注:紙面の都合上、適宜改行を入れています)。

リスト5. 除去の結果
<?xml version="1.0" encoding="UTF-8"?>
<faqoutput><info><title>Output DOM object?</title></info>
   <issue>
        Is there an easy way to send a DOM Document to the screen?
        confused@wisconsin.com</issue><solution><answered>Yes, as a matter of fa
ct, there is. All you have to do is transform the Document, but don't add a styl
e sheet:</answered><code>...  DOMSource source = new DOMSource(myDocObject);  St
reamResult result = new StreamResult(System.out);  TransformerFactory transFacto
ry =                          TransformerFactory.newInstance();  Transformer tra
nsformer = transFactory.newTransformer();  transformer.transform(source, result)
;...</code></solution>
</faqoutput>

皆さんは、依然としてquestionとaddress 要素の間、およびコード・セクション内に空白が残っていることにお気づきになるでしょう。混乱するかもしれませんが、上の例では空白文字自体ではなく空白ノード (訳注:空白文字列のみからなるテキストノード)を除去したということを思い出してください。テキスト・ノードに空白以外の文字が入っている場合、他の設定が適切であっても、プロセッサーはそのノードを除去しません。

一方、コード内の改行はすべて除去されています。これは望んでいたことではありません。空白保存要素のリストからある要素を除去した場合、以下のようにxsl:preserve-space 要素を使用してその子要素を空白保存要素リストに戻すことができます。

リスト6. 空白保存
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="question"/>
<xsl:preserve-space elements="codesection"/>
<xsl:template match="/">
<faqoutput>
    <info>
...

この変更の結果、codesection 要素は空白保存要素のリストに戻され、以下のように改行は保持されます。

リスト7. 保存の結果
<?xml version="1.0" encoding="UTF-8"?>
<faqoutput><info><title>Output DOM object?</title></info>
   <issue>
        Is there an easy way to send a DOM Document to the screen?
        confused@wisconsin.com</issue><solution><answered>Yes, as a matter of fa
ct, there is. All you have to do is transform the Document, but don't add a styl
e sheet:</answered><code>...
            DOMSource source = new DOMSource(myDocObject);
            StreamResult result = new StreamResult(System.out);
            TransformerFactory transFactory = TransformerFactory.newInstance();
            Transformer transformer = transFactory.newTransformer();
            transformer.transform(source, result);
          ...</code></solution>
</faqoutput>

さらに、スタイルシート内の空白を管理することによって、文書をもっと読みやすくすることができます。

スタイルシートへの空白の追加

プロセッサーがスタイルシートから空白ノードを除去する場合、デフォルトで空白保存要素のリストにあるのはxsl:text 要素だけです。text 要素は常に保存されるため、文書内に改行または空白を追加するのに役立ちます。

リスト8. xsl:textによる改行の追加
...
<xsl:template match="question">
<issue><xsl:value-of select="questiontext"/></issue><xsl:text>
   </xsl:text><solution><xsl:apply-templates select="answer"/></solution>
</xsl:template>
...

空白保存要素のリストから個々の要素を除去できるのと同様に、以下に示すように、xml:space 属性を使用することによって、リストへの個々の要素の追加を個別に制御することができます。

リスト9. xml:spaceによる空白の制御
...
<xsl:template match="/">
<faqoutput><xsl:text>
    </xsl:text><infoxml:space="preserve">
       <titlexml:space="default">
         <xsl:value-of select="faqs/question/questiontitle"/>
       </title>
    </info>
    <xsl:apply-templates/>
</faqoutput>
</xsl:template>
...

この場合、title 要素の前後 の空白は保持されますが、title 要素内 の空白は除去されます。

リスト10. スタイルシート内の空白の制御の結果
<?xml version="1.0" encoding="UTF-8"?>
<faqoutput>
    <info xml:space="preserve">
       <title xml:space="default">Output DOM object?</title>
    </info>
   <issue>
        Is there an easy way to send a DOM Document to the screen?
        confused@wisconsin.com</issue>
   <solution><answered>Yes, as a matter of fact, there is. All you have to do is
 transform the Document, but don't add a style sheet:</answered><code>...
            DOMSource source = new DOMSource(myDocObject);
            StreamResult result = new StreamResult(System.out);
            TransformerFactory transFactory = TransformerFactory.newInstance();
            Transformer transformer = transFactory.newTransformer();
            transformer.transform(source, result);
          ...</code></solution>
</faqoutput>

要約

スタイルシートまたはソース文書に適用される空白保存の規則を理解することによって、最終的な文書の形態をさらに細かく制御できるようになることでしょう。しかし、空白以外の文字を持つテキスト・ノード内から空白が除去されることはありません。


ダウンロード可能なリソース


関連トピック

  • W3CのXSLT 1.0勧告を参照してください。
  • XML関連の他の資料は、developerWorksのXMLゾーンで調べることができます。
  • XMLおよびその関連テクノロジーのIBM Certified Developer になる方法をお調べください。
  • この記事のようなXMLに関する情報を毎週受け取ることをお望みですか? developerWorksXML Tips newsletter をお申し込みください。
static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML
ArticleID=242725
ArticleTitle=ヒント: XSLTスタイルシートの空白を制御する
publish-date=11022002