XMLマスターポイントレッスン
      ~ プロフェッショナル(アプリケーション開発)編 ~
第5回 XML Schemaによる妥当性の検証

インフォテリア株式会社  教育部 木村 達哉

今回は、「XMLマスター:プロフェッショナル(アプリケーション開発)」認定試験のセクション4で出題される、XML Schema関連問題のポイントについて解説します。セクション4では、XML Schemaに関する総合的な知識が要求されます。ここで紹介する問題、およびその解説を参考にして、XML Schemaに関する確かな知識を習得しておいてください。

セクション4のポイント

  セクション4では、XML Schemaの基本文法をしっかりと理解したうえで、名前空間を考慮したXMLスキーマの設計手法や、他のXMLスキーマをインクルード/インポートする方法など、幅広い知識を身に付けておく必要があります。以降では、出題されるものの中でも典型的な問題を例にとって解説します。

Javaによる妥当性検証

  XML Schema関連問題のポイントの話に入る前に、XMLスキーマに対するXML文書の妥当性検証をJavaで行う方法を確認しておきましょう。と言っても、これも前回説明したXSLT変換と同様、J2SE 5.0に含まれるXML処理用の標準API「JAXP(Java API for XML Processing)」を使えば、簡単に行うことができます。リスト1に示すのが、JAXPを用いて作成した、妥当性検証を行うプログラムの例です。

リスト1:Java(JAXP)を使用して妥当性検証を行うプログラム(XSDValidate.java)


import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException;

public class XSDValidate {
   public static void main(String[] args) {
      if (args.length == 0) {
         System.out.println(
            "usage: XSDValidate XML-file [XSD-schema]");
         return;
      }

      String xml = args[0];
      String xsd = null;

      if (args.length > 1) {
         xsd = args[1];
      }
 
      try {
         DocumentBuilderFactory dbf
            = DocumentBuilderFactory.newInstance();
                                     --
         dbf.setNamespaceAware(true); 
         dbf.setValidating(true);    (2)

         dbf.setAttribute(
            "http://java.sun.com/xml/jaxp/properties/schemaLanguage",
            "http://www.w3.org/2001/XMLSchema"); 
                                     --

         if (xsd != null) {
            dbf.setAttribute(
               "http://java.sun.com/xml/jaxp/properties/schemaSource",
               xsd);
         }
 
         DocumentBuilder db = dbf.newDocumentBuilder();
         db.setErrorHandler(new ErrorHandler() {
            public void error(SAXParseException exception) {
               System.out.println(
                 "Error: URI=" + exception.getSystemId()
                  + ", Line=" + exception.getLineNumber()
                  + ", Column=" + exception.getColumnNumber());
               System.out.println(exception.getMessage());
               System.out.println();
            }
            public void fatalError(SAXParseException exception) {}
            public void warning(SAXParseException exception) {}
         });
         db.parse( xml );     (1)
         System.out.println("妥当性の検証を行いました");
      } catch (Exception e) {
         System.out.println(e);
      }
   }
}

  このプログラムは、第1引数に指定されたXML文書が、第2引数に指定されたXMLスキーマに対して妥当か否かを検証し、結果を出力します。ただし、このとき、XMLスキーマへの参照(属性noNamespaceSchemaLocation、またはschemaLocation)がXML文書に直接記述されている場合は、第2引数を省略することが可能です。妥当性検証を実行した結果、検証エラーがない場合は「妥当性の検証を行いました」というメッセージを出力し、検証エラーがある場合は、エラー・メッセージ(エラーが検出されたファイル名と、エラーが発生した行とカラム、エラーの内容を示すメッセージ)を出力します。

  リスト1からもわかるように、JAXPを用いて妥当性の検証を行う際には、クラスjavax.xml.parsers.DocumentBuilderのインスタンスを生成し、メソッドparseを実行します(リスト1-(1))。同クラスのインスタンスを生成するには、先にファクトリ・クラスであるjavax.xml.parsers.DocumentBuilderFactoryのインスタンスを生成しておく必要があります。生成したDocumentBuilderFactoryインスタンスに対しては、あらかじめメソッドsetValidatingやsetAttributeを呼び出し、妥当性検証に必要な設定を行っておきます(リスト1-(2))。

  なお、XML Schemaについての理解を深めるうえでは、XML Schemaで書かれた既存のXMLスキーマを眺めるだけでなく、自分でさまざまなXMLスキーマを作成し、実際にXML文書の妥当性検証を行ってみることをお勧めします。

  それでは、XML Schema関連の問題のポイントに話を進めましょう。以降では、XML Schemaに関する例題/解答を提示するとともに、その問題でポイントとなる個所を解説していきます。

●XML Schema関連の出題例――(1)

  次の《XML文書》の妥当性検証を行った結果として、正しいものを選択してください。ただし、XMLパーサは、XML Schemaの属性noNamespaceSchemaLocation、属性schemaLocationを正しく処理できるものとします。

《XML文書》

<Rensai
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="rensai.xsd">
  <Title>XMLマスターポイントレッスン ~ プロフェッショナル(アプリケーション開発)編 ~ </Title>
  <Content xmlns="urn:xmlmaster:sample">
    <SubTitle>DOM/SAXの基本仕様</SubTitle>
    <SubTitle>DOM/SAXプログラミング</SubTitle>
  </Content>
</Rensai>

《rensai.xsd》

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:import namespace="urn:xmlmaster:sample"
    schemaLocation="content.xsd" />
 
  <xs:element name="Rensai" type="rensaiType" />
  <xs:complexType name="rensaiType">
    <xs:sequence>
      <xs:element name="Title" type="xs:string" />
      <xs:element ref="sam:Content" xmlns:sam="urn:xmlmaster:sample" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

《content.xsd》

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="urn:xmlmaster:sample"
  xmlns:sam="urn:xmlmaster:sample">
 
  <xs:element name="Content" type="sam:contentType" />
  <xs:complexType name="contentType">
    <xs:sequence>
      <xs:element name="SubTitle" type="xs:string" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

●選択肢
A.
妥当である

B.
XML文書の記述が不適切であるため、《XML文書》の「xsi:noNamespaceSchemaLocation="rensai.xsd"」を処理する際にエラーが発生する

C.
XMLスキーマの記述が不適切であるため、《rensai.xsd》の要素xs:importを処理する際にエラーが発生する

D.
処理エラーは発生しないが、妥当なXML文書ではない

●解答
D

●解説
  この問題では、名前空間を考慮したXMLスキーマの設計、および他のXMLスキーマのインポートに関する理解度が問われています。それでは、選択肢で「不適切」とされている部分から順に《XML文書》、および《rensai.xsd》、《content.xsd》の内容を見ていきましょう。

  まず、選択肢Bでは、「『xsi:noNamespaceSchemaLocation="rensai.xsd"』を処理する際にエラーが発生する」としています。この属性xsi:noNamespaceSchemaLocationは、XML文書と任意のXMLスキーマとを関連づけるものです。つまり、例題で提示されている《XML文書》では、《XML文書》とrensai.xsdを関連づけていることになります。そして、この記述に誤りはありません。したがって、選択肢Bは不正解です。

  次に、選択肢Cでは、要素xs:importの記述に問題があるという趣旨のことが書かれています。XMLスキーマに要素xs:importを記述することにより、他のXMLスキーマをインポートすることができます。例題の《rensai.xsd》では、この要素xs:importを使い、《content.xsd》をインポートする指定を行っていますが、この記述にも誤りはありません。よって、選択肢Cも不正解ということになります。

  選択肢を見る限り、後はこの《XML文書》がXMLスキーマに対して妥当か否かが正答につながるようです。では、その点について見ていきましょう。

  XML Schemaでは、あるXMLスキーマに他のXMLスキーマをインポートした場合、そのXMLスキーマ内で定義された要素を使うことができます。この仕組みを利用して、《rensai.xsd》では、インポートした《content.xsd》に定義されている要素Contentを使ってスキーマを定義しているわけです。具体的には、《rensai.xsd》では、要素Rensaiの後に、要素Title、要素Contentの順に子要素を定義しています。

  一方、《content.xsd》では、《rensai.xsd》で使われている要素Contentが定義されています。《content.xsd》には「targetNamespace="urn:xmlmaster:sample"」と書かれているので、「要素Contentは、名前空間urn:xmlmaster:sampleに属している」ということがわかります。また、要素Contentには、子要素としてSubTitleが定義されています。

  ここで、要素SubTitleが属する名前空間に注意してください。実は要素SubTitleは、要素xs:complexType内でローカルに宣言されたものであり、要素Contentの名前空間であるurn:xmlmaster:sampleには属していません。それにもかかわらず、提示された《XML文書》では、デフォルトの名前空間(urn:xmlmaster:sample)が使われています。つまり、《XML文書》中の要素Contentおよび要素SubTitleは、名前空間urn:xmlmaster:sampleに属するものとして書かれているのです。その結果、XML文書、XMLスキーマの双方に記述された要素SubTitleの名前空間が異なるため、妥当性検証を実行すると「妥当ではない」という結果になるのです。

  例題のように要素xs:importを使用する場合には、「必ず異なる名前空間のXMLスキーマをインポートする」というルールがあります。他のXMLスキーマの取り込み(インクルード)には、ほかに要素xs:includeも使えますが、こちらを使用する場合は、必ず同じ名前空間に属するXMLスキーマを指定します。両者のこうした違いはきちんと理解しておきましょう。

  そのほか、出題頻度が高く、実務上も重要度の高い事項を以下に列挙しておくので、これらに関してもしっかりと学んでおいてください。

●要素xs:any、要素xs:anyAttributeによる任意要素、任意属性の指定
●要素xs:redefineによるスキーマ定義の書き換え
●要素xs:elementの属性substitutionGroupを使用した代替要素の指定
●要素xs:group、要素xs:attributeGroupによる要素グループ、属性グループの作成
●要素xs:unique、要素xs:key、要素xs:keyrefによる一意的な値の指定

●XML Schema関連の出題例――(2)

  次の《XML文書》の妥当性検証を行った結果として、正しいものを選択してください。ただし、XMLパーサは、XML Schemaの属性noNamespaceSchemaLocation、属性schemaLocationを正しく処理できるものとします。

《XML文書》

<Rensai
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="rensai.xsd"
  xsi:schemaLocation="urn:xmlmaster:sample content.xsd">
  <Title>XMLマスターポイントレッスン ~ プロフェッショナル(アプリケーション開発)編 ~ </Title>
  <Content xmlns="urn:xmlmaster:sample">
    <SubTitle>DOM/SAXの基本仕様</SubTitle>
    <SubTitle>DOM/SAXプログラミング</SubTitle>
  </Content>
</Rensai>

《rensai.xsd》

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Rensai" type="rensaiType" />
  <xs:complexType name="rensaiType">
    <xs:sequence>
      <xs:element name="Title" type="xs:string" />
      <xs:any />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

《content.xsd》

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="urn:xmlmaster:sample"
  xmlns:sam="urn:xmlmaster:sample">
  <xs:element name="Content" type="sam:contentType" />
  <xs:complexType name="contentType">
    <xs:sequence>
      <xs:element name="SubTitle" type="xs:string" maxOccurs="unbounded" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

●選択肢
A.
妥当である

B.
XML文書の記述が不適切であるため、《XML文書》の「xsi:schemaLocation="urn:xmlmaster:sample content.xsd"」を処理する際にエラーが発生する

C.
XMLスキーマの記述が不適切であるため、《rensai.xsd》の要素anyを処理する際にエラーが発生する

D.
処理エラーは発生しないが、妥当ではない

●解答
D

●解説
  こちらも、選択肢で「不適切」とされている部分から順に《XML文書》、および《rensai.xsd》、《content.xsd》の内容を見ていきましょう。

  まず、選択肢Bでは、「『xsi:schemaLocation="urn:xmlmaster:sample content.xsd"』を処理するときにエラーが発生する」としています。この属性schemaLocationは、XML文書中の名前空間に属している要素と、XMLスキーマとを関連づけるためのものです。つまり、例題で提示された《XML文書》では、名前空間urn:xmlmaster:sampleに属している要素と、《content.xsd》を関連づけていることになります。そして、この記述に誤りはありません。したがって、選択肢Bは不正解です。

  続いて、選択肢Cでは、要素anyを処理する際にエラーが発生するとしています。要素anyは、それが書かれた位置に任意の要素が出現することを示すものです。

  《rensai.xsd》では、《XML文書》中の名前空間に属さない要素Rensaiが定義されています。さらに、その子要素としてTitleとany(すなわち、任意の要素)が定義されているわけです。ここで、《rensai.xsd》中の要素anyの記述形式などに、誤っている部分はありません。よって、選択肢Cも不正解です。

  となると、先の例題と同様、後はこの《XML文書》が妥当か否かが正答につながるようです。では、《XML文書》の妥当性について見ていきましょう。

  要素anyには、属性namespaceを記述することができます。同属性を書くことにより、任意の要素の名前空間に制約を与えられるのです。例えば、「namespace="##any"」と記述すれば、任意の名前空間を持つ要素を指定することができ、「namespace="urn:xmlmaster:javaworld"」と書けば、名前空間がurn:xmlmaster:javaworldである要素を指定することができるといった具合です。なお、例題のように属性namespaceを省略した場合、デフォルト値として「##any」が適用されます。

  さらに、要素anyには、属性processContentsを記述することもできます。この属性を使うことで、任意の要素の妥当性検証を行うか否かを指定することが可能です。この属性の値には、以下の3つのうち、いずれかを記述します。

strict:妥当性検証を行う
skip:妥当性検証を行わない
lax:XMLスキーマが見つかれば妥当性検証を行う。見つからなければ行わない

  例題のように、属性processContentsを省略した場合のデフォルト値は、「strict」となります。

  以上を踏まえると、《XML文書》中に、任意の要素として要素Contentが記述されていること自体に問題はありません。ただし、この場合、要素Content以下の妥当性検証も行われることになります。ここで問題となるのは、《XML文書》中の要素Contentの子要素SubTitleの名前空間は「urn:xmlmaster:sample」ですが、一方の《content.xsd》に書かれている要素SubTitleが属する名前空間はないということです。つまり、XML文書とXMLスキーマとで要素SubTitleが属する名前空間が異なるため、結果は「妥当ではない」ということになります。したがって、選択肢Dが正解です。


ページトップへ▲

XMLマスターポイントレッスン ~ プロフェッショナル(アプリケーション開発)編 ~ 記事一覧へ戻る

HOMEへ戻る