<?xml version="1.0" encoding="UTF-8"?><project>
<modelVersion>4.0.0</modelVersion>
<groupId>Jaxb2Exam</groupId>
<artifactId>Jaxb2Exam</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description></description>
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>src/main/resources/schema</schemaDirectory>
<generateDirectory>src/main/java/</generateDirectory>
<generatePackage>com.snail.exam.jaxb.object</generatePackage>
<!-- これを入れないと src/main/java/ 以下を全て削除されてしまう -->
<removeOldOutput>false</removeOldOutput>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Maven 2 Repository</name>
<url>http://download.java.net/maven/2</url>
</repository>
<repository>
<id>maven-repository.dev.java.net</id>
<name>Java.net Maven 1 Repository (legacy)</name>
<url>http://download.java.net/maven/1</url>
<layout>legacy</layout>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Maven 2 Repository</name>
<url>http://download.java.net/maven/2</url>
</pluginRepository>
<pluginRepository>
<id>maven-repository.dev.java.net</id>
<name>Java.net Maven 1 Repository (legacy)</name>
<url>http://download.java.net/maven/1</url>
<layout>legacy</layout>
</pluginRepository>
</pluginRepositories>
</project>
※ 追記(2011-04) : 最近は、<repositories><pluginRepositories> 要らないかも (JAXB2 自体は JDK6 の標準構成品。Maven plugin も Maven のセントラルレポジトリに入っている)<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:include schemaLocation="EmployeeInfo.xsd" />
<!-- JAXBテスト用 -->
<xsd:element name="Employee">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<!--
あってもなくても良い項目、maxOccurs を設定すると List になるので
minOccurs のみ定義する
-->
<xsd:element name="sex" type="sex_t" minOccurs="0" maxOccurs="1"/>
<!--
1つから3つの繰り返し
-->
<xsd:element name="phone" type="phonecode_t" minOccurs="1" maxOccurs="3"/>
<!--
0個以上の繰り返し
-->
<xsd:element name="post" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
<!--
複合項目の繰り返し
-->
<xsd:element name="qualification" type="qualification_t" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- JAXBUtilテスト用 -->
<!-- 型定義 -->
<!--
電話番号
<phone type="office">01-2345-6789</phone> の様に、XML構造の末端で
属性をもつ場合。(+ 型検証)
xsd:string を継承して、正規表現チェック機能を持った phonecode_base型
を作る。phonecode_base を継承して、属性をもった phonecode_t型を作る。
-->
<xsd:simpleType name="phonecode_base">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{2,3}-[0-9]{3,4}-[0-9]{3,4}"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="phonecode_t">
<xsd:simpleContent>
<xsd:extension base="phonecode_base">
<xsd:attribute name="type" type="xsd:string" use="optional"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<!--
性別
<sex type="m"/> の様に、属性のみがある場合
-->
<xsd:complexType name="sex_t">
<xsd:sequence>
</xsd:sequence>
<xsd:attribute name="type" type="xsd:string" use="optional"/>
</xsd:complexType>
<!--
資格
<qualification valid="true">
<title>3級陰陽師</title>
<date>1024-03-02</date>
<copy>0123456789ABCDEF</copy>
</qualification>
の様に、子要素と属性をもつ場合
-->
<xsd:complexType name="qualification_t">
<xsd:sequence>
<xsd:element name="title" type="xsd:string"/>
<xsd:element name="date" type="xsd:date"/>
<xsd:element name="copy" type="xsd:hexBinary"/>
</xsd:sequence>
<xsd:attribute name="valid" type="xsd:boolean" use="optional"/>
</xsd:complexType>
</xsd:schema>
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-520
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2008.11.06 at 12:39:37 午前 JST
//
package com.snail.exam.jaxb.object;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="sex" type="{}sex_t" minOccurs="0"/>
* <element name="phone" type="{}phonecode_t" maxOccurs="3"/>
* <element name="post" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
* <element name="qualification" type="{}qualification_t" maxOccurs="unbounded" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"name",
"sex",
"phone",
"post",
"qualification"
})
@XmlRootElement(name = "Employee")
public class Employee {
@XmlElement(required = true)
protected String name;
protected SexT sex;
@XmlElement(required = true)
protected List<PhonecodeT> phone;
protected List<String> post;
protected List<QualificationT> qualification;
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
/**
* Gets the value of the sex property.
*
* @return
* possible object is
* {@link SexT }
*
*/
public SexT getSex() {
return sex;
}
/**
* Sets the value of the sex property.
*
* @param value
* allowed object is
* {@link SexT }
*
*/
public void setSex(SexT value) {
this.sex = value;
}
/**
* Gets the value of the phone property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the phone property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getPhone().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link PhonecodeT }
*
*
*/
public List<PhonecodeT> getPhone() {
if (phone == null) {
phone = new ArrayList<PhonecodeT>();
}
return this.phone;
}
/**
* Gets the value of the post property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the post property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getPost().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link String }
*
*
*/
public List<String> getPost() {
if (post == null) {
post = new ArrayList<String>();
}
return this.post;
}
/**
* Gets the value of the qualification property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the qualification property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getQualification().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link QualificationT }
*
*
*/
public List<QualificationT> getQualification() {
if (qualification == null) {
qualification = new ArrayList<QualificationT>();
}
return this.qualification;
}
}
package com.snail.exam.jaxb;
import java.io.StringReader;
// javax.xml.bind は、JDK6 から標準添付
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import com.snail.exam.jaxb.object.Employee;
import com.snail.exam.jaxb.object.ObjectFactory;
import com.snail.exam.jaxb.object.PhonecodeT;
import com.snail.exam.jaxb.object.SexT;
public class Jaxb2Exam {
/**
* JAXBContext の singleton.
*/
private static JAXBContext singJaxbContext = null;
/**
* JAXBContext を作成する.
*
* <pre>
* JAXBContext の初期化には、非常にコストがかかるので、毎回作るのではなく、
* singleton を使い回す様にしなければならない。
* JAXBContext は、Thread Safe なので、複数の Thread から同時に使われても良い。
*
* (Marshaller / Unmarshaller は Thread Safe でないので、プールして使い回す
* ときにはそれなりの対処が必要)
*
* @return JAXBContext
* @throws JAXBException JAXBContextの作成に失敗
* @see https://jaxb.dev.java.net/guide/Performance_and_thread_safety.html
*
*/
private static JAXBContext getJAXBContext() throws JAXBException {
if (singJaxbContext == null) {
singJaxbContext = JAXBContext.newInstance("com.snail.exam.jaxb.object");
}
return singJaxbContext;
}
private static final String XML = "<?xml version=\"1.0\"?>" + "<Employee>"
+ "<name>たろう</name>" + "<sex type=\"male\"/>"
+ "<phone type=\"cell\">09012345678</phone>"
+ "<phone type=\"office\">0398765432</phone>" + "</Employee>";
/**
* @param args
*/
public static void main(final String[] args) {
try {
// 1) XML文書を JAXB Object に変換する
Unmarshaller unmarshaller = getJAXBContext().createUnmarshaller();
Object jaxbObject = unmarshaller.unmarshal(new StringReader(XML));
dumpBean((Employee) jaxbObject);
// 2) JAXB Object を作成する
ObjectFactory factory = new ObjectFactory();
Employee hanako = factory.createEmployee();
hanako.setName("はなこ");
SexT sex = factory.createSexT();
sex.setType("female");
hanako.setSex(sex);
PhonecodeT phone1 = factory.createPhonecodeT();
phone1.setType("skype");
phone1.setValue("05055555555");
hanako.getPhone().add(phone1);
PhonecodeT phone2 = factory.createPhonecodeT();
phone2.setType("daemon");
phone2.setValue("06066666666");
hanako.getPhone().add(phone2);
dumpBean(hanako);
// 3) JAXB Object をXMLに変換する
Marshaller marshaller = getJAXBContext().createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 改行とインデントを入れる
marshaller.setProperty(Marshaller.JAXB_ENCODING, "MS932");
System.out.println("-----");
marshaller.marshal(hanako, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
private static void dumpBean(final Employee bean) {
System.out.println("-----");
System.out.println("NAME :" + bean.getName());
System.out.println("SEX :" + bean.getSex().getType());
for (PhonecodeT phone : bean.getPhone()) {
System.out.println("PHONE:" + phone.getValue() + "(" + phone.getType() +")");
}
}
}
----- NAME :たろう SEX :male PHONE:09012345678(cell) PHONE:0398765432(office) ----- NAME :はなこ SEX :female PHONE:05055555555(skype) PHONE:06066666666(daemon) ----- <?xml version="1.0" encoding="MS932" standalone="yes"?> <Employee> <name>はなこ</name> <sex type="female"/> <phone type="skype">05055555555</phone> <phone type="daemon">06066666666</phone> </Employee>
package com.snail.exam.jaxb;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.ValidationEventLocator;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.xml.sax.SAXException;
import com.snail.exam.jaxb.object.Employee;
import com.snail.exam.jaxb.object.PhonecodeT;
public class Jaxb2ExamValidation {
private static JAXBContext singJaxbContext = null;
private static JAXBContext getJAXBContext() throws JAXBException {
if (singJaxbContext == null) {
singJaxbContext = JAXBContext.newInstance("com.snail.exam.jaxb.object");
}
return singJaxbContext;
}
private static final String XML =
"<?xml version=\"1.0\"?>\n"
+ "<Employee>\n"
+ " <name>おすぎ</name>\n"
+ " <sex type=\"male\"/>\n"
+ " <sex type=\"female\"/>\n"
+ "</Employee>\n";
public static void main(String[] args) {
try {
// 4) XML文書を XML Schema チェックしながら JAXB Object に変換する
Unmarshaller unmarshaller = getJAXBContext().createUnmarshaller();
// JAXB 1.x では、Schema検証に、unmarshaller.setValidating(true);
// を使っていたが、JAXB 2.x では、JAXP を使う
SchemaFactory sf = SchemaFactory
.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(ClassLoader
.getSystemResource("schema/Employee.xsd"));
unmarshaller.setSchema(schema);
// エラーを受け取るための変数
final boolean[] hasError = new boolean[] { false }; // <- tricky
final Map<Integer, String> errorMap = new HashMap<Integer, String>();
// エラーイベントハンドラを unmarshaller に設定する
// エラーが起きると errorMap に [行数,メッセージ] の形でエラー情報を格納する
//
// また、hasError[0] を true に書き換える( 無名class が操作できる外部の変数
// は final 属性のみなので、このような tricky な実装になる )
unmarshaller.setEventHandler(new ValidationEventHandler() {
public boolean handleEvent(ValidationEvent ve) {
if ((ve.getSeverity() == ValidationEvent.FATAL_ERROR)
|| (ve.getSeverity() == ValidationEvent.ERROR)) {
ValidationEventLocator locator = ve.getLocator();
hasError[0] = true;
errorMap.put(locator.getLineNumber(), ve.getMessage());
}
// 最後まで検証を行う
return true;
}
});
// XML文書の読み込み
Object jaxbObject = unmarshaller.unmarshal(new StringReader(XML));
if (hasError[0]) {
// エラーがあったので、その内容を表示する
System.out.println("INPUT XML IS NOT VALID:");
String[] lines = XML.split("\n");
for (int cnt = 0; cnt < lines.length; cnt++) {
System.out.println("L" + (cnt + 1) + ":" + lines[cnt]);
if (errorMap.containsKey(cnt + 1)) {
System.out.println("***ERROR " + errorMap.get(cnt + 1));
}
}
} else {
// エラーが無かったので、読み込み結果を表示する
dumpBean((Employee) jaxbObject);
}
} catch (JAXBException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
private static void dumpBean(final Employee bean) {
System.out.println("-----");
System.out.println("NAME :" + bean.getName());
System.out.println("SEX :" + bean.getSex().getType());
for (PhonecodeT phone : bean.getPhone()) {
System.out.println("PHONE:" + phone.getValue() + "(" + phone.getType()
+ ")");
}
}
}
INPUT XML IS NOT VALID: L1:<?xml version="1.0"?> L2:<Employee> L3: <name>おすぎ</name> L4: <sex type="male"/> L5: <sex type="female"/> ***ERROR cvc-complex-type.2.4.a: Invalid content was found starting with element 'sex'. One of '{phone}' is expected. L6:</Employee>L5 に、<sex> が現れているけど、XML Schema 的には <phone> が来るべきと言っています・・・たぶん。
<?xml version="1.0" encoding="UTF-8"?>
<fooResource
xmlns="http://foo.com/schemas/settings"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://foo.com/schemas/settings
http://foo.com/schemas/settings.xsd">
<config>
<version>5.1</version>
</config>
<text id="target">XXビル会議室</text>
<text id="RESVOK">{0}件予約しました。</text>
<text id="RESVPT">{0}件中{1}件を予約しました。内容を確認してください。</text>
<array id="prior">
<elem>192.168.96</elem>
<elem>192.168.97</elem>
</array>
<map id="rooms">
<elem key="room101">101会議室</elem>
<elem key="room102">102会議室</elem>
</map>
</fooResource>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://foo.com/schemas/settings"
xmlns:foo="http://foo.com/schemas/settings" >
<xsd:element name="fooResource">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="foo:config" minOccurs="0"
maxOccurs="1" />
<xsd:element ref="foo:text" minOccurs="0"
maxOccurs="unbounded" />
<xsd:element ref="foo:array" minOccurs="0"
maxOccurs="unbounded" />
<xsd:element ref="foo:map" minOccurs="0"
maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="config">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="version" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="text">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="id" type="xsd:string" />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="array">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="foo:elem" minOccurs="0"
maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="map">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="foo:elem" minOccurs="0"
maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="elem">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="key" type="xsd:string" use="optional"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>