利用xmlBean工具进行xml文件读写开发(一)
在java的工程开发中,经常会遇到对xml文件的读写操作。Apache的工具xmlBean是个非常好用的工具,通过它生成jar包,这样在工程开发时,直接调用jar包中的方法来实现对xml文件的操作。本文就其开发使用步骤进行说明。
一 准备工作
首先下载安装XMLBean,这是Apache的一个开源项目,可以从http://www.apache.org下载,我用的版本是2.2.0;将下载的XMLBean解压到任意目录,如C:\xmlbeans-2.2.0\;在环境变量path中加入C:\xmlbeans-2.2.0\bin;
然后下载并按照Altova XMLSpy工具,用该工具生成和编辑Schema文件;
二 jar包的制作
首先要根据要操作的xml文件生成对应的Schema文件,这个文件应该理解为对xml文件数据结构进行描述的文件,以.xsd为扩展名。如果对xml数据结构以及xsd描述规则足够了解和熟悉,实际上可以直接采用任何的文本编辑工具进行xsd文件的编辑。这里利用Altova XMLSpy从xml文件进行转换,然后进行修改形成xsd文件。有了xsd文件,就看利用命令scomp来生成jar包了。步骤的详细说明如下:
1. 从xml文件转换得到xsd文件
用Altova XMLSpy将xml文件打开。这里以vpn.xml文件为例,该文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<VPNS>
<VPN>
<Id>1</Id>
<Name>vpntest</Name>
<Description>test!</Description>
<VpnType>1</VpnType>
<VpnBind/>
<LNS>
<VpnInfo>
<Id>1</Id>
<VpnNumber>1</VpnNumber>
<TunnelType>1</TunnelType>
<TunnelMediaType>1</TunnelMediaType>
<ServerEndPoint>3.3.3.31</ServerEndPoint>
<TunnelPassword>1</TunnelPassword>
<Status>0</Status>
</VpnInfo>
</LNS>
</VPN>
<VPN>
<Id>2</Id>
<Name>2</Name>
<Description>2</Description>
<VpnType>1</VpnType>
<VpnBind>0</VpnBind>
<LNS>
<VpnInfo>
<Id>1</Id>
<VpnNumber>1</VpnNumber>
<TunnelType>1</TunnelType>
<TunnelMediaType>1</TunnelMediaType>
<ServerEndPoint>2.3.3.3</ServerEndPoint>
<TunnelPassword>3</TunnelPassword>
<Status>0</Status>
</VpnInfo>
</LNS>
</VPN>
<VPN>
<Id>3</Id>
<Name>2</Name>
<Description>2</Description>
<VpnType>1</VpnType>
<VpnBind>0</VpnBind>
<LNS>
<VpnInfo>
<Id>1</Id>
<VpnNumber>1</VpnNumber>
<TunnelType>1</TunnelType>
<TunnelMediaType>1</TunnelMediaType>
<ServerEndPoint>1.3.3.3</ServerEndPoint>
<TunnelPassword>3</TunnelPassword>
<Status>0</Status>
</VpnInfo>
</LNS>
</VPN>
<VPN>
<Id>4</Id>
<Name>22</Name>
<Description>22</Description>
<VpnType>1</VpnType>
<VpnBind>0</VpnBind>
</VPN>
<VPN>
<Id>5</Id>
<Name>44</Name>
<Description>44</Description>
<VpnType>1</VpnType>
<VpnBind/>
<LNS>
<VpnInfo>
<Id>1</Id>
<VpnNumber>1</VpnNumber>
<TunnelType>1</TunnelType>
<TunnelMediaType>1</TunnelMediaType>
<ServerEndPoint>33.3.3.3</ServerEndPoint>
<TunnelPassword>3333</TunnelPassword>
<Status>0</Status>
</VpnInfo>
</LNS>
</VPN>
</VPNS>
然后,选择菜单DTD/Schema->生成Schema,弹出生成Schem对话框,取默认值点击确定,弹出保存对话框,选择路径,保存为vpn.xsd;
此时生成的vpn.xsd,如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--W3C Schema 由 XMLSpy v2006 U 创建 (http://www.altova.com)-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="Description">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="2"/>
<xs:enumeration value="22"/>
<xs:enumeration value="44"/>
<xs:enumeration value="test!"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="Id">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="1"/>
<xs:enumeration value="2"/>
<xs:enumeration value="3"/>
<xs:enumeration value="4"/>
<xs:enumeration value="5"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="LNS">
<xs:complexType>
<xs:sequence>
<xs:element ref="VpnInfo"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Name">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="2"/>
<xs:enumeration value="22"/>
<xs:enumeration value="44"/>
<xs:enumeration value="vpntest"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="ServerEndPoint">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="1.3.3.3"/>
<xs:enumeration value="2.3.3.3"/>
<xs:enumeration value="3.3.3.31"/>
<xs:enumeration value="33.3.3.3"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="Status">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="TunnelMediaType">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="TunnelPassword">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="1"/>
<xs:enumeration value="3"/>
<xs:enumeration value="3333"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="TunnelType">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="VPN">
<xs:complexType>
<xs:sequence>
<xs:element ref="Id"/>
<xs:element ref="Name"/>
<xs:element ref="Description"/>
<xs:element ref="VpnType"/>
<xs:element ref="VpnBind"/>
<xs:element ref="LNS" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="VPNS">
<xs:complexType>
<xs:sequence>
<xs:element ref="VPN" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="VpnBind" type="xs:string"/>
<xs:element name="VpnInfo">
<xs:complexType>
<xs:sequence>
<xs:element ref="Id"/>
<xs:element ref="VpnNumber"/>
<xs:element ref="TunnelType"/>
<xs:element ref="TunnelMediaType"/>
<xs:element ref="ServerEndPoint"/>
<xs:element ref="TunnelPassword"/>
<xs:element ref="Status"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="VpnNumber">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="VpnType">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
2. 编辑xsd文件
刚刚生成的vpn.xsd显得很杂乱,可以看出该文件中将xml中的实际取值都带了过来,而我们所要的是对数据的抽象描述,所以需要进一步编辑。
首先,找到第一级的节点,这里是<xs:element name="VPNS">。一般而言Xsd描述的数据结构都是从元素<xs:element>入口,可以是多个,但命名必须全局唯一。从这个元素节点出发,结合对xml文件的分析,我们就会很快理清整个数据结构;
找到所有包含复合类的元素,这里有<xs:element name="VPN">,<xs:element name = "VpnInfo">和<xs:element name="LNS">;
保留前面的4个元素,删除所有其它包含简单类的元素,这时的文件如下:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="LNS">
<xs:complexType>
<xs:sequence>
<xs:element ref="VpnInfo"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="VPN">
<xs:complexType>
<xs:sequence>
<xs:element ref="Id"/>
<xs:element ref="Name"/>
<xs:element ref="Description"/>
<xs:element ref="VpnType"/>
<xs:element ref="VpnBind"/>
<xs:element ref="LNS" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="VPNS">
<xs:complexType>
<xs:sequence>
<xs:element ref="VPN" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="VpnInfo">
<xs:complexType>
<xs:sequence>
<xs:element ref="Id"/>
<xs:element ref="VpnNumber"/>
<xs:element ref="TunnelType"/>
<xs:element ref="TunnelMediaType"/>
<xs:element ref="ServerEndPoint"/>
<xs:element ref="TunnelPassword"/>
<xs:element ref="Status"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
结构已经很清晰了,继续修改。
从第一级元素<xs:element name="VPNS">开始逐步修改。将<xs:element name="VPNS">中<xs:element ref="VPN" maxOccurs="unbounded"/>改为<xs:element name="VPN" type="VPNType" maxOccurs="unbounded"/>;
将<xs:element name="VPN">修改为符合类<xs:complexType name="VPNType">,其中的简单类如<xs:element ref="Name"/>改为<xs:element name="Name" type="xs:string"/>,将ref该为name,添加类type属性。元素<xs:element ref="LNS">复杂一些,它包括一个VpnInfo的复合类,修改为如下:
<xs:element name="LNS">
<xs:complexType>
<xs:sequence>
<xs:element name="VpnInfo" type="VpnInfoType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
这样的话,<xs:element name="LNS">也不需要了,删除;
最后修改<xs:element name="VpnInfo">,将其改为复合类<xs:complexType name="VpnInfoType">,其中的简单类也做如上述符合类<xs:complexType name="VPNType">中的修改。
完成编辑修改后的vpn.xsd文件如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="VPNS">
<xs:complexType>
<xs:sequence>
<xs:element name="VPN" type="VPNType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="VPNType">
<xs:sequence>
<xs:element name="Id" type="xs:int"/>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Description" type="xs:string"/>
<xs:element name="VpnType" type="xs:string"/>
<xs:element name="VpnBind" type="xs:string"/>
<xs:element name="LNS">
<xs:complexType>
<xs:sequence>
<xs:element name="VpnInfo" type="VpnInfoType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="VpnInfoType">
<xs:sequence>
<xs:element name="Id" type="xs:int"/>
<xs:element name="VpnNumber" type="xs:string"/>
<xs:element name="TunnelType" type="xs:string"/>
<xs:element name="TunnelMediaType" type="xs:string"/>
<xs:element name="ServerEndPoint" type="xs:string"/>
<xs:element name="TunnelPassword" type="xs:string"/>
<xs:element name="Status" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
利用Schema/WSDL模式,可以看到如下数据结构图,可以对照一下xml文档,检查是否正确。
3. 生成jar包
有了vpn.xsd,我们就可以生成jar包了。在做jar包前,我们需要一个配置文件vpn.xsdconfig用于定义包路径,文件内容:
<xb:config xmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config">
<xb:namespace>
<xb:package>com.xxx.xmlBean.vpn</xb:package>
</xb:namespace></xb:config>
在windows命令行模式下,输入如下命令:
scomp -src build\src -out build\vpnXmlBean.jar xsd\vpn.xsd -compiler C:\jdk1.5.0_11\bin\javac conf\vpn.xsdconfig -javasource 1.5
命令执行完毕后会生成一个vpnXmlBean.jar包。上述命令参数解释如下:
-src build\src,在指定目录下生成源代码;
-out build\vpnXmlBean.jar,在指定目录下生成名为vpnXmlBean.jar的jar包;
xsd\vpn.xsd,生成jar包所用的xsd文件;
-compiler C:\jdk1.5.0_11\bin\javac,javac所在目录;
conf\vpn.xsdconfig,包路径配置文件;
-javasource 1.5,指定java编译器,这里为java1.5;
java1.5和1.4的编译结果不太一样,其中一个主要差别是1.5编译结果提供返回List的数据,而1.4只提供返回数组。
一 工程应用
将生成的vpnXmlBean.jar包加入到工程的lib目录下,这样就可用通过import com.xxx.. xmlBean.vpn.*来导入jar包中的类。
1. 数据描述Bean开发
对应xml的数据,首先要写两个bean:VpnBean.java和LnsBean.java,分别如下:
VpnBean.java:
public class VpnBean implements java.io.Serializable {
private int id;
private String name;
private String description;
private String vpnType;
private String vpnBind;
private List<LnsBean> lns;
//getter
//setter方法
}
LnsBean.java:
public class LnsBean
{
private String vpnNumber;
private String tunnelType;
private String tunnelMediaType;
private String serverEndPoString;
private String tunnelPassword;
private String status;
private int id;
// getter方法
// setter方法
}
2. 数据访问层Dao的开发
接口定义:
public interface IVpnDao {
List<VpnBean> getVpn();
void addVpn(VpnBean vb) ;
void deleteVpn(VpnBean vb) ;
VpnBean updateVpn(VpnBean vb) ;
void updateVpn(List<VpnBean> vpnlist);
}
类定义:
public class VpnDao implements IVpnDao {
private String fileName;
public void setFileName(String fn) {
this.fileName = fn;
}
public VpnDao() {
}
//方法略
}
说明:生成的jar包中的方法的命名还是很直观的,每个节点都有相应的操作方法,节点下为序列的,会有getXXXList()方法,另外还有返回数组的方法等。
解析xml文件。这里的fileName即vpn.xml(含路径),可通过IOC机制注入;
File xmlFile = new File(fileName);
VPNSDocument doc = VPNSDocument.Factory.parse(xmlFile);
获得vpn列表:doc.getVPNS().getVPNList(),返回一个List;
获得vpn节点数据, vb为VpnBean类:
VPNType vpn = (VPNType )doc.getVPNS().getVPNList().get(i);
vb.setId(vpn.getId());
vb.setName(vpn.getName());
vb.setDescription(vpn.getDescription());
vb.setVpnBind(vpn.getVpnBind());
vb.setVpnType(vpn.getVpnType());
清空vpn:doc.getVPNS().getVPNList().clear();
添加一个vpn节点:VPNType vpn = doc.getVPNS().addNewVPN();
设置vpn节点数据,vb为VpnBean类,传入的数据;
vpn.setId(vb.getId());
vpn.setName(vb.getName());
vpn.setDescription(vb.getDescription());
vpn.setVpnBind(vb.getVpnBind());
vpn.setVpnType(vb.getVpnType());
每次操作完成后,不要忘记保存文件:
XmlOptions xmlOptions = new XmlOptions();
xmlOptions.setSavePrettyPrint();
doc.save(xmlFile, xmlOptions);
如果没有上述文件保存设置,xml中的内容不换行,看起来含难受的。