xml读取的基本上都是获取一个xml文件的输入流作为参数,通过一些类方法返回一个document对象(sax读取除外),接下下来的是事情就简单了;xml的写入是利用设置好输出格式的transformer转换器将document对象和xml文件的输出流作为参数生成一个xml文档。采用的测试xml是一个包含全球所有一级城市的xml文档,按照读取所有国家、有州就不读城市(中国除外)的逻辑那么整个文档有3512条可用数据。源码下载
一、采用Dom方式读写
Dom方式读写都是利用的DocumentBuilder对象来读取xml文件或创建document对象的,将创DocumentBuilder对象的代码放入一个方法中。
/**
* @Decription TODO 获取DocumentBuilder对象
* @date 2016年10月12日 下午8:29:46
* @return
*/
public DocumentBuilder getDocumentBuilder(){
// 获得DocumentBuilderFactory对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db =null;
try {
db= factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
return db;
}
1、Dom读
一次加载所有节点(xml文件过大可能就比较慢的),能保存xml的结构(更方便修改,整棵树都在内存中)。利用DocumentBuilder对象的parse()方法加载xml文档。
/**
* @Decription TODO
* 有些小国家是没其他城市的,所以没有子节点.
* 如果有就获取所有一级城市节点:国外有些国家是没有州的state,那么这些国家的一级城市就是city节点的属性值.
* 中华人民共和国全部的省份城市都要保存
* @date 2016年10月11日 下午2:46:25
*/
public void domParseTest() {
try {
// 获得DocumentBuilder对象
DocumentBuilder builder = this.getDocumentBuilder();
// 通过xml文件输入流获取xml的document对象,parse有输入流的重载方法。这里我用的是源文件路经作为参数(懒^_^)
Document document = builder.parse("LocList.xml");
// 获取所有国家节点
NodeList countrys = document.getElementsByTagName("CountryRegion");
//要保存到数据库的数据题条目的计数器
int count = 0;
//遍历所有CountryRegion节点
for (int j = 0; j < countrys.getLength(); j++) {
String countryName = "";
String countryCode = "";
//获取当前CountryRegion节点
Element country = (Element) countrys.item(j);
//判断是否拥有属性
if(country.hasAttributes()){
//这是一种获取属性值得方式,当属性较多时可用遍历去获取,下面有遍历获取的的方法
countryName = country.getAttribute("Name");
countryCode = country.getAttribute("Code");
System.out.println("国家:" + countryName + " 代码:" + countryCode);
count++;
}
//判断当前CountryRegion节点是否拥有子节点
if (country.hasChildNodes()) {
//获取CountryRegion节点的子节点
NodeList states = country.getChildNodes();
//遍历所有CountryRegion节点下的所有State节点
for (int k = 0; k < states.getLength(); k++) {
//缓存city或state节点的name属性值
String cityName = "";
//缓存city或state节点的code属性值
String cityCode = "";
//中国下面的子节点逻辑(if) 其他(else if 和else) 当elseif和前面的if或elseif同时成立时,执行前面的那一个if或elseif后面的elseif不执行。
if ("State".equals(states.item(k).getNodeName()) && states.item(k).hasAttributes() && "中华人民共和国".equals(countryName)) {
if (states.item(k).getNodeType() == Node.ELEMENT_NODE){
NamedNodeMap stateAttr = states.item(k).getAttributes();
for (int i = 0; i < stateAttr.getLength(); i++) {
Attr attr = (Attr) stateAttr.item(i);
if ("Name".equals(attr.getNodeName())) {
cityName = attr.getNodeValue();
} else {
cityCode = attr.getNodeValue();
}
}
System.out.println(countryName + "的省份: " + cityName + " 代码:" + cityCode);
count++;
if (states.item(k).hasChildNodes()){
NodeList cityList = states.item(k).getChildNodes();
//将省份保留下来
String curState = cityName;
for (int city = 0; city < cityList.getLength(); city++) {
if (cityList.item(city).hasAttributes()){
NamedNodeMap cityAttr = cityList.item(city).getAttributes();
for (int i = 0; i < cityAttr.getLength(); i++) {
Attr attr = (Attr) cityAttr.item(i);
if ("Name".equals(attr.getNodeName())) {
cityName = attr.getNodeValue();
} else {
cityCode = attr.getNodeValue();
}
}
System.out.println(countryName + curState + "的城市或地区: " + cityName + " 代码:" + cityCode);
count++;
}
}
}
}
}else if("State".equals(states.item(k).getNodeName()) && states.item(k).hasAttributes() ){
NamedNodeMap cityAttr = states.item(k).getAttributes();
for (int i = 0; i < cityAttr.getLength(); i++) {
Attr attr = (Attr) cityAttr.item(i);
if ("Name".equals(attr.getNodeName())) {
cityName = attr.getNodeValue();
} else {
cityCode = attr.getNodeValue();
}
}
System.out.println(countryName + "的一级城市: " + cityName + " 代码:" + cityCode);
count++;
}else {
/**
* 前面是没有属性的state节点时System.out.println(states.item(k).getNodeName());输出下列内容:
* #text TEXT_NODE
* State ELEMENT_NODE
* #text
* 所以要加一个判断
**/
if (states.item(k).getNodeType() == Node.ELEMENT_NODE){
if(states.item(k).hasChildNodes()){
NodeList cityList = states.item(k).getChildNodes();
for (int city = 0; city < cityList.getLength(); city++) {
if (cityList.item(city).hasAttributes()){
NamedNodeMap cityAttr = cityList.item(city).getAttributes();
for (int i = 0; i < cityAttr.getLength(); i++) {
Attr attr = (Attr) cityAttr.item(i);
if ("Name".equals(attr.getNodeName())) {
cityName = attr.getNodeValue();
} else {
cityCode = attr.getNodeValue();
}
}
System.out.println(countryName + "的一级城市: " + cityName + " 代码:" + cityCode);
count++;
}
}
}else{
NamedNodeMap cityAttr = states.item(k).getAttributes();
for (int i = 0; i < cityAttr.getLength(); i++) {
Attr attr = (Attr) cityAttr.item(i);
if ("Name".equals(attr.getNodeName())) {
cityName = attr.getNodeValue();
} else {
cityCode = attr.getNodeValue();
}
}
System.out.println(countryName + "的一级城市: " + cityName + " 代码:" + cityCode);
count++;
}
}
}
}
} else {
System.out.println(countryName + "是个小国家,没有一级城市!");
}
}
System.out.println("一共有:" + count + "的数据!");
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
2、Dom写
利用DocumentBuilder对象创建document对象,Transformer对象生成xml文档。
/**
* dom生成xml文件
*/
public void domCreateXml(){
//创建DocumentBuilder对象
DocumentBuilder db = this.getDocumentBuilder();
//生成一个Dom树
Document document = db.newDocument();
//去掉standalone="no"声明,说明只是一个简单的xml,没有特殊DTD(document type definition文档类型定义)规范
document.setXmlStandalone(true);
//创建Location根节点
Element rootElement = document.createElement("Location");
//创建CountryRegion节点
Element country = document.createElement("CountryRegion");
country.setAttribute("Name", "中国");
country.setAttribute("Code", "1");
//创建State节点
Element state = document.createElement("State");
state.setAttribute("Name", "四川");
state.setAttribute("Code", "22");
//创建city节点
Element city = document.createElement("City");
city.setAttribute("Name", "成都");
city.setAttribute("Code", "cd");
//将city是state下的子节点,将city加入到state中
state.appendChild(city);
//将state是country下的子节点,将state加入到country中
country.appendChild(state);
//将country是Location下的子节点,将state加入到country中
rootElement.appendChild(country);
//将包含了子节点的rootElement添加到document中
document.appendChild(rootElement);
//实例化工厂类,工厂类不能使用new关键字实例化创建对象
TransformerFactory transFactory = TransformerFactory.newInstance();
try {
//创建transformer对象
Transformer transformer = transFactory.newTransformer();
//设置换行
transformer.setOutputProperty(OutputKeys.INDENT, "Yes");
//构造转换,参数都是抽象类,要用的却是更具体的一些类,这些的类的命名有一些规律的。
transformer.transform(new DOMSource(document), new StreamResult("LocListDom.xml"));
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
}
二、采用SAX方式读写
1、SAX读
事件驱动,逐行读取,通过重写DefaultHandler来获取解析的场景。
/**
* @Decription TODO
* @date 2016年10月12日 下午7:33:26
*/
public void saxParseTest(){
//SAXParserFactory工厂类对象
SAXParserFactory factory = SAXParserFactory.newInstance();
InputStream in = null;
try {
//利用工厂类创建SAXParser对象
SAXParser parser = factory.newSAXParser();
//创建文件输入流
in = new FileInputStream("LocList.xml");
//解析
parser.parse(in, new SaxHandler());
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if(in != null)
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过继承DefaultHandler重写4个方法获取解析状态
package my.sax.practice;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SaxHandler extends DefaultHandler{
//缓存CountryRegion的name属性值
String countryName = "";
//缓存CountryRegion的code属性值
String countryCode = "";
//缓存city或state节点的name属性值
String stateName = "";
//缓存city或state节点的code属性值
String stateCode = "";
/**
* xml解析开始
*/
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("sax的xml解析开始");
}
/**
* 解析节点开始
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
//attributes!=null判断不行
if(attributes.getLength() > 0){
switch (qName) {
case "CountryRegion":
countryName = attributes.getValue("Name");
countryCode = attributes.getValue("Code");
System.out.println("国家:" + countryName + " 代码:" + countryCode);
break;
case "State":
stateName = attributes.getValue("Name");
stateCode = attributes.getValue("Code");
System.out.println(countryName + "的一级城市: " + stateName + " 代码:" + stateCode);
break;
case "City":
String cityName = attributes.getValue("Name");
String cityCode = attributes.getValue("Code");
if("".equals(stateName) && "".equals(stateCode)){
System.out.println(countryName + "的一级城市: " + cityName + " 代码:" + cityCode);
}else{
System.out.println(countryName + stateName + "的城市或地区: " + cityName + " 代码:" + cityCode);
}
break;
default:
break;
}
}else{
if(qName.equals("State")){
stateName = "";
stateCode = "";
}
}
}
/**
* 解析节点结束
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
}
/**
* xml解析结束
*/
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("sax的xml解析结束");
}
}
2、SAX写
/**
* @Decription TODO sax方法创建一个xml文档
* @date 2016年10月12日 下午8:37:26
*/
public void saxCreateXml(){
//1、创建一个SAXTransformerFactory一个对象
SAXTransformerFactory sf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
OutputStream in =null;
try {
//2、通过SAXTransformerFactory创建一个TransformerHandler对象
TransformerHandler handler = sf.newTransformerHandler();
//3、通过TransformerHandler对象获取Transformer对象(用于设置xml输出的样式和头)
Transformer transformer = handler.getTransformer();
//设置没有其他的DTD(Document Type Defination 文档类型定义)规范
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
//设置编码格式,显式的显示在<?xml version="1.0" ?>中
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
//设置换行
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//文件输出
File file =new File("LocListSax.xml");
//确保file是存在的
if(!file.exists()){
if(!file.createNewFile()){
throw new FileNotFoundException("文件创建失败!");
}
}
//4、创建输出流OutputStream对象
in = new FileOutputStream(file);
//5、创建流Result对象
Result result = new StreamResult(in);
//6、关联result,此时有了生成元素的方法(handler提供的方法)和装元素的容器(result对象)
handler.setResult(result);
//打开文档
handler.startDocument();
//属性设置
AttributesImpl attr = new AttributesImpl();
//开始创建元素
handler.startElement("", "", "Location", attr);
attr.addAttribute("", "", "Name", "", "阿尔巴尼亚");
attr.addAttribute("", "", "Code", "", "DZA");
handler.startElement("", "", "CountryRegion", attr);
attr.clear();
attr.addAttribute("", "", "Name", "", "阿德拉尔");
attr.addAttribute("", "", "Code", "", "ADR");
handler.startElement("", "", "State", attr);
handler.endElement("", "", "State");
handler.endElement("", "", "CountryRegion");
//结束元素创建
handler.endElement("", "", "Location");
//关闭文档
handler.endDocument();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
//关闭流, 习惯不好,老是不喜欢关闭流
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、采用JDom方式读写
1、JDom读
public static void jdomParseTest(){
//创建SAXBuilder对象
SAXBuilder builder = new SAXBuilder();
//创建InputStream对象并初始化变量null
InputStream in = null ;
//缓存CountryRegion的name属性值
String countryName = "";
//缓存CountryRegion的code属性值
String countryCode = "";
//缓存city或state节点的name属性值
String stateName = "";
//缓存city或state节点的code属性值
String stateCode = "";
//初始化字符输入流
InputStreamReader reader =null;
try {
//获得文件的输入流
in =new FileInputStream("LocList.xml");
//给设置字符输入流设置编码格式
reader = new InputStreamReader(in, "UTF-8");
//通过SAXBuilder对象的build方法获取xml的Document对象
//报错:前言中不允许有内容,解决办法:使用notepad++ utf-8保存一下
Document document = builder.build(reader);
//获取根节点Location
Element rootElement = document.getRootElement();
//获取根节点Location的子节点
List<Element> coutryList = rootElement.getChildren();
//遍历子节点
for(Element country : coutryList){
if (country.hasAttributes()){
countryName = country.getAttributeValue("Name");
countryCode = country.getAttributeValue("Code");
System.out.println("国家:" + countryName + " 代码:" + countryCode);
//获取country的子节点state
List<Element> stateList = country.getChildren();
//遍历state
for (Element state : stateList){
//判断是否拥有属性外国的state节点都是没有属性的,有
if(state.hasAttributes()){
stateName = state.getAttributeValue("Name");
stateCode = state.getAttributeValue("Code");
//当是中国时才遍历state下的子节点
if("中华人民共和国".equals(countryName)){
//获取state的子节点city
List<Element> cityList = state.getChildren();
//遍历city
for (Element city : cityList){
if(city.hasAttributes()){
String cityName = city.getAttributeValue("Name");
String cityCode = city.getAttributeValue("Code");
System.out.println(countryName + stateName + "的城市或地区: " + cityName + " 代码:" + cityCode);
}
}
}else{
System.out.println(countryName + "的一级城市: " + stateName + " 代码:" + stateCode);
}
}else{
//获取state的子节点city
List<Element> cityList = state.getChildren();
//遍历city
for (Element city : cityList){
if(city.hasAttributes()){
String cityName = city.getAttributeValue("Name");
String cityCode = city.getAttributeValue("Code");
System.out.println(countryName + "的一级城市: " + cityName + " 代码:" + cityCode);
}
}
}
}
}
}
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if(in !=null)
in.close();
if (reader != null)
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、JDom写
/**
*jdom方法生成xml文件
*/
public static void jdomCreateXml(){
//创建根节点
Element root = new Element("Location");
//创建document对象
Document document = new Document(root);
//添加子节点
Element child = new Element("CountryRegion");
child.setAttribute("Name", "中国");
child.setAttribute("Code", "1");
//添加子节点
Element subchild = new Element("State");
subchild.setAttribute("Name", "四川");
subchild.setAttribute("Code", "sc");
//添加子节点
Element subsubchild = new Element("City");
subsubchild.setAttribute("Name", "成都");
subsubchild.setAttribute("Code", "cd");
//添加孙子节点
subchild.addContent(subsubchild);
//添加子节点
child.addContent(subchild);
//添加节点
root.addContent(child);
//创建Format对象,格式化xml
Format formater =Format.getPrettyFormat();
//创建XMLOutputter对象
XMLOutputter outputer = new XMLOutputter(formater);
//初始化输出流,局部变量必须初始化
OutputStream out = null;
//创建xml文件
File file = new File("LocListJdom.xml");
try {
if (!file.exists()){
if (!file.createNewFile()){
throw new FileCanNotCreateException();
}
}
//创建输出流
out = new FileOutputStream(file);
//XMLOutputter写入
outputer.output(document, out);
} catch (IOException e) {
e.printStackTrace();
e.printStackTrace();
} catch (FileCanNotCreateException e) {
e.printStackTrace();
} finally{
//关闭流
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、采用Dom4j方式读写
1、Dom4j读
public static void dom4jParseTest(){
//缓存CountryRegion的name属性值
String countryName = "";
//缓存CountryRegion的code属性值
String countryCode = "";
//缓存city或state节点的name属性值
String stateName = "";
//缓存city或state节点的code属性值
String stateCode = "";
//创建InputStream对象并初始化变量null
InputStream in = null;
SAXReader reader = new SAXReader();
//获得文件的字符输入流
InputStreamReader isr =null;
try {
in =new FileInputStream("LocList.xml");
//给设置输入流直射编码格式
isr = new InputStreamReader(in, "UTF-8");
//使用read方法将输入流加载到SAXBuilder中获得xml的Document对象
Document document = reader.read(isr);
//获取根节点Location
Element rootElement = document.getRootElement();
//获取根节点Location的子节点
@SuppressWarnings("unchecked")
List<Element> coutryList = rootElement.elements();
//遍历子节点
for(Element country : coutryList){
if (country.attributes()!=null && country.attributes().size()>0){
countryName = country.attributeValue("Name");
countryCode = country.attributeValue("Code");
System.out.println("国家:" + countryName + " 代码:" + countryCode);
//获取country的子节点state
@SuppressWarnings("unchecked")
List<Element> stateList = country.elements();
//遍历state
for (Element state : stateList){
//判断是否拥有属性外国的state节点都是没有属性的,有
if(state.attributes()!=null && state.attributes().size()>0){
stateName = state.attributeValue("Name");
stateCode = state.attributeValue("Code");
//当是中国时才遍历state下的子节点
if("中华人民共和国".equals(countryName)){
//获取state的子节点city
@SuppressWarnings("unchecked")
List<Element> cityList = state.elements();
//遍历city
for (Element city : cityList){
if(city.attributes()!=null && city.attributes().size()>0){
String cityName = city.attributeValue("Name");
String cityCode = city.attributeValue("Code");
System.out.println(countryName + stateName + "的城市或地区: " + cityName + " 代码:" + cityCode);
}
}
}else{
System.out.println(countryName + "的一级城市: " + stateName + " 代码:" + stateCode);
}
}else{
//获取state的子节点city
@SuppressWarnings("unchecked")
List<Element> cityList = state.elements();
//遍历city
for (Element city : cityList){
if(city.attributes()!=null && city.attributes().size()>0){
String cityName = city.attributeValue("Name");
String cityCode = city.attributeValue("Code");
System.out.println(countryName + "的一级城市: " + cityName + " 代码:" + cityCode);
}
}
}
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (DocumentException e) {
e.printStackTrace();
}catch (UnsupportedEncodingException e) {
e.printStackTrace();
} finally{
//关闭流
try {
if(in != null)
in.close();
if (isr != null)
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、Dom4j写
/**
* 生成xml文件
*/
public static void Dom4jCreateXml(){
//初始化输出流
OutputStream out = null;
//通过DocumentHelper创建document对象
Document document = DocumentHelper.createDocument();
//创建根节点
Element root = document.addElement("Location");
//添加子节点
Element child =root.addElement("CountryRegion");
child.addAttribute("Name", "中国");
child.addAttribute("Code", "1");
//添加子节点
Element subchild = child.addElement("State");
subchild.addAttribute("Name", "四川");
subchild.addAttribute("Code", "sc");
//添加子节点
Element subsubchild = subchild.addElement("City");
subsubchild.addAttribute("Name", "成都");
subsubchild.addAttribute("Code", "cd");
//将文件输出
try {
//创建输出流
out = new FileOutputStream("LocListDom4j.xml");
//createPrettyPrint格式化xml并返回一个OutPutFormat对象
OutputFormat of = OutputFormat.createPrettyPrint();
//创建一个XMLWriter对象
XMLWriter writer = new XMLWriter(out,of);
writer.write(document);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
五、四种方式性能对比
四种方法中sax读写都是最快,但是sax没办法往回读的。dom4j是第二最关键的代码量少啊,在实际的应用比较多(spring就是用的dom4j)。jdom和dom都差不多,dom的性能还要好一些(我没测试过几次啊,目测)。
本文详细介绍了Java中XML的读写方法,包括Dom、SAX、JDom和Dom4j四种方式,并提供了每种方式的读写操作实例。同时,对这四种方式的性能进行了对比,SAX速度最快,但不支持回读。Dom4j因其简洁的代码和良好的性能在实际应用中常见,而JDom和Dom的性能相近,Dom稍优。
675

被折叠的 条评论
为什么被折叠?



