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が正解です。