携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情
背景
xml的解析技术包括了很多,其中dom4j,jdom,SAX等技术估计已经在大部分的人心中成为了耳熟能详的东西,但是如果是关于xml与对象直接的转换技术,那么下面几种技术是不错的选择。
Commons-Digester
Commons-Digester是apache的一个组件,你不用再象以前通过jdom或者Xerces去读取一个document对象,通过它可以很方便的从xml文件生成java对象.
Digester简单原理
Digester底层采用SAX解析XML文件,对象转换由事件驱动,即在识别出特定XML元素时(实际被细分为begin、body、end、finish四个时点),将执行特定的动作,比如创建特定的Java对象,或调用特定对象的方法等。此处的XML元素根据匹配模式(matching pattern)识别,而相关操作由规则(rule)定义。在转换过程中,Digester维持了一个对象栈,可以看作对象转换的工作台,用来存放转换中生成的、或是为转换临时创建的Java对象。对输入XML文件作了一趟完整的扫描后,对象栈的栈顶元素即为目标对象。由于Digester屏蔽了SAX解析的细节,使用者仅需关注转换操作本身,大大简化了转换操作。
列举实例
首先编写xml文件,文件内容如下:
<?xml version="1.0"?>
<academy name="JAcademy">
<student name="JavaBoy" division="A">
<course>
<id>C1</id>
<name>JSP</name>
</course>
<course>
<id>C2</id>
<name>Servlets</name>
</course>
</student>
<student name="JavaGirl" division="B">
<course>
<id>C3</id>
<name>EJB</name>
</course>
</student>
<teacher name="JavaGuru">
<certification>SCJP</certification>
<certification>SCWCD</certification>
</teacher>
<teacher name="JavaMaster">
<certification>OCP</certification>
<certification>SCJP</certification>
<certification>SCEA</certification>
</teacher>
</academy>
根据xml文件,编写Digester解析的规则文件。
<?xml version="1.0"?>
<digester-rules>
<pattern value="academy">
<object-create-rule classname="com.huawei.example.Academy" />
<set-properties-rule />
<pattern value="student">
<object-create-rule classname="com.huawei.example.Student" />
<set-properties-rule />
<pattern value="course">
<object-create-rule classname="com.huawei.example.Course" />
<bean-property-setter-rule pattern="id" />
<bean-property-setter-rule pattern="name" />
<set-next-rule methodname="addCourse" />
</pattern>
<set-next-rule methodname="addStudent" />
</pattern>
<pattern value="teacher">
<object-create-rule classname="com.huawei.example.Teacher" />
<set-properties-rule />
<call-method-rule pattern="certification"
methodname="addCertification" paramcount="1" />
<call-param-rule pattern="certification" paramnumber="0" />
<set-next-rule methodname="addTeacher" />
</pattern>
</pattern>
</digester-rules>
规则说明:
-
ObjectCreateRule 当begin()方法被调用时, 此rule创建相应Java对象, 并将其push到Digester的对象栈上。当end()方法被调用时, 栈顶对象将被pop, Digester内所有对该对象的引用都将失效。
-
FactoryCreateRule 创建Java对象的另一种选择。当待创建的Java对象没有无参或需要在创建时需要进行额外的设置时,需要用此rule。
属性设置
-
SetPropertiesRule 当begin()方法被调用时, Digester使用标准的Java反射API,将栈顶对象的属性设置为XML元素的同名属性值。
-
SetPropertyRule 当begin()方法被调用时, Digester调用栈顶对象某指定属性的设置方法,设置其值。
父子关系管理
-
SetNextRule 当end()方法被调用时, Digester将栈顶元素设置进次栈顶元素中(调用相应的设置方法)。
-
SetTopRule 当end()方法被调用时, Digester将次栈顶元素设置顶元素中(调用相应的设置方法)。
任意方法调用
-
CallMethodRule 当end()方法被调用时, Digester将调用栈顶元素指定名称的方法。除了方法名外,此rule还需要配置参数数目,参数类型。参数值一般通过CallParamRule得到。
-
CallParamRule 此rule内嵌于CallParamRule中,按顺序(相对于0)定义了CallParamRule中参数值的来源,可选的来源包括当前XML元素的属性或内容。
编写测试类
public static void main(String[] args) throws IOException, SAXException,
IllegalAccessException, InvocationTargetException,
NoSuchMethodException
{
Digester digester = DigesterLoader.createDigester(TestDigester.class
.getClassLoader().getResource("academyRules.xml"));
Academy academy = (Academy) digester.parse(TestDigester.class
.getClassLoader().getResourceAsStream("academy.xml"));
Vector<Student> vStud = academy.getStudents();
Vector<Teacher> vTeach = academy.getTeachers();
for (int i = 0; i < vStud.size(); i++)
{
Student student =vStud.get(i)
System.out.println("name : "+student.getName());
System.out.println("cources name :"+student.getCourses().get(0).getName());
}
for (int i = 0; i < vTeach.size(); i++)
{
Teacher teacher =vTeach.get(i);
System.out.println("Certifications : "+teacher.getCertifications());
}
}
运行其结果如下:
cources name :JSP
name : JavaGirl
cources name :EJB
Certifications : [SCJP, SCWCD]
Certifications : [OCP, SCJP, SCEA]
JAXB
JAXB是一项数据绑定技术,它将xml文件映射成一个个的java类,程序员通过操作这些类就可以对xml文件中的元素进行读取等操作,同样程序员也可以改变这些类的属性,最后映射到xml文件中,这样做可以把程序员的主要精力放在业务逻辑上,并且也更符合面向对象的思想,而无需像使用DOM4J等技术一样需要处理一个个的xml节点。
简单的实例
通过命令将xml文件生成xsd文件。
java -jar trang.jar academy.xml academy.xsd
下载jaxb相关的jar包,下载的详细地址如下:
http://jaxb.java.net
命令将xsd文件生成对应的java实体类
xjc -p com.huawei.wuhen.academy academy.xsd -d src
说明
- -d 指定了保存java文件的目录
- -p 指定了生成的java文件所在的包
编写测试类
private JAXBContext jaxb;
// 这里要生成java实体类所对应的package名称
private final String PACKAGE_NAME = "com.huawei.wuhen.academy";
public Test() throws JAXBException
{
jaxb = JAXBContext.newInstance(PACKAGE_NAME);
}
// 将xml转换成对象
public Academy umarshall(String inputtFileName) throws JAXBException,
FileNotFoundException
{
if (null == inputtFileName || inputtFileName.isEmpty())
{
return null;
}
Unmarshaller unmarshaller = jaxb.createUnmarshaller();
return (Academy) unmarshaller.unmarshal(new FileInputStream(
inputtFileName));
}
// 将对象转换成xml
public void marshall(Academy academy, String outputFileName)
throws JAXBException, FileNotFoundException
{
Marshaller marshaller = jaxb.createMarshaller();
marshaller.marshal(academy, new FileOutputStream(outputFileName));
}
public static void main(String[] args) throws JAXBException,
FileNotFoundException
{
Test test = new Test();
Academy academy = test.umarshall("D:\\academy.xml");
System.out.println("name : " + academy.getStudent().get(0).getName());
test.marshall(academy, "F:\\academy.xml");
}
总结
本文介绍了几种java与xml相互转换的技术,每种技术都具有自己的优点和缺点,我们可以根据项目的情况,选择合适的解析方案。