一种解析XML的方法――jaxb
不论是J2EE还是J2SE的应用中读取xml格式的文件都是必不可少的。通常xml格式的文件可以作为配置文件存储应用程序的配置信息。比如说servlet配置的web.xml. Struts的struts-config.xml都是将配置文件写成xml的格式。Xml格式的文件还可以存储一些可能会扩充或者改变的信息,例如,我们支持的数据类型已经有了text,csv,还有可能增加xml的类型,那么这样的信息我们也可以存储在xml格式的配置文件中。当我们有一些扩充类型的需求时,只需要修改配置信息而不需要修改相应的java或者JSP代码。
对于一个应用来说,当我们有了xml格式的配置文件,就需要对文件进行解析。比较理想的情况是将解析出来的配置信息变成相应的对象,这样方便了调用和处理。Jaxb就是sun公司提供的一个将xml映射成java class的一个小工具。
使用jaxb来解析XML,首先要定义一个xsd文件,这个文件类似一个dtd文件,是对xml个格式进行了一个说明。其次,要使用命令生成java的class文件。最后在我们的应用程序中就可以直接载入xml文件并且创建生成的class文件的实例。
这里有一个例子:
以下是希望解析的xml文件ProtocolOptionsMapping.xml。这里面我们会生成一个有层次的配置信息,基本内容是:
xml文件如下:
<ProtocolOptionsMapping>
<LogType name="Syslog" value="0">
<DestinationType name="Loglogic LMI Appliance" value="1">
<ProtocolOption name="UDP Syslog" value="17"></ProtocolOption>
<ProtocolOption name="Raw TCP Syslog" value="200"></ProtocolOption>
<ProtocolOption name="LogLogic TCP" value="6"></ProtocolOption>
</DestinationType >
<DestinationType name="Loglogic SEM Appliance" value="2">
<ProtocolOption name="UDP Syslog" value="17"></ProtocolOption>
<ProtocolOption name="Raw TCP Syslog" value="200"></ProtocolOption>
</DestinationType >
<DestinationType name="Other Destinations" value="0">
<ProtocolOption name="UDP Syslog" value="17"></ProtocolOption>
<ProtocolOption name="Raw TCP Syslog" value="200"></ProtocolOption>
</DestinationType >
</LogType>
<LogType name="SNMP" value="1">
<DestinationType name="Loglogic LMI Appliance" value="1">
<ProtocolOption name="SNMP" value="201"></ProtocolOption>
<ProtocolOption name="LogLogic TCP" value="6"></ProtocolOption>
</DestinationType >
<DestinationType name="Loglogic SEM Appliance" value="2">
<ProtocolOption name="UDP Syslog" value="17"></ProtocolOption>
<ProtocolOption name="Raw TCP Syslog" value="200"></ProtocolOption>
</DestinationType >
<DestinationType name="Other Destinations" value="0">
<ProtocolOption name="SNMP" value="201"></ProtocolOption>
<ProtocolOption name="UDP Syslog" value="17"></ProtocolOption>
<ProtocolOption name="Raw TCP Syslog" value="200"></ProtocolOption>
</DestinationType >
</LogType>
<LogType name="File" value="2">
<DestinationType name="Loglogic LMI Appliance" value="1">
<ProtocolOption name="LogLogic TCP" value="6"></ProtocolOption>
</DestinationType >
<DestinationType name="Loglogic SEM Appliance" value="2">
<ProtocolOption name="UDP Syslog" value="17"></ProtocolOption>
<ProtocolOption name="Raw TCP Syslog" value="200"></ProtocolOption>
</DestinationType >
<DestinationType name="Other Destinations" value="0">
<ProtocolOption name="UDP Syslog" value="17"></ProtocolOption>
<ProtocolOption name="Raw TCP Syslog" value="200"></ProtocolOption>
</DestinationType >
</LogType>
</ProtocolOptionsMapping>
最终生成的class会有:ProtocolOptionsMapping,LogType,DestinationType,ProtocolOption。
其中ProtocolOptionsMapping中有一个存放LogType的List。
LogType中有两个属性Name,value,还有一个存放DestinationType实例的List
以此类推。
自动生成的class代码如下:
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.0 in JDK 1.6
// 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: 2010.08.25 at 11:08:55 下午 PDT
//
package generated;
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.XmlAttribute;
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="LogType" maxOccurs="unbounded" minOccurs="0">
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="DestinationType" maxOccurs="unbounded">
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="ProtocolOption" maxOccurs="unbounded">
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="value" type="{http://www.w3.org/2001/XMLSchema}int" />
* </restriction>
* </complexContent>
* </complexType>
* </element>
* </sequence>
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="value" type="{http://www.w3.org/2001/XMLSchema}int" />
* </restriction>
* </complexContent>
* </complexType>
* </element>
* </sequence>
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="value" type="{http://www.w3.org/2001/XMLSchema}int" />
* </restriction>
* </complexContent>
* </complexType>
* </element>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"logType"
})
@XmlRootElement(name = "ProtocolOptionsMapping")
public class ProtocolOptionsMapping {
@XmlElement(name = "LogType")
protected List<ProtocolOptionsMapping.LogType> logType;
/**
* Gets the value of the logType 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 logType property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getLogType().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link ProtocolOptionsMapping.LogType }
*
*
*/
public List<ProtocolOptionsMapping.LogType> getLogType() {
if (logType == null) {
logType = new ArrayList<ProtocolOptionsMapping.LogType>();
}
return this.logType;
}
/**
* <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="DestinationType" maxOccurs="unbounded">
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="ProtocolOption" maxOccurs="unbounded">
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="value" type="{http://www.w3.org/2001/XMLSchema}int" />
* </restriction>
* </complexContent>
* </complexType>
* </element>
* </sequence>
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="value" type="{http://www.w3.org/2001/XMLSchema}int" />
* </restriction>
* </complexContent>
* </complexType>
* </element>
* </sequence>
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="value" type="{http://www.w3.org/2001/XMLSchema}int" />
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"destinationType"
})
public static class LogType {
@XmlElement(name = "DestinationType", required = true)
protected List<ProtocolOptionsMapping.LogType.DestinationType> destinationType;
@XmlAttribute
protected String name;
@XmlAttribute
protected Integer value;
/**
* Gets the value of the destinationType 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 destinationType property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getDestinationType().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link ProtocolOptionsMapping.LogType.DestinationType }
*
*
*/
public List<ProtocolOptionsMapping.LogType.DestinationType> getDestinationType() {
if (destinationType == null) {
destinationType = new ArrayList<ProtocolOptionsMapping.LogType.DestinationType>();
}
return this.destinationType;
}
/**
* 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 value property.
*
* @return
* possible object is
* {@link Integer }
*
*/
public Integer getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value
* allowed object is
* {@link Integer }
*
*/
public void setValue(Integer value) {
this.value = value;
}
/**
* <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="ProtocolOption" maxOccurs="unbounded">
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="value" type="{http://www.w3.org/2001/XMLSchema}int" />
* </restriction>
* </complexContent>
* </complexType>
* </element>
* </sequence>
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="value" type="{http://www.w3.org/2001/XMLSchema}int" />
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"protocolOption"
})
public static class DestinationType {
@XmlElement(name = "ProtocolOption", required = true)
protected List<ProtocolOptionsMapping.LogType.DestinationType.ProtocolOption> protocolOption;
@XmlAttribute
protected String name;
@XmlAttribute
protected Integer value;
/**
* Gets the value of the protocolOption 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 protocolOption property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getProtocolOption().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link ProtocolOptionsMapping.LogType.DestinationType.ProtocolOption }
*
*
*/
public List<ProtocolOptionsMapping.LogType.DestinationType.ProtocolOption> getProtocolOption() {
if (protocolOption == null) {
protocolOption = new ArrayList<ProtocolOptionsMapping.LogType.DestinationType.ProtocolOption>();
}
return this.protocolOption;
}
/**
* 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 value property.
*
* @return
* possible object is
* {@link Integer }
*
*/
public Integer getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value
* allowed object is
* {@link Integer }
*
*/
public void setValue(Integer value) {
this.value = value;
}
/**
* <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">
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="value" type="{http://www.w3.org/2001/XMLSchema}int" />
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
public static class ProtocolOption {
@XmlAttribute
protected String name;
@XmlAttribute
protected Integer value;
/**
* 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 value property.
*
* @return
* possible object is
* {@link Integer }
*
*/
public Integer getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value
* allowed object is
* {@link Integer }
*
*/
public void setValue(Integer value) {
this.value = value;
}
}
}
}
}
其中自动生成的class中会有ObjectFactory.java, 这个类包含了创建新实例的方法。猜想,jaxb中会调用这些方法创建新的实例。
下面,就要说一下,如何进行解析了。代码如下。
FileInputStream inputStream = new FileInputStream( “c://config.xml” );;
JAXBContext jc = JAXBContext.newInstance( "com.loglogic.logapp.generated.xml.mapping:" );
Unmarshaller unmarshaller = jc.createUnmarshaller();
ProtocolOptionsMapping protocolOptions = (ProtocolOptionsMapping)unmarshaller.unmarshal( inputStream );
至此,对象就生成了。
那么下面讲一下如何自动生成对象。
首先要定义xsd,上述xml所对应的xsd如下
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ProtocolOptionsMapping"><!--顶层元素-->
<xs:complexType><!--以下将定义子节点和属性-->
<xs:sequence><!--这里是一个可以循环的LIST是子节点-->
<xs:element name="LogType" minOccurs="0" maxOccurs="unbounded"><!--子节点对象-->
<xs:complexType>
<xs:sequence><!--这里是一个可以循环的LogType的子节点,可能有多个-->
<xs:element name="DestinationType" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="ProtocolOption" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="value" type="xs:int"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="value" type="xs:int"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/><!--这里定义LogType节点的属性-->
<xs:attribute name="value" type="xs:int"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
定义完毕之后,就可以直接运行命令生成java文件了。命令如下:
xjc -d gen *.xsd
其中,-d表示生成的路径。