JAXB その5

先週に引きつづき,今週もJAXBで使われるアノテーションを紹介していきます。今週は列挙型を修飾するアノテーションと,フィールド/プロパティを修飾するアノテーションです。

その後,実際にJavaのクラスからスキーマを生成させる方法を紹介します。

列挙型を修飾するアノテーション

列挙型は特殊なクラスなので,クラスを修飾するアノテーションはすべて使用することができます。それ以外に@XmlEnumと@XmlEnumValueが使用できます。

表1 列挙型を修飾するアノテーション
アノテーション名 説明/デフォルト値
@XmlEnum クラスをスキーマの型に対応づける
@XmlEnum(
  value=String.class
)
@XmlEnumValue 値をスキーマの型に対応づける
なし
@XmlType クラスをスキーマの型に対応づける
@XmlType(
  name="##default",
  propOrder={""},
  namespace="##default",
  factoryClass=DEFAULT.class,
  factoryMethod=""
)
@XmlRootElement クラスをスキーマの宣言に対応づける
@XmlRootElement(
  name="##default",
  namespace="##default"
)
@XmlAccessorType フィールド,プロパティの対応を決定する
@XmlAccesorType(
  namespace="http://www.w3.org/2001/XMLSchema",
  type=DEFAULT.class
)
@XmlAccessorOrder フィールド,プロパティの対応順序を決める
なし
@XmlEnum

@XmlEnumは,列挙型をXML Schemaで定義された型に対応づけるために使用します。デフォルトは文字列です。

例として血液型を表す列挙型を使用します。

@XmlEnum(String.class)
@XmlType
public enum BloodType {
    A, B, O, AB
}

@XmlEnumの要素に使用するクラスオブジェクトを指定します。上記のソースでは文字列(String.class)を使用しています。

文字列の場合,XML Schemaに対応するのはnameメソッドの戻り値です。たとえば,BloodType.AはBloodType.A.name()がスキーマで使用されます。

  <xs:simpleType name="bloodType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="A"/>
      <xs:enumeration value="B"/>
      <xs:enumeration value="O"/>
      <xs:enumeration value="AB"/>
    </xs:restriction>
  </xs:simpleType>

列挙型は,simpleTypeとenumerationで表されます。ここでは,@XmlEnum(String.class)と指定したので,文字列で表されています。

@XmlEnumの要素に文字列以外を使用したい場合,@XmlEnumValueと組み合わせて使用します。

たとえば,血液型を整数で表す場合には次のようにします。

@XmlEnum(Integer.class)
@XmlType
public enum BloodType {
    @XmlEnumValue("1") A,
    @XmlEnumValue("2") B,
    @XmlEnumValue("3") O,
    @XmlEnumValue("4") AB
}

@XmlEnumで使用するクラスを指定し,値をそのクラスの文字列表現で修飾します。

この列挙型に対応するXML Schemaを次に示します。

  <xs:simpleType name="bloodType">
    <xs:restriction base="xs:int">
      <xs:enumeration value="1"/>
      <xs:enumeration value="2"/>
      <xs:enumeration value="3"/>
      <xs:enumeration value="4"/>
    </xs:restriction>
  </xs:simpleType>

型がintになり,@XmlEnumValueで指定した値が使用されていることが分かります。

フィールド/プロパティを修飾するアノテーション

フィールドもしくはプロパティを修飾するアノテーションを表2に示しました。以下,よく使用されるアノテーションを少し詳しく説明していきます。

表2 フィールド/プロパティを修飾するアノテーション
アノテーション名 説明/デフォルト値
@XmlElement フィールド/プロパティを,その名前に由来するXML要素に対応づける
@XmlElement (
  name = "##default",
  nillable = false,
  namespace = "##default",
  type = DEFAULT.class,
  defaultValue = "\u0000"
) 
@XmlElements @XmlElementのコンテナアノテーション
なし
@XmlElementRef フィールド/プロパティを,その型に由来するXML要素に対応づける
@XmlElementRef (
  name = "##default",
  namespace = "##default",
  type = DEFAULT.class,
) 
@XmlElementRefs @XmlElementRefのコンテナアノテーション
なし
@XmlElementWrapper XML表現の周りにラッパー要素を生成する
@XmlElementWrapper (
  name = "##default",
  namespace = "##default",
  nillable = false
) 
@XmlAnyElement フィールド,プロパティをanyに対応づける
@XmlAnyElement (
  lax = false,
  value = W3CDomHandler.class
) 
@XmlAttribute フィールド,プロパティを属性に対応づける
@XmlAttribute (
  name = ##default,
  required = false,
  namespace = "##default"
) 
@XmlAnyAttribute フィールド,プロパティをワイルドカード属性に対応づける
なし
@XmlTransient フィールド,プロパティをXMLに対応づけないようにする
なし
@XmlValue フィールド,プロパティをcomplexTypeのsimpleContentもしくはsimpleTypeに対応づける
なし
@XmlIDREF フィールド,プロパティをXML IDREFに対応づけます
なし
@XmlList フィールド,プロパティをリストsimpleTypeに対応づける
なし
@XmlMixed ミックスコンテンツをサポートするために,複数の値をとるフィールド,プロパティをマークする
なし
@XmlMimeType フィールド,プロパティをMIME型に対応づける
なし
@XmlAttachmentRef MIMEコンテンツへのURI参照であることを示すため,フィールド,プロパティをマークする
なし
@XmlInlineBinaryData base64エンコードされたバイナリデータにバインドされるデータ型に対して,XOPエンコーディングの考慮を無効にする
なし
@XmlSchemaType フィールド,プロパティの対応順序を決める
@XmlSchemaType(
  namespace="http://www.w3.org/2001/XMLSchema",
  type = DEFAULT.class 
)

@XmlElementで修飾されたfirst,lastはXMLの要素に対応づけられます。

  <xs:element name="name">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="first" type="xs:string" minOccurs="0"/>
        <xs:element name="last" type="xs:string" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

ここで,firstがnullの場合があるとしましょう。そのような場合,@XmlElementのnillable要素を使用します。nullを使えるようにする場合はnillableの値をtrue,nullを許容しない場合はfalseにします。nillabel要素を指定しない場合,nillableの値はfalseになります。

@XmlRootElement
@XmlType(name="")
public class Name {
    @XmlElement(nillable = true)
    String first;
 
    @XmlElement(nillable = false)
    String last;
}

ここでは,firstはnillableをtrueに,lastはfalseにしてみました。これに対応するXML Schemaは次のようになります。

  <xs:element name="name">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="first" type="xs:string" nillable="true" minOccurs="0"/>
        <xs:element name="last" type="xs:string" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

firstのみ,要素の定義にnillable="true"が付加されました。

要素に必ず値を代入しなくてはならない場合は,required要素で指定します。required要素もnillable要素と同じように,指定しない場合はfalseと見なされます。

@XmlRootElement
@XmlType(name="")
public class Name {
    @XmlElement(nillable = true)
    String first;
 
    @XmlElement(required = true)
    String last;
}

対応するXML Schemaを次に示します。

  <xs:element name="name">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="first" type="xs:string" nillable="true" minOccurs="0"/>
        <xs:element name="last" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

minOccursが指定されていないことが分かります。

プロパティのデフォルト値を指定するには,defaultValue要素で指定します。

@XmlRootElement
@XmlType(name="")
public class Name {
    @XmlElement(defaultValue = "Yuichi")
    String first;
 
    @XmlElement(defaultValue = "Sakuraba")
    String last;
}

ここでは,firstのデフォルト値をYuichi,lastのデフォルト値をSakurabaにしました。

  <xs:element name="name">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="first" type="xs:string" default="Yuichi" minOccurs="0"/>
        <xs:element name="last" type="xs:string" default="Sakuraba" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

defaultValueで指定した値がdefault属性に対応していることが分かります。

@XmlElements

@XmlElementsは,複数の要素をXML SchemaにおけるcomplexTypeのchoiceに対応させます。

たとえば,座標を表すPointクラスで,座標値を整数と倍精度浮動小数で表せる場合を考えてみます。

@XmlRootElement
@XmlType(name="")
public class Point {
 
    @XmlElements({
        @XmlElement(name="ix", type=Integer.class),
        @XmlElement(name="dx", type=Double.class)
    })
    Number x;
 
    @XmlElements({
        @XmlElement(name="iy", type=Integer.class),
        @XmlElement(name="dy", type=Double.class)
    })
    Number y;
}

@XmlElementsの要素は,@XmlElementの配列です。xは整数の場合,ixというXMLの要素で表します。同様に,倍精度浮動小数の場合,dxというXML要素です。ixでもdxでも同じように扱うため,xの型はNumberクラスにしてあります。

これに対応するXML Schemaを次に示します。

  <xs:element name="point">
    <xs:complexType>
      <xs:sequence>
        <xs:choice minOccurs="0">
          <xs:element name="ix" type="xs:int"/>
          <xs:element name="dx" type="xs:double"/>
        </xs:choice>
        <xs:choice minOccurs="0">
          <xs:element name="iy" type="xs:int"/>
          <xs:element name="dy" type="xs:double"/>
        </xs:choice>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

x,yがともにchoiceに対応づけられます。xは,要素名をixとしたときは整数,dxとしたときは倍精度浮動小数となります。

プロパティがコレクションの場合も同様に,@XmlEmementsで修飾することができます。

@XmlRootElement
@XmlType(name="")
public class Point {
    @XmlElements({
        @XmlElement(name="ix", type=Integer.class),
        @XmlElement(name="dx", type=Double.class)
    })
    List<? extends Number> listX;
  
    @XmlElements({
        @XmlElement(name="iy", type=Integer.class),
        @XmlElement(name="dy", type=Double.class)
    })
    List<? extends Number> listY;
}

listX,listYの要素がIntegerオブジェクトとDoubleオブジェクトの場合があるため,赤字で示したようにジェネリクスでどちらでも扱えるように指定してあります。

XML Schemaを次に示します。

  <xs:element name="point">
    <xs:complexType>
      <xs:sequence>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="ix" type="xs:int"/>
          <xs:element name="dx" type="xs:double"/>
        </xs:choice>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="iy" type="xs:int"/>
          <xs:element name="dy" type="xs:double"/>
        </xs:choice>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

maxOccurs属性が指定されたことが分かります。

来週説明するXmlAdapterを使用すると,ユーザーが定義したクラスでも同様のことを行なうことができます。

@XmlElementWrapper

@XmlElementWrapperは,フィールド/プロパティに対応したXML要素を含むラッパー要素を生成します。このアノテーションは,コレクションや配列で使用することが可能です。

たとえば,アルバムの中にソングが複数あるクラスを考えます。

@XmlRootElement
@XmlType(name="")
public class Album {
    @XmlElement(name = "song")
    List<String> songs;
}

このクラスに対応するXMLドキュメントは次のようになります。

<album>
  <song>Tell Me Why</song>
  <song>After the Gold Rush</song>
      ......
</album>

これに対し,次のように<song>タグを子要素として持つ,<songs>タグを挿入したいと考えます。

<album>
  <songs>
    <song>Tell Me Why</song>
    <song>After the Gold Rush</song>
        ......
  </songs>
</album>

この<songs>タグがラッパー要素にあたります。このラッパー要素に対応づけたクラスは次のようになります。

@XmlRootElement
@XmlType(name="")
public class Album {
    @XmlElementWrapper(name = "songs")
    @XmlElement(name = "song")
    List<String> songs;
}

赤字で示したように,@XmlElementWrapperを付け加えています。name要素でラッパー要素の名前を指定します。デフォルトでは,name要素はプロパティ名に対応づけられます。したがって,上記の例ではname要素を指定する必要はないのですが,分かりやすさのために書いてみました。

これに対応するXML Schemaを以下に示します。

  <xs:element name="album">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="songs" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="song" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

song要素を子要素として持つ,songs要素が追加されています。

@XmlAttribute

@XmlAttributeは,フィールド/アトリビュートをXMLの属性に対応づけます。

@XmlRootElement
@XmlType(name="")
public class Name {
    @XmlAttribute
    String first;
  
    @XmlAttribute 
    String last;
}

このクラスに対応するXML Schemaを次に示します。

  <xs:element name="name">
    <xs:complexType>
      <xs:sequence/>
      <xs:attribute name="first" type="xs:string"/>
      <xs:attribute name="last" type="xs:string"/>
    </xs:complexType>
  </xs:element>

firstとlastがattributeで定義されていることが分かります。

では,コレクションの場合はどうなるでしょうか。次のクラスを考えてみましょう。

@XmlRootElement
@XmlType(name="")
public class Album {
    @XmlAttribute
    String title;
 
    @XmlAttribute(name = "song")
    List<String> songs;
}

titleが単一の文字列であるのに対し,songsは複数の要素を保持することができます。これをXML Schemaにすると,次のようになります。

  <xs:element name="album">
    <xs:complexType>
      <xs:sequence/>
      <xs:attribute name="title" type="xs:string"/>
      <xs:attribute name="song">
        <xs:simpleType>
          <xs:list itemType="xs:string"/>
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>

songは,simpleTypeで表された属性に対応づけられています。

@XmlTransient

@XmlTransientは,フィールド/プロパティをXMLに対応づけないようにします。

@XmlRootElement
@XmlType(name="")
public class Name {
    @XmlTransient
    String first;
   
    @XmlElement
    String last;
}

このクラスではfirstを@XmlTransientで修飾し,lastを@XmlElementで修飾しています。このクラスから生成したXML Schemaを次に示します。

  <xs:element name="name">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="last" type="xs:string" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

スキーマにはfirstの定義が含まれていません。このように,@XmlTransientで修飾することにより,XMLへの対応付けを抑制できます。

@XmlValue

@XmlValueはフィールド/プロパティをcomplexTypeにおけるsimpleContent,もしくはsimpleTypeに対応づけます。

なお,@XmlValueで修飾できるフィールド/プロパティは1つだけです。また,@XmlValueで修飾されたフィールド/プロパティを持つクラスは,@XmlElementを使うことはできません。

@XmlRootElement
@XmlType(name="")
public class Album {
    @XmlValue
    String title;
}

ここでは,titleを@XmlValueで修飾しています。XML Schemaは次のようになります。

  <xs:element name="album">
    <xs:simpleType>
      <xs:restriction base="xs:string"/>
    </xs:simpleType>
  </xs:element>

album要素がsimpleTypeで定義されました。

では,@XmlValueで修飾する対象がコレクションもしくは配列の場合はどうなるでしょうか。

@XmlRootElement
@XmlType(name="")
public class Album {
    @XmlAttribute
    String title;
 
    @XmlValue
    List<String> songs;
}

対応するXML Schemaを次に示します。

  <xs:element name="album">
    <xs:complexType>
      <xs:simpleContent>
        <xs:extension base="xs:string">
          <xs:attribute name="title" type="xs:string"/>
        </xs:extension>
      </xs:simpleContent>
    </xs:complexType>
  </xs:element>

赤字で示したようにalbum要素がsimpleContentで定義されました。

ここで紹介した以外にも,XmlAdapterやObjectFactoryで使用するアノテーションがありますが,ここでは省略します。

Javaクラスからスキーマを生成する

先週から紹介してきたアノテーションを使用し,クラスからスキーマを生成してみましょう。

スキーマの生成にはschemagenコマンドを使用します。

例として,次のクラスからスキーマを生成してみます。

package net.javainthebox.music;

import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
 
@XmlRootElement
@XmlType(name="")
public class Album {
    @XmlAttribute
    String title;
  
    @XmlElementWrapper(name = "songs")
    @XmlElement(name = "song")
    List<String> songs;
}

名前空間を扱うために,パッケージの定義も行ないます。パッケージの定義は先週解説したように,package-info.javaで行ないます。

// package-info.java
    
@javax.xml.bind.annotation.XmlSchema(
    namespace = "http://www.javainthebox.net/music",
    elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED
)
package net.javainthebox.music;

これで準備は整いました。schemagenでスキーマを生成してみましょう。

schemagenの使い方は簡単です。オプションとして,スキーマを生成させるためのソースファイルを並べていくだけです。

schemagenは名前空間ごとにスキーマを出力します。現状ではschemagenはschema1.xsd,schema2.xsdのようなファイル名となり,これを変更することはできません。

まずはLinuxでやってみましょう。

[sakuraba]$ schmagen net/javainthebox/music/*.java
注:Writing schema1.xsd
 
[sakuraba]$

生成したスキーマschema1.xsdは次のようになりました。なお,見やすくするために,整形をほどこしてあります。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema elementFormDefault="qualified" version="1.0"
        targetNamespace="http://www.javainthebox.net/music"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="album">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="songs" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="song" type="xs:string"
                          minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
      <xs:attribute name="title" type="xs:string"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

このようにスキーマを生成することができました。

同じようにWindowsでもやってみましょう。

C:\jaxb>schmagen net\javainthebox\music\*.java
アプリケーションで例外が発生しました (1.6.0_06)。Bug Parade に同じバグが登録され
ていないことをご確認の上、Java Developer Connection (http://java.sun.com/webapps
/bugreport) にてバグの登録をお願いいたします。 レポートには、そのプログラムと下
記の診断内容を含めてください。ご協力ありがとうございます。
java.lang.NullPointerException
        at com.sun.tools.apt.main.CommandLine.parse(CommandLine.java:42)
        at com.sun.tools.apt.main.Main.compile(Main.java:775)
             <<以下、省略>>

NullPointerException例外が発生してしまいました。

schemagenは内部でjavacをコールして,ソースのコンパイルを行なっています。しかし,コンパイルに必要なtools.jarがクラスパスに含まれていないため,このような例外が発生してしまいます注1

これを解決するためには,-cpもしくは-classpathオプションを使用して,tools.jarをクラスパスに含めるようにします。tools.jarは,JDKをインストールしたディレクトリの直下にあるlibディレクトリに配備されています。

したがって,次のようにschemagenを実行します。

C:\jaxb>schmagen -cp "C:\Program Files\Java\jdk1.6.0_06\lib\tools.jar;. net\jav
ainthebox\music\*.java
注:Writing C:\jaxb\schema1.xsd

schemagenのコマンド行が2行になっていますが,実際には1行で入力します。

このようにtools.jarを含めることで,正しくスキーマを生成することが可能になります。

これで,JavaのクラスからXMLのスキーマを生成できるようになりました。今まで紹介したことを含めると,JavaのクラスとXMLのスキーマの相互変換が可能になったわけです。

さて,来週はJAXBのバインディングをカスタマイズする方法を紹介します。お楽しみに。

 

注1 このバグはすでにBug Databaseに登録されているのですが(BugID: 6510966),まだ修正されていないようです。




Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值