Java学习之Xml系列六:Dom4j——专题1:基于DOM树的增删改查

全在注释里。

dtd文档:

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT SwordLibrary (Sword*)>
<!ELEMENT Sword (SwordName,Price,Attack)>
<!ELEMENT SwordName (#PCDATA)>
<!ELEMENT Price (#PCDATA)>
<!ELEMENT Attack (#PCDATA)>
<!ATTLIST Sword sno CDATA #REQUIRED>
<!ATTLIST Price type CDATA #IMPLIED>
<!ATTLIST Attack factor CDATA "1.0">

xml文档:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE SwordLibrary SYSTEM "SwordTypeDefinition.dtd">
<SwordLibrary>
<Sword sno="s1">
<SwordName>欢欣之刃</SwordName>
<Price>1000</Price>
<Attack factor="1.0">10</Attack>
</Sword>
<Sword sno="s2">
<SwordName>夜叉</SwordName>
<Price>2050</Price>
<Attack factor="2.0">30</Attack>
</Sword>
<Sword sno="s3">
<SwordName>魔棒</SwordName>
<Price type="Dollar">200</Price>
<Attack factor="1.0">0</Attack>
</Sword>
</SwordLibrary>


java代码:

package com.JavaLeaner;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;

public class XmlDemo6 {

	/*
	 * 使用dom4j读取元素、属性
	 */
	@Test
	public void Test1() throws DocumentException {
		SAXReader reader = new SAXReader();
		Document doc = reader.read(new File("src/SwordLib.xml"));
		Element root = doc.getRootElement();
		Element sword = root.element("Sword");
		String snoAttr = sword.attributeValue("sno");
		Element swordName = sword.element("SwordName");
		String swordNameText = swordName.getText();
		System.out.println("Sword (" + snoAttr + ") is " + swordNameText);

	}

	/*
	 * 使用dom4j遍历DOM树
	 */
	@Test
	public void Test2() throws DocumentException {
		SAXReader reader = new SAXReader();
		Document doc = reader.read(new File("src/SwordLib.xml"));
		Element root = doc.getRootElement();
		treeWalk(root);
	}

	void treeWalk(Element element) {

		for (int i = 0, size = element.nodeCount(); i < size; i++) {
			Node node = element.node(i);
			if (node instanceof Element) {

				System.out.println(node.getName());
				System.out.println(node.getText());

				List attrList = ((Element) node).attributes();
				for (int j = 0; j < attrList.size(); j++) {
					Attribute item = (Attribute) (attrList.get(0));
					String attrName = item.getName();
					String attrValue = item.getText();
					System.out.println("	" + attrName + "=" + attrValue);

				}

				treeWalk((Element) node);
			} else {
				// do something....
			}
		}
	}

	/*
	 * 利用dom4j添加文档元素和属性 格式化(漂漂型和紧凑型)、指定编码输出到xml文件
	 */
	@Test
	public void Test3() throws DocumentException, IOException {
		SAXReader reader = new SAXReader();
		Document doc = reader.read(new File("src/SwordLib.xml"));

		Element root = doc.getRootElement();
		// dom4j中的Element的addElement方法能够添加完元素后将其返回,很赞吧
		// 之后的操作十分优雅.请看Attack元素在添加后直接设置属性的操作
		Element newSword = root.addElement("Sword");
		newSword.addElement("SwordName").setText("散华");// setText不会返回Element
		newSword.addElement("Price").addText("2050");// addText会返回Element
		newSword.addElement("Attack").addAttribute("factor", "0.15")
				.addText("30");

		// Pretty print the document to 输出流
		OutputFormat format = OutputFormat.createPrettyPrint();
		/*
		 * // Compact format to 输出流 OutputFormat format =
		 * OutputFormat.createCompactFormat();
		 */

		// 这里牵涉到复杂的编码转换问题:
		// 使用以上方法读取xml文件得到的Document,不管xml文件是那种编码,在读到内存里都会变成UTF-8
		// 而在将Document写回文件时,如果用new XMLWriter(new FileOutputStream(new
		// File("...")),
		// FileOutputStream所访问的码表是本地默认中文码表,即gb2312。而FileOutputStream也一种没有指定输出编码标准的构造方法
		// 所以,需要中间借助OutputStreamWriter来进行输出流的编码类型转换。
		// 这样,就可以按照UTF-8写回原xml文件了。
		XMLWriter writer = new XMLWriter(new OutputStreamWriter(
				new FileOutputStream(new File("src/SwordLib.xml")), "UTF-8"),
				format);
		writer.write(doc);
		writer.close();

		// 但是,还有更妖怪的事情存在。如果原xml文件本身是gb2312编码,并且你想以gb2312输出到xml文件,也就是说你想xml的头直接写encoding="gb2312"
		// 发现用new XMLWriter(new FileOutputStream(new
		// File("..."))输出,xml文件没有乱码,但是xml的头奇怪地变成了encoding="UTF-8"
		// 这里只给出解决办法,就是借助于上面的格式化输出器:
		// OutputFormat format = OutputFormat.createPrettyPrint();
		// format.setEncoding("gb2312");
		// XMLWriter writer=new XMLWriter(FileOutputStream(new
		// File("src/SwordLib.xml"),format);
		// XMLWriter在吧document交给FileOutputStream时,要转换成字节流,转换时参考的码表就通过format来获得。
		// 注意:不能用FileWriter因为它底层是字符流,XMLWriter在吧document交给FileWriter不会查码表。切记!
		// 总结一句:FileWriter底层流是字符流,FileOutputStream底层流是字节流
		// XMLWriter写需要借助OutputFormat对象来设定码表(推荐)。或者中间套一层OutputStreamWriter来构造指定也可以。
		// 总之,想要编码不出错,原xml文件的encoding和format.setEncoding要一致。

	}

	/*
	 * 利用dom4j添加内容的另一种方式,可以指定相同名称元素的所在位置,以及先创建再追加的方法
	 */
	@Test
	public void Test4() throws DocumentException, IOException {
		SAXReader reader = new SAXReader();
		Document doc = reader.read(new File("src/SwordLib.xml"));

		Element swordLib = doc.getRootElement();
		//这里的.elements()返回的list应该是Document中的元素引用,而不是元素副本,所以修改list是直接对Document进行的
		List list = swordLib.elements();
		
		//创建方式概念,Test3中是天追加在设置
		//这里是先用DocumentHelper.createElement凭空创建,在添加到指定位置。
		Element newSword=DocumentHelper.createElement("Sword");
		newSword.addAttribute("sno", "s4");
		newSword.addElement("SwordName").setText("散华");
		newSword.addElement("Price").addText("2050");
		newSword.addElement("Attack").addAttribute("factor", "0.15")
				.addText("30");
		
		//在指定位置添加,在第0处添加这个新的元素
		//list.add(newSword);默认添加在最后
		list.add(0,newSword);
		
		
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("UTF-8");
		
		XMLWriter writer = new XMLWriter(new FileOutputStream(new File("src/SwordLib.xml")),format);
		writer.write(doc);
		writer.close();
	}

	/*
	 * 按照指定要求删除节点remove
	 * 删除属性也是一样方法remove
	 */
	@Test
	public void Test5() throws DocumentException, IOException
	{
		SAXReader reader = new SAXReader();
		Document doc = reader.read(new File("src/SwordLib.xml"));
		
		List list = doc.getRootElement().elements("Sword");
		for(int i=0;i<list.size();i++)
		{
			Element sword=(Element)(list.get(i));
			Element swordName=sword.element("SwordName");
			if("散华".equals(swordName.getTextTrim()))
			{
				//注意:一定要用父节点删除索要删除的节点,这里其实可以写得更简洁,直接用sword,以下写法主要是想突出获取和利用父节点的思路。
				if(swordName.getParent().getParent().remove(swordName.getParent()))
				{
					System.out.println("成功删除");
				}
				else
				{
					System.out.println("删除失败");
				}
			}
		}
		
				
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("UTF-8");
		

		XMLWriter writer = new XMLWriter(new FileOutputStream(new File("src/SwordLib.xml")),format);
		writer.write(doc);
		writer.close();
	}
	
	/*
	 * 改,很简单
	 */
	@Test
	public void Test6() throws DocumentException, IOException
	{
		SAXReader reader = new SAXReader();
		Document doc = reader.read(new File("src/SwordLib.xml"));
		
		List list = doc.getRootElement().elements("Sword");
		for(int i=0;i<list.size();i++)
		{
			Element sword=(Element)(list.get(i));
			Element swordName=sword.element("SwordName");
			Element price=sword.element("Price");
			if("散华".equals(swordName.getTextTrim()))
			{
				price.setText("2055");
			}
		}
		
				
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("UTF-8");
		

		XMLWriter writer = new XMLWriter(new FileOutputStream(new File("src/SwordLib.xml")),format);
		writer.write(doc);
		writer.close();
	}
}




你可能感兴趣的:(Java学习之Xml系列六:Dom4j——专题1:基于DOM树的增删改查)