`
code727
  • 浏览: 67289 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

JAXB2.0编组和解组实现

阅读更多

 

       JAXB是数据绑定框架之一,它在SOA的实现(如WebService)中被广泛的应用。这里所说的“绑定”是指XML文档与JAVA对象树之间的关联关系:可以根据JAVA对象树生成XML实例文档,这一过程叫做“编组”;而根据XML实例文档生成JAVA对象树的过程叫做“解组”。与JAXB类似的框架还有XMLBeans和Castor等。

       从另一方面来讲,JAXB也是XML解析方式之一。与SAX和DOM等不同的是,在解析的过程中操作的不再是DOM节点,取而代之的是JAVA对象树。

       JAXB最核心的接口和类有如下几个:

       1)javax.xml.bind.Marshaller:编组器。提供编组、验证、事件处理等操作;

       2)javax.xml.bind.Unmarshaller:解组器。提供解组、验证、事件处理等操作;

       3)javax.xml.bind.JAXBContext:JAXB客户端的入口。提供了实现 JAXB 所需的解组器、编组器和验证等。

       JAXB在核心的基础上提供了验证和事件处理的功能。

       验证的目的在于保证编组结果或用于解组的资源数据是符合相关模式(Schema或DTD)规范的。JAXB1.0验证实现采用的是JAXP早期的验证方法,即通过调用Marshaller和Unmarshaller实例对象的setValidating(boolean validating)来控制是否启用验证,不过这种方式在JAXB2.0中已被废弃,取而代之的是采用JAXP的验证分离方式,即通过调用Marshaller和Unmarshaller实例对象的setSchema(Schema schema)方法,设置相关的验证模式即可。(JAXP的验证可参考http://code727.iteye.com/blog/1908320

       默认情况下,JAXB在编组或解组的过程中,如果发现所绑定的数据资源不符合相关的模式约束时,只是简单的抛出MarshalException和UnmarshalException,并会阻止当前编组或解组过程继续往下进行。为了更好的控制验证出现错误时的后续行为以及对错误信息的展示,JAXB提供了一个javax.xml.bind.ValidationEventHandler接口专门来做这些工作,用户需自定义实现此接口,完成后将相关的实例对象赋予Marshaller和Unmarshaller实例对象即可。

 

       从上面UML图中可看出,ValidationEventHandler接口只声明了一个public boolean handleEvent( ValidationEvent event )方法,这个方法不需要在客户端进行显示调用,而是当发生验证错误时,由Marshaller和Unmarshaller实例对象自动回调,此方法返回boolean值,表示是否继续进行后续的处理。

       ValidationEventHandler可以处理三种类型的错误,如下:

       1)Warning:警告,对应ValidationEvent.WARNING常量标识;

       2)Error:一般性错误,对应ValidationEvent.ERROR常量标识;

       3)Fatal Error:严重错误,对应ValidationEvent.FATAL_ERROR常量标识。

       handleEvent()方法的参数是一个ValidationEvent接口对象,当错误发生时,可通过此对象可获取到错误信息以及错误在文档中的坐标位置(javax.xml.bind.ValidationEventLocator)。
       JAXB另外一个核心部分就是模式(Schema或DTD),上述的编组、解组和验证等都是围绕模式来开展的:

       1)对于编组来说,模式是根据JAVA对象树生成XML实例文档的依据;

       2)对于解组来说,模式是将XML实例数据绑定到JAVA对象树上的依据;

       3)更为重要的是,模式是构建(生成)JAVA对象树结构的依据,在解组和编组被执行之前,相关的JAVA对象树结构是必须存在的。

      JAXB需要相关的参考实现来支持。例如,SUN的JAVA Web Service开发包(WSDP)就包括了相关的实现,但对于JAXB1.0和2.0来说,各自的实现有着比较显著的区别,如下:

  JAXB1.0 JAXB2.0
定义
  1. JSR31;
  2. 解组和编组操作以及炎症时所用的API;
  3. 模式编译器的绑定方式。
  1. JSR222;
  2. JavaEE5规范的一部分,依赖于注解(Annotation)和泛型(参数类型)。
主要特征/区别
  1. 实现支持W3C XML Schema的子集;
  2. 不能将任意的JAVA类绑定到XML,用于编组的类必须是通过JAXB模式编译器所生成的;
  3. 为每个XML Schema中的组件都生成公共接口和私有实现类;
  4. 支持对生成类实例的模式进行验证,但也可以选择禁止验证。
  1. 全面支持W3C XML Schema规范;
  2. 通过注解可以将任意的JAVA类绑定到XML;
  3. 只生成不会实现任何特定接口或继承任何类的POJO类,编组和解组所需的元数据都包括在JAVA注解中;
  4. 本身不支持验证,而是集成JAXP的验证;
  5. 不仅包括JAXB1.0的模式编译器,还包括Schema(模式)生成器,可以查找JAVA类中的注解并生成XML Schema;
  6. 集成StAX:Marshaller接口的实现将JAVA对象树编组为一个java.xml.stream.XMLStreamWriter或java.xml.stream.XMLEventWriter对象;Unmarshaller接口的实现将java.xml.stream.XMLStreamReader或java.xml.stream.XMLEventReader对象解组为一棵JAVA对象树。
  7. 支持回调方法,允许在对象被编组或解组之前或之后,进行相关的额外操作。还允许向编组器或解组器中的实例中注册监听对象,以便接收每个对象的编组和解组事件。

 

       WSDP可以在https://jaxb.java.net中下载,完成后解压文件,例如:jaxb-ri-2.2.7,在此文件夹里又包含了如下4个主要目录:

       1)bin:包含运行模式编译器和生成器的批处理脚本;

       2)doc:包含编译器和生成器的说明文档和JAXB API的JAVAdocs;

       3)lib:包含JAXB API和参考实现的JAR文件;

       4)samples:包含各类JAXB应用程序示例。

       如果我们的应用程序是运行在Jdk1.6+版本上的,则无需进行WSDP的安装,其中JAR里的实现已包含在了JRE(rt.jar)中。

       在Linux或Window的命令终端中键入如下命令:

       xjc -version

       如果随后输出xjc的版本信息,则说明JAXB运行环境已准备就绪。

 

一、JAXB2.0编组实现

       利用JAXB进行编组的第一步就是为JAVA对象树模型创建模式(Schema或DTD) 。例如: 一个简易版的工作简历(Resume)模板的模式定义为如下所示:

       

<?xml version="1.0" encoding="UTF-8"?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	targetNamespace="http://www.jaxbdemo.daniele.com/resume" 
	xmlns:tns="http://www.jaxbdemo.daniele.com/resume">

	<!-- 简历根元素 -->
	<xsd:element name="resume" type="tns:resume"/>
	
	<!-- 简历内容定义 -->	
	<xsd:complexType name="resume">
		<xsd:sequence>
			<xsd:element name="baseInfo" type="tns:baseInfo" />
			<xsd:element name="selfAssessment" type="tns:selfAssessment" />
			<xsd:element name="careerObjective" type="tns:careerObjective" >
				<!-- 定义各个location子元素之间的文本值不能重复 -->
				<xsd:unique name="location" >
					<xsd:selector xpath=".//location"></xsd:selector>
					<xsd:field xpath="."></xsd:field>
				</xsd:unique>
			</xsd:element>
		</xsd:sequence>
		<xsd:attribute name="id" use="optional" />
	</xsd:complexType>
	
	<!-- "基本信息"部分定义 -->
	<xsd:complexType name="baseInfo">
		<xsd:sequence>
			<xsd:element name="name" type="xsd:string"/>
			<xsd:element name="gender" type="tns:gender" />
			<xsd:element name="birthDate" type="xsd:date" />
			<xsd:element name="residency" type="xsd:string" />
			<xsd:element name="experience" type="tns:experience" />
			<xsd:element name="email" type="tns:email" />
			<xsd:element name="mobilePhone" type="tns:mobilePhone" />
			<xsd:element name="height" type="tns:height" minOccurs="0" maxOccurs="1" />
			<xsd:element name="maritalStatus" type="tns:maritalStatus" minOccurs="0" maxOccurs="1" />
		</xsd:sequence>
	</xsd:complexType>
	
	<!-- "自我评价"部分定义 -->
	<xsd:complexType name="selfAssessment">
		<xsd:sequence>
			<xsd:element name="description" type="xsd:string"/>
		</xsd:sequence>
	</xsd:complexType>
	
	<!-- "求职意向"部分定义 -->
	<xsd:complexType name="careerObjective">
		<xsd:sequence>
			<xsd:element name="jobType" type="tns:jobType" default="Full-time"/>
			<xsd:element name="location" type="tns:location" minOccurs="1" maxOccurs="5" />
		</xsd:sequence>
	</xsd:complexType>
	
	<!-- 性别类型定义 -->
	<xsd:simpleType name="gender">
		<xsd:restriction base="xsd:string">
			<xsd:enumeration value="male" />
			<xsd:enumeration value="female" />
		</xsd:restriction>
	</xsd:simpleType>
	
	<!-- 工作年限定义 -->
	<xsd:simpleType name="experience">
		<xsd:restriction base="xsd:integer">
			<xsd:minExclusive value="-1" />
		</xsd:restriction>
	</xsd:simpleType>
	
	<!-- 电子邮件定义 -->
	<xsd:simpleType name="email">
		<xsd:restriction base="xsd:string">
			<xsd:pattern value="(\w+\.)*\w+@(\w+\.)+[A-Za-z]{2,9}" />
		</xsd:restriction>
	</xsd:simpleType>
	
	<!-- 移动电话定义 -->
	<xsd:simpleType name="mobilePhone">
		<xsd:restriction base="xsd:string">
			<xsd:pattern value="\d{11}" />
		</xsd:restriction>
	</xsd:simpleType>
	
	<!-- 身高定义 -->
	<xsd:simpleType name="height">
		<xsd:restriction base="xsd:int">
			<xsd:minExclusive value="0" />
			<xsd:maxExclusive value="300" />
		</xsd:restriction>
	</xsd:simpleType>
	
	<!-- 婚姻状况定义 -->
	<xsd:simpleType name="maritalStatus">
		<xsd:restriction base="xsd:string">
			<xsd:enumeration value="married" />
			<xsd:enumeration value="unmarried" />
		</xsd:restriction>
	</xsd:simpleType>
	
	<!-- 工作性质定义 -->
	<xsd:simpleType name="jobType">
		<xsd:restriction base="xsd:string">
			<xsd:enumeration value="Full-time" />
			<xsd:enumeration value="Part-time" />
			<xsd:enumeration value="Intern/Trainee" />
			<xsd:enumeration value="Both Full-time And Part-time" />
		</xsd:restriction>
	</xsd:simpleType>
	
	<!-- 工作地点定义 -->
	<xsd:simpleType name="location">
		<xsd:restriction base="xsd:string">
			<xsd:minLength value="1" />
			<!-- 移除开头和结尾部分的空格,而中间多个连续的空格会被缩减为一个的空格 -->
			<xsd:whiteSpace value="collapse" />
		</xsd:restriction>
	</xsd:simpleType>
	
</xsd:schema>
       根据JAXB2.0的规范,第二步则是编译上述的Schema并生成对应的JAVA对象树模式,即相关的POJO类。这里需要使用xjc来编译,例如:

 

       xjc -p com.daniele.jaxbdemo.resume.domain -d src resource/resume.xsd

       表示将resource/resume.xsd生成的基础类放到src输出目录下的com.daniele.jaxbdemo.resume.domain包中。其中-p和-d是命令行参数,更多的参数可参考WSDP的文档。

      
图1 xjc编译命令

图2 xjc编译生成的类
   

       从图2中可看出还生成了一个ObjectFacotory,它是一个专门创建complexType元素的工厂类。上述两步确认无误后就可以进行相关的编组实现了。

       编组实现的基础步骤如下:

       1)按照Schema规则设置JAVA对象树各节点值;

       2)创建JAXBContext实例;

       3)根据Context实例创建Marshaller实例;

       4)创建用于输出目的的JAXBElement实例;

       5)调用Marshaller实例的marshal()方法,并将上述的JAXBElement实例传递给此方法。

      

package com.daniele.jaxbdemo.resume.test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

import com.daniele.jaxbdemo.resume.domain.BaseInfo;
import com.daniele.jaxbdemo.resume.domain.CareerObjective;
import com.daniele.jaxbdemo.resume.domain.Gender;
import com.daniele.jaxbdemo.resume.domain.JobType;
import com.daniele.jaxbdemo.resume.domain.MaritalStatus;
import com.daniele.jaxbdemo.resume.domain.ObjectFactory;
import com.daniele.jaxbdemo.resume.domain.Resume;
import com.daniele.jaxbdemo.resume.domain.SelfAssessment;
import com.daniele.jaxbdemo.validation.JAXBValidationEventHandler;
import com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl;

/**
 * <p>简历模板编组测试类</p> 
 * @author  <a href="mailto:code727@gmail.com">Daniele</a>
 * @version 1.0.0, 2013-7-29
 * @see     
 * @since   JAXBDemo1.0.0
 */
public class ResumeMarshallerTest {

	public static void main(String[] args) throws JAXBException, IOException, SAXException {
		
		ObjectFactory factory = new ObjectFactory();
		
		/* 设置"基础信息"部分的数据 */
		BaseInfo baseInfo = factory.createBaseInfo();
		baseInfo.setName("daniele");
		baseInfo.setGender(Gender.MALE);
		baseInfo.setBirthDate(XMLGregorianCalendarImpl.createDate(1983, 7, 27, 0));
		baseInfo.setExperience(new BigInteger("7"));
		baseInfo.setEmail("code727@gmail.com");
		baseInfo.setMobilePhone("13888888888");
		baseInfo.setResidency("ChengDu Hi Tech Zone");
		baseInfo.setHeight(171);
		baseInfo.setMaritalStatus(MaritalStatus.MARRIED);
		
		/* 设置"自我描述"部分的数据 */
		SelfAssessment selfAssessment = factory.createSelfAssessment();
		selfAssessment.setDescription("5 years java development and 2 years test management.");
		
		/* 设置"求职意向"部分的数据 */
		CareerObjective careerObjective = factory.createCareerObjective();
		careerObjective.setJobType(JobType.FULL_TIME);
		List<String> location = new ArrayList<String>();
		location.add("ChengDu");
		location.add("DuJiangYan");
		careerObjective.setLocation(location);
		
		/* 设置根元素<Resume>下的各个子元素 */
		Resume resume = factory.createResume();
		resume.setBaseInfo(baseInfo);
		resume.setSelfAssessment(selfAssessment);
		resume.setCareerObjective(careerObjective);
		
		// 根据上下文路径(用于绑定目的的POJO类所在的包路径)创建JAXB上下文
		JAXBContext context = JAXBContext.newInstance("com.daniele.jaxbdemo.resume.domain");
		Marshaller marshaller = context.createMarshaller();
		
		File schemaSource = new File("resource/resume.xsd");
		Schema schema = SchemaFactory.newInstance(
				XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaSource);
		// 设置编组过程中所遵循的验证规则。如果不设置,则不能保证最终的编组结果是合法的。
		marshaller.setSchema(schema);
		
		JAXBValidationEventHandler handler = new JAXBValidationEventHandler();
                handler.setContinueWhenWarning(true);
		handler.setContinueWhenError(false);
		handler.setContinueWhenFatalError(false);
		
		/*
		 *  设置在编组过程中所使用的验证事件处理器。
		 *  当Marshaller实例对象中设置了schema对象,并且在编组过程中出现验证警告或错误时,
		 *  则会自动调用处理器的handleEvent()方法进行处理,
		 */
		marshaller.setEventHandler(handler);
		
		// 创建可用于编组输出的根元素
		JAXBElement<Resume> root = factory.createResume(resume);
		
		// 在最终的编组输出中增加xsi:schemaLocation属性,并设置值为Schema文件的URI
		marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, root.getName()
				.getNamespaceURI() + " " + schemaSource.getName());
//		marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, schemaSource.getName());
		// 设置编组后进行格式化输出
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		
		// 编组输出方式一:根据JAXBElement类型的根元素来编组
//		marshaller.marshal(root, new FileOutputStream(new File(
//				"resource/resume_daniele.xml")));
		
		/*
		 *  编组输出方式二:根据某个POJO类实例所表示的根元素来编组
		 *  注意:利用xjc命令在生成POJO类时,没有使用@XmlRootElement注解来将某一个类标注为XML根元素,
		 *       因此这里需要在Resume类上人为的加入此注解。
		 */
		marshaller.marshal(resume, new FileOutputStream(
				new File("resource/resume_daniele.xml")));
	}

}
 
package com.daniele.jaxbdemo.validation;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.ValidationEventLocator;

/**
 * <p>JAXB编组或解组验证事件处理器</p> 
 * @author  <a href="mailto:code727@gmail.com">Daniele</a>
 * @version 1.0.0, 2013-7-29
 * @see     
 * @since   JAXBDemo1.0.0
 */
public class JAXBValidationEventHandler implements ValidationEventHandler {
	
	private static final String WARNING_EVENT = "Warning";
	
	private static final String ERROR_EVENT = "Error";
	
	private static final String FATAL_ERROR_EVENT = "FatalError";
	
	private Writer writer;
	
	private StringBuffer message;
	
	/** 当出现警告级别的验证问题时是否还继续后续处理 */
	private boolean continueWhenWarning = true;
	
	/** 当出现一般性错误级别的验证问题时是否还继续后续处理 */
	private boolean continueWhenError = false;
	
	/** 当出现致命性错误级别的验证问题时是否还继续后续处理 */
	private boolean continueWhenFatalError = false;
	
	public JAXBValidationEventHandler() {
		this(System.out);
	}
	
	public JAXBValidationEventHandler(OutputStream out) {
		writer = new BufferedWriter(new OutputStreamWriter(out));
		message = new StringBuffer();
	}
	
	/**
	 * <p>处理编组或解组过程中出现的验证警告或错误的通知。</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @param event:事件对象
	 * @return 
	 * @since JAXBDemo1.0.0
	 */
	@Override
	public boolean handleEvent(ValidationEvent event) {
		int severity = event.getSeverity();
		try {
			if (severity == ValidationEvent.WARNING)
				return handleWarning(event);
			else if (severity == ValidationEvent.ERROR)
				return handleError(event);
			else
				return handleFatalError(event);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
		
	}
	
	/**
	 * <p>处理警告级别的验证事件</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @param event:事件对象
	 * @return 
	 * @throws IOException 
	 * @since JAXBDemo1.0.0
	 */
	protected boolean handleWarning(ValidationEvent event) throws IOException {
		handleEventMessage(event, WARNING_EVENT);
		return continueWhenWarning;
	}
	
	/**
	 * <p>处理一般性错误级别的验证事件</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @param event:事件对象
	 * @return 
	 * @throws IOException 
	 * @since JAXBDemo1.0.0
	 */
	protected boolean handleError(ValidationEvent event) throws IOException {
		handleEventMessage(event, ERROR_EVENT);
		return continueWhenError;
	}
	
	/**
	 * <p>处理严重性错误级别的验证事件</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @param event:事件对象
	 * @return 
	 * @throws IOException 
	 * @since JAXBDemo1.0.0
	 */
	protected boolean handleFatalError(ValidationEvent event) throws IOException {
		handleEventMessage(event, FATAL_ERROR_EVENT);
		return continueWhenFatalError;
	}
	
	/**
	 * <p>根据事件级别处理提示信息</p> 
	 * @author <a href="mailto:code727@gmail.com">Daniele</a> 
	 * @param event:事件对象
	 * @param eventLevel:事件级别名称
	 * @throws IOException 
	 * @since JAXBDemo1.0.0
	 */
	protected void handleEventMessage(ValidationEvent event, String eventLevel) throws IOException {
		String eventMessage = event.getMessage();
		ValidationEventLocator locator = event.getLocator();
		message.setLength(0);
		message.append(eventLevel).append("[").append(locator.getLineNumber())
				.append(",").append(locator.getColumnNumber()).append("]");
		int index = eventMessage.indexOf(":");
		if (index != -1)
			message.append(eventMessage.substring(index));
		else
			message.append(":").append(eventMessage);
		message.append("\n");
		writer.write(message.toString());
		writer.flush();
	}

	public boolean isContinueWhenWarning() {
		return continueWhenWarning;
	}

	public void setContinueWhenWarning(boolean continueWhenWarning) {
		this.continueWhenWarning = continueWhenWarning;
	}

	public boolean isContinueWhenError() {
		return continueWhenError;
	}

	public void setContinueWhenError(boolean continueWhenError) {
		this.continueWhenError = continueWhenError;
	}

	public boolean isContinueWhenFatalError() {
		return continueWhenFatalError;
	}

	public void setContinueWhenFatalError(boolean continueWhenFatalError) {
		this.continueWhenFatalError = continueWhenFatalError;
	}
	
}
    上述ResumeMarshallerTest运行后将会在resource目录中自动生成resume_daniele.xml实例文档:

 

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:resume xmlns:ns2="http://www.jaxbdemo.daniele.com/resume"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.jaxbdemo.daniele.com/resume resume.xsd">
	
	<baseInfo>
		<name>daniele</name>
		<gender>male</gender>
		<birthDate>1983-07-27Z</birthDate>
		<residency>ChengDu Hi Tech Zone</residency>
		<experience>7</experience>
		<email>code727@gmail.com</email>
		<mobilePhone>13888888888</mobilePhone>
		<height>171</height>
		<maritalStatus>married</maritalStatus>
	</baseInfo>
	
	<selfAssessment>
		<description>5 years java development and 2 years test management.</description>
	</selfAssessment>
	
	<careerObjective>
		<jobType>Full-time</jobType>
		<location>ChengDu</location>
		<location>DuJiangYan</location>
	</careerObjective>
	
</ns2:resume>
 

 

二、JAXB2.0解组实现

      与编组实现类似,解组实现的基础步骤如下:

       1)创建JAXBContext实例;

       2)根据Context实例创建Unmarshaller实例;

       3)调用Unmarshaller实例的unmarshal()方法,将解组的XML实例文档资源传递给此方法,并返回绑定了实例数据的JAXBElement实例对象;

       4)从JAXBElement实例对象中获取数据。

 

package com.daniele.jaxbdemo.resume.test;

import java.io.File;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

import com.daniele.jaxbdemo.resume.domain.BaseInfo;
import com.daniele.jaxbdemo.resume.domain.CareerObjective;
import com.daniele.jaxbdemo.resume.domain.MaritalStatus;
import com.daniele.jaxbdemo.resume.domain.Resume;
import com.daniele.jaxbdemo.validation.JAXBValidationEventHandler;

/**
 * <p>简历模板解组测试类</p> 
 * @author  <a href="mailto:code727@gmail.com">Daniele</a>
 * @version 1.0.0, 2013-7-29
 * @see     
 * @since   JAXBDemo1.0.0
 */
public class ResumeUnmarshallerTest {

	public static void main(String[] args) throws JAXBException, SAXException {
		
		JAXBContext context = JAXBContext.newInstance("com.daniele.jaxbdemo.resume.domain");
		Unmarshaller unmarshaller = context.createUnmarshaller();
		
		File schemaSource = new File("resource/resume.xsd");
		Schema schema = SchemaFactory.newInstance(
				XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaSource);
		// 设置解组过程中所遵循的验证规则。如果不设置,则不能保证最终的解组结果是合法的。
		unmarshaller.setSchema(schema);
		
		JAXBValidationEventHandler handler = new JAXBValidationEventHandler();
		handler.setContinueWhenWarning(true);
		handler.setContinueWhenError(false);
		handler.setContinueWhenFatalError(false);
		
		/*
		 *  设置在解组过程中所使用的验证事件处理器。
		 *  当Unmarshaller实例对象中设置了schema对象,并且在解组过程中出现验证警告或错误时,
		 *  则会自动调用处理器的handleEvent()方法进行处理,
		 */
		unmarshaller.setEventHandler(handler);
		
		JAXBElement<Resume> resumeElement = unmarshaller.unmarshal(
				new StreamSource(new File("resource/resume_daniele.xml")),
				Resume.class);
		Resume resume = resumeElement.getValue();
		
		System.out.println("简历详情如下:");
		BaseInfo info = resume.getBaseInfo();
		System.out.println("------ 【基本信息】 ------");
		System.out.println("name       :" + info.getName());
		System.out.println("gender     :" + info.getGender());
		System.out.println("birthDate  :" + info.getBirthDate());
		System.out.println("residency  :" + info.getResidency());
		System.out.println("email      :" + info.getEmail());
		System.out.println("mobilePhone:" + info.getMobilePhone());
		int height = info.getHeight();
		if (height > 0)
			System.out.println("height :" + height);
		MaritalStatus maritalStatus = info.getMaritalStatus();
		if (maritalStatus != null) 
			System.out.println("maritalStatus:" + maritalStatus.value());
		
		System.out.println("------ 【个人评价】 ------");
		System.out.println(resume.getSelfAssessment().getDescription());
		
		CareerObjective careerObjective = resume.getCareerObjective();
		System.out.println("------ 【求职意向】 ------");
		System.out.println("jobType :" + careerObjective.getJobType().value());
		System.out.println("location:" + careerObjective.getLocation());
		
	}
}
      考虑如下一个场景:实际的解组应用通常都发生客户端,我们往往只会接收到服务端发送来的一个XML实例文档,而不知道JAVA对象树模型究竟是怎样的,因此就不能像上述ResumeUnmarshallerTest类里所展示的那样直接从对象树中获取数据(因为在客户端需要一个能接收当前XML实例数据的对象树后,才能获取到被封装的数据),为了解决这个问题,我们需要根据XML实例文档来生成Shcema,然后再从Shcema中生成对象树模型。

 

       因此如何根据XML实例文档来生成Shcema就成为了关键,可以借助第三方的工具来完成,如http://www.xmlforasp.net/CodeBank/System_Xml_Schema/BuildSchema/BuildXMLSchema.aspx,   


 
       如上图,可以在第一个文本框中输入完整的XML实例文档内容后点击“Generate Schema”按钮,等待一段时间,页面会自动生成下面第二个文本框以及Shema结构定义的内容。

       除此之外,在实际的应用中可能还需要根据带了JAXB注解的对象树来生成XML Schema,为此参考实现提供了shcemagen命令来完成这一工作。

  • 大小: 2.2 KB
  • 大小: 7.2 KB
  • 大小: 8.4 KB
  • 大小: 69.9 KB
分享到:
评论
1 楼 baso4233 2014-02-10  
写的非常详细。挺。

相关推荐

    jaxb入门学习

    3. **Binding Runtime Framework**:JAXB的运行时框架,实现编组和解组功能。 - 这是JAXB的核心部分,它包含了实现编组和解组逻辑的所有必要组件。 #### 四、JAXB数据绑定步骤 1. **生成类**:使用JAXB Binding ...

    基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)

    基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业),个人经导师指导并认可通过的高分设计项目,评审分99分,代码完整确保可以运行,小白也可以亲自搞定,主要针对计算机相关专业的正在做大作业的学生和需要项目实战练习的学习者,可作为毕业设计、课程设计、期末大作业,代码资料完整,下载可用。 基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业)基于Python的天气预测和天气可视化项目源码+文档说明(高分毕设/大作业

    2025工业5G终端设备发展报告.pdf

    2025工业5G终端设备发展报告.pdf

    基于分布式ADMM算法与碳排放交易的MATLAB代码:电力系统优化调度

    内容概要:本文介绍了一段基于分布式ADMM算法的MATLAB代码,用于电力系统优化调度,尤其关注碳排放交易的影响。代码首先对电力系统进行分区,接着构建DC-DOPF最优潮流问题,考虑碳排放交易的成本,并利用ADMM算法求解。文中详细解释了各个关键步骤,如系统分区、目标函数设计、碳排放交易成本计算以及ADMM算法的具体实现。此外,代码还包括了多种优化技术和实用技巧,如自适应惩罚因子调整、边界条件处理等,确保算法的有效性和实用性。 适用人群:适用于对电力系统优化调度感兴趣的科研人员、工程师和技术爱好者,尤其是希望深入了解分布式算法和碳排放交易机制的人群。 使用场景及目标:①研究电力系统优化调度的新方法和技术;②探讨碳排放交易对电力系统调度策略的影响;③提高电力系统运行效率和环保性能。 其他说明:代码不仅提供了详细的注释和模块化设计,还展示了丰富的可视化结果,便于理解和进一步研究。同时,文中提到了一些实际应用案例,证明了该方法的有效性和优越性。

    IDEA中本地运行配置文件

    适配于jdk8版本

    dify-course-demo.yml

    自动化生成全套教程

    【GRP-U8软件维护】GRP-U8软件常见问题及解决方案:涵盖账务处理、自定义凭证打印、期初余额导入、双凭证模式调整、电子报表、工资模块、资产管理、物资管理、网上报销、预算编制、学生收费、安装配置及

    内容概要:本文档《GRP_U8软件近期常见问题85例.docx》详细列出了GRP_U8软件在实际使用过程中遇到的85个常见问题及其解决方案。这些问题涵盖了账务处理、电子报表、工资模块、资产管理、物资管理、成本模块、网上报销、预算编制、学生收费、安装配置以及基础数据管理等多个方面。每个问题不仅描述了现象,还提供了具体的解决步骤或SQL语句。文档强调在执行任何脚本前务必进行整库备份,并提供了维护问题的联系方式。 适合人群:适用于GRP_U8软件的管理员、技术支持人员及有一定数据库操作基础的用户。 使用场景及目标:①帮助用户快速定位并解决GRP_U8软件在账务处理、报表生成、工资管理、资产管理等模块中遇到的具体问题;②提供详细的SQL语句和操作指南,确保用户能够独立解决问题,减少对技术支持的依赖;③指导用户在遇到软件安装、配置及升级相关问题时采取正确的措施。 其他说明:文档内容正在不断完善中,用户可以通过私信反馈意见和建议。此外,文档中多次强调了数据安全的重要性,提醒用户在执行任何操作前做好备份工作。针对某些特定问题,文档还提供了多种解决方案供用户选择,以适应不同的环境和需求。

    少儿编程scratch项目源代码文件案例素材-scratch RPG 战斗.zip

    少儿编程scratch项目源代码文件案例素材-scratch RPG 战斗.zip

    基于模型预测控制(MPC)的无人艇分布式编队协同控制仿真与实现

    内容概要:本文详细介绍了利用模型预测控制(MPC)实现无人艇分布式编队协同控制的方法和技术。首先,通过简化的动力学模型和MATLAB代码展示了无人艇的基本行为预测。接着,深入探讨了编队协同控制的关键要素,包括代价函数的设计、信息交换机制以及分布式MPC的具体实现步骤。文中还提供了具体的Python代码示例,涵盖了从单个无人艇的动力学建模到多智能体之间的协作控制。此外,作者分享了一些实用技巧,如如何处理通信延迟、传感器噪声等问题,并展示了仿真效果,证明了所提出方法的有效性和鲁棒性。 适合人群:对无人艇编队控制、模型预测控制(MPC)、分布式系统感兴趣的科研人员、工程师及高校学生。 使用场景及目标:适用于研究和开发无人艇编队控制系统,特别是希望通过分布式控制实现高效、灵活的编队任务。目标是在复杂的海洋环境中,使无人艇能够自主完成编队、跟踪指定路径并应对各种干扰因素。 其他说明:文中提供的代码片段和理论解释有助于理解和实现无人艇编队控制的实际应用。建议读者在实验过程中结合实际情况进行参数调整和优化。

    操作系统实验2内存管理实验

    (3)编写程序验证FIFO和Stack LRU页面置换算法 (4)分别用FIFO和Stack LRU页置换算法,自己设定一个页面引用序列,绘制页错误次数和可用页帧总数的曲线并对比(可用Excel绘制或手绘);能否重现FIFO导致的Belady异常; (5)[选做]编程实现最优页置换算法,用课件上的序列验证。

    机器学习(深度学习):一个用于骨折分类的医学图像数据集

    一个用于骨折分类的医学图像数据集,旨在通过计算机视觉技术帮助研究人员和医疗专业人员准确识别和分类骨折类型。以下是关于该数据集的详细介绍。该数据集包含了多种类型的骨折X光图像,涵盖了常见的骨折类别,如撕脱性骨折(Avulsion Fractures)、粉碎性骨折(Comminuted Fractures)、骨折脱位(Fracture-Dislocations)、青枝骨折(Greenstick Fractures)、发际线骨折(Hairline Fractures)、嵌插性骨折(Impacted Fractures)、纵向骨折(Longitudinal Fractures)、斜行骨折(Oblique Fractures)、病理性骨折(Pathological Fractures)和螺旋形骨折(Spiral Fractures)等。多样性:数据集中的图像来自不同的骨折类型,能够为模型训练提供丰富的样本。高质量标注:数据由专业放射科医生手动标记,确保了数据的准确性和可靠性。适用性:该数据集适用于机器学习和深度学习项目,可用于开发自动化骨折分类系统。该数据集主要用于训练和验证计算机视觉模型,以实现从X光图像中自动识别和分类骨折类型。通过自动化骨折分类,可以提高医疗诊断的效率和准确性,减少人为误判,并帮助医疗专业人员更快地做出决策。是一个极具价值的医学图像数据集,能够为医疗领域的研究人员和从业者提供有力支持,推动医学影像分析技术的发展。

    互联网的兴起与数字未来

    本书《互联网的历史与数字未来》由约翰尼·瑞安撰写,探讨了互联网从诞生到成为全球性现象的历程。书中分为三个阶段:分布式网络与离心思想的兴起、互联网的扩展以及新兴环境下的互联网。第一阶段追溯了互联网概念的起源,包括冷战背景下的军事实验和计算机技术的普及。第二阶段描述了互联网如何从军事网络演变为全球互联网,并催生了万维网。第三阶段则探讨了Web 2.0的出现、网络社会的形成以及互联网对政治、文化和商业的深远影响。瑞安强调了互联网作为离心力、用户驱动和开放性的三个核心特征,并指出这些特征正在重塑我们的世界。

    易语言进程封包截取工具

    进程封包截取神器,支持TCP和UDP协议封包拦截

    最新版kibana-9.0.0-linux-x86-64.tar.gz

    最新版kibana-9.0.0-linux-x86_64.tar.gz

    子查询练习题,多练习总没有坏处,不知道凑没凑够十一个字

    子查询练习题,多练习总没有坏处,不知道凑没凑够十一个字

    可见光近红外波段VO2介电常数的Matlab计算与COMSOL仿真教程

    内容概要:本文详细介绍了如何利用Matlab计算二氧化钒(VO2)在可见光到近红外波段的介电常数,并将其应用于COMSOL多物理场仿真软件进行光学性能仿真。主要内容包括:VO2在不同温度下的相变特性及其对折射率的影响;基于Lorentz和Drude模型的介电常数计算方法;Matlab代码实现步骤;COMSOL中材料参数的导入与设置;以及常见错误提示和解决方案。文中还附带了一个详细的30分钟教学视频,帮助读者更好地理解和掌握整个流程。 适合人群:对光学材料、相变材料感兴趣的科研工作者和技术人员,尤其是从事智能窗户、光学开关等领域研究的人士。 使用场景及目标:① 学习并掌握VO2在不同温度下的光学特性和相变机制;② 利用Matlab和COMSOL进行材料参数计算和仿真,为实际应用提供理论支持;③ 解决仿真过程中可能出现的问题,提高仿真精度。 阅读建议:建议读者跟随文中的代码示例逐步操作,结合提供的教学视频加深理解。对于初学者来说,可以先熟悉Matlab的基本语法和COMSOL的操作界面,再尝试完成完整的仿真流程。

    COMSOL模拟激光打孔热应力耦合分析及优化方法

    内容概要:本文详细介绍了利用COMSOL Multiphysics进行激光打孔过程中热应力耦合仿真的具体步骤和技术要点。首先,通过建立波动光学和固体力学两个物理场,精确模拟了1064nm激光与材料相互作用产生的温度场变化及其引起的热膨胀效应。接着,针对热源加载、网格划分、求解器配置等方面进行了深入探讨,提出了多项创新性的解决方案,如采用移动高斯热源实现精准加热、引入时间条件判断调整热膨胀系数以及优化网格布局等措施。此外,还讨论了材料参数设置中的注意事项,尤其是对于高温合金材料,在不同温度区间内的导热系数和弹性模量的变化规律,并强调了相变潜热的影响。最后,通过对温度场和应力场的综合分析,揭示了激光移动速度对孔洞边缘应力分布的影响机制。 适用人群:从事激光加工、材料科学、热力学研究的专业人士,以及对多物理场耦合仿真感兴趣的科研工作者。 使用场景及目标:适用于希望深入了解激光打孔过程中热应力形成机理的研究人员;旨在提高加工精度、减少缺陷发生的工程技术人员;希望通过理论模型指导实际生产的制造业从业者。 其他说明:文中提供了大量MATLAB代码片段用于辅助理解和实施相关操作,同时分享了许多实用的经验技巧,帮助读者更好地掌握COMSOL软件的应用。

    永磁同步电机全速度域无位置传感器控制技术与切换策略研究

    内容概要:本文详细探讨了永磁同步电机(PMSM)在全速度范围内实现无位置传感器控制的技术方法和切换策略。针对高速和低速段分别介绍了超螺旋滑模控制和脉振高频方波注入的具体实现方式,并提供了相应的代码示例。对于切换策略,则讨论了加权切换和双坐标切换的方法,强调了在实际应用中需要注意的问题,如角度补偿和平滑过渡。此外,还分享了一些实用的经验技巧,如高频注入信号的滤波处理、滑模控制参数的优化设置等。 适合人群:从事电机控制系统设计的研究人员和技术工程师。 使用场景及目标:适用于需要深入了解PMSM无位置传感器控制技术的研发项目,旨在帮助工程师掌握不同速度范围内的最优控制策略,确保系统在全速域内的稳定性和可靠性。 其他说明:文中提供的代码片段和实践经验有助于读者更好地理解和实施相关技术,同时也提醒读者在实际应用中应注意参数调整和系统调试。

    C#运控框架雷赛DMC系列项目:适合新手的运动控制源码学习

    内容概要:本文介绍了一个基于C#和雷赛DMC系列的运动控制项目,该项目提供了详细的源码解析和技术要点讲解。尽管界面较为简陋,但功能齐全,涵盖了设备连接、运动参数设置、运动控制、状态监测等多个方面。文章详细解释了各个关键模块的实现,如初始化、运动控制、指令解析、多线程同步和紧急停止等功能。此外,还介绍了常见的陷阱和优化建议,帮助新手更好地理解和掌握运动控制编程。 适合人群:初学者和有一定编程基础的开发者,特别是对运动控制编程感兴趣的程序员。 使用场景及目标:① 学习C#与雷赛DMC系列设备的集成;② 掌握运动控制项目的开发流程;③ 实践运动控制的实际应用场景,如工业自动化。 其他说明:项目不仅提供完整的代码示例,还包括了许多实用的技术提示和最佳实践,非常适合新手进行深度学习和改造。

Global site tag (gtag.js) - Google Analytics