<?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>
<?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>