Java 利用document操作xml并实现DES加密和解密

1 篇文章 0 订阅
1 篇文章 0 订阅

下面是利用document对xml文件进行修改的大致过程:

java中使用XML,目前常用的就是Jaxp(sun)dom4j了,这里先讲讲java自带的Jaxp

JAXP 开发包是J2SE的一部分,它由javax.xmlorg.w3c.domorg.xml.sax包及其子包组成

Jaxpxml解析器有两种,一种是DOM解析器,一种是SAX解析器,两种各自应用在不同的场景上。

DOM

DOM分析器通过对XML文档的分析,把整个XML文档以一棵DOM树的形式存放在内存中,应用程序可以随时对DOM树中的任何一个部分进行访问与操作,也就是说,通过DOM树,应用程序可以对XML文档进行随机访问。这种访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个XML文档中的内容。然而,由于DOM分析器把整个XML文档转化成DOM树放在了内存中,因此,当XML文档比较大或者文档结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项比较耗时的操作。所以,DOM分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于DOM分析器的树结构的思想与XML文档的结构相吻合,而且,通过DOM树机制很容实现随机访问。因此DOM分析器也有较为广泛的使用价值。

 

DOM解析时,会把xml中各个节点视为对象,然后根据父子关系相互嵌套。优点时容易操纵,缺点也很明显,必须全部通读xml并加载进内存。

DOM解析的流程:

1。DocumentBuilderFactory是抽象类,newInstance()方法会根据本地平台安装的xml解析器自动创建相应的工厂实例

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

2。DocumentBuildernewDocumentBuilder()方法会得到本地xml解析器相应的DocumentBuilder实例

DocumentBuilder documentB = dbf.newDocumentBuilder();

3。解析xml,根据DocumentBuilderparse方法。

Document document = documentB.parse(newFile(path));

//看文档可以知道,parse可以从解析FileInputSource(经过包装的InputStream)、InputStreamURI字符串

4Document代表了整个XML文档,首先获取根节点,Element就是标签,它们都属于Node,也就是说,都实现了Node接口

Element root=document.getDocumentElement();

5,下面就是增删改查了

增加结点

//增加一个结点,注意,增加节点是对document操作,Document实现了这个方法

Element newStudent=document.createElement("student");

              

//增加一个属性,属性也算是结点,一切都是Node

Attr cid=document.createAttribute("idcard");

//给属性设置值

cid.setValue("1121");

              

//将属性添加进这个标签

newStudent.setAttributeNode(cid);

              

//最后,将这个结点添加进根节点,注意,是对根节点添加,不是Document

root.appendChild(newStudent);

 

提取某节点信息(查)

//首先根据第3步,已经获得根结点,也就是Element root

  

  

//获取所有标签名为sutdent的节点集合

NodeList students=root.getElementsByTagName("student");

  

//至于获取标签属性以及text内容,自行看手册

  

//要注意的是,换行和制表符'\n\t'这些,也会被当做text内容解析

//至于xml的编码问题,都是自动的,不用手动设置了。

更改结点内容(很多都是Node接口的方法,自行查看手册即可)

//设置标签内容

Node.setTextContent(String text)

  

//设置属性内容

Attr.setValue(String value)

删除结点

Node.removeChild(Node node)

 

6操作完xml,保存结果

javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出,例如把xml文件应用样式表后转成一个html文档。

利用这个对象,当然也可以把Document对象又重新写入到一个XML文件中

//1、获得Transformer工厂

TransformerFactory tff=TransformerFactory.newInstance();

  

//2、对于DOM对象,使用树来表示,肯定是个多叉树了,,,

//这个类,就是将树,变为结果树

Transformer tf = tff.newTransformer();

  

//3、把documentDOM)转换为xml source

Source sc=newDOMSource(document);

  

//4、创建一个DOM目标,这里是个流

Result rs=newStreamResult(newFile(path_URI));

  

//5、将 XML Source转换为 Resultwriter这样就写入数据流了

tf.transform(sc, rs);

DOM解析就到这里,如果以网络流读取一个大的xml文件的话,这样肯定是不行的,不可能一直等到它全部读完载入内存再操作吧。。。。。光读取的话,就用SAX了。


SAX                                                                                                                         

SAX分析器在对XML文档进行分析时,触发一系列的事件,应用程序通过事件处理函数实现对XML文档的访问。由于事件触发本身是有时序性的,因此,SAX分析器提供的是一种对XML文档的顺序访问机制,对于已经分析过的部分,不能再倒回去重新处理。
    SAX
之所以被叫做"简单"应用程序接口,是因为SAX分析器只做了一些简单的工作,大部分工作还要由应用程序自己去做。也就是说,SAX分析器在实现时,它只是顺序地检查XML文档中的字节流,判断当前字节是XML语法中的哪一部分,检查是否符合XML语法并触发相应的事件。对于事件处理函数本身,要由应用程序自己来实现。同DOM分析器相比,SAX分析器对XML文档的处理缺乏一定的灵活性,然而,对于那些只需要访问XML文档中的数据而不对文档进行更改的应用程序来说,SAX分析器的效率则更高。由于SAX分析器实现简单,对内存要求比较低,因此实现效率比较高同时具有广泛的应用价值。


下面是一个较为完整的例子:

用java向XML增加一个结点元素是今年ACCP认证考试的试题,可见XML的重要性!
题目要求考生向已经给出的XML文件增加一个结点元素,答案如下:
//DomXML.java
import javax.xml.parsers.*; 
import javax.xml.transform.*; 
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult; 
import org.w3c.dom.*; 
class XmlWrite
{
public static void main(String[] args)
{ 
try{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc=builder.parse("links.xml");
doc.normalize();

String name2="Hanzhong´s Homepage"; 
String sex2="male";
String phone2="22324098"; 

//create an element named "link"
Element link=doc.createElement("link"); 
/*create an element of context named "name"
context is consided with an element by w3c */
Element linkName=doc.createElement("name"); 
Text textName=doc.createTextNode(name2);
linkName.appendChild(textName);
link.appendChild(linkName); 
doc.getDocumentElement().appendChild(link);//return a root node of document

TransformerFactory tFactory =TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(); 
DOMSource source = new DOMSource(doc); 
StreamResult result = new StreamResult(new java.io.File("links.xml")); 
transformer.transform(source, result); 
}
catch(Exception e){}
}
}

将代码封装起来:

获得Document,即xml文件的树模型

public static Document getDocument(String xmlPath) {

		Document document = null;
 // 建立DocumentBuilderFactory对象 
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder;
		try {
 // 建立DocumentBuilder对象 
			builder = factory.newDocumentBuilder();
 // 用DocumentBuilder对象的parse方法引入文件建立Document对象 
			document = builder.parse("file:\\" + xmlPath);
		} catch (Exception e) {
			// e.printStackTrace();
			return null;
		}
		return document;
	}
获得Document后,增加或删除节点后输出xml文件
public static void writeToXML(String path, Document document) {

		try {
			FileOutputStream fos = new FileOutputStream(path);
			OutputStreamWriter outwriter = new OutputStreamWriter(fos);
			callWriteXmlFile(document, outwriter, "gb2312");
			outwriter.close();
			fos.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
操作完xml,保存结果
private static void callWriteXmlFile(Document doc, Writer w, String encoding) {
		try {
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(w);
			Transformer xformer = TransformerFactory.newInstance()
					.newTransformer();
			xformer.setOutputProperty(OutputKeys.ENCODING, encoding);//设置xml的编码
			xformer.setOutputProperty(OutputKeys.VERSION, "1.0");
			xformer.transform(source, result);
			xformer.setOutputProperty(OutputKeys.INDENT, "yes");//用于设置缩进的
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}

现在我们来看一段DES加密、解密的代码

import java.io.*;

import javax.crypto.*;
import java.security.*;

public class DESCryptoTest {
	public static void main(String[] args) {
		// Security.addProvider(new com.sun.crypto.provider.SunJCE());
		// Security.addProvider(new
		// org.bouncycastle.jce.provider.BouncyCastleProvider());
		KeyGenerator kg = null;
		try {
			// 指定算法,这里为DES;如果想用Blowfish算法,则用 getInstance("Blowfish")
			// BouncyCastle基本上支持所有通用标准算法
			kg = KeyGenerator.getInstance("DES");

			// 指定密钥长度,长度越高,加密强度越大
			kg.init(56);

			// 产生密钥
			Key key = kg.generateKey();
			System.out.println("Key format: " + key.getFormat());//RAW
			System.out.println("Key algorithm: " + key.getAlgorithm());//DES

			// 加密要用Cipher来实现
			Cipher cipher = Cipher.getInstance("DES");
			System.out.println("Cipher provider: " + cipher.getProvider());//SunJCE version 1.6
			System.out.println("Cipher algorithm: " + cipher.getAlgorithm());//DES
//**************
			byte[] data = "Hello World!".getBytes();
			System.out.println("Original data : [" + data.length + "]"
					+ new String(data));//[12]Hello World!

			// 设置加密模式
			cipher.init(Cipher.ENCRYPT_MODE, key);
			byte[] result = cipher.doFinal(data);
			System.out.println("Encrypted data: [" + result.length + "]"
					+ new String(result));//[16]C澵K墙憇`禃??

			// 设置解密模式
			cipher.init(Cipher.DECRYPT_MODE, key);
			byte[] original = cipher.doFinal(result);
			System.out.println("Decrypted data: [" + original.length + "]"
					+ new String(original));//[12]Hello World!
//*******************
			
			
			
			String filename = "d:\\待加密.xml";
			// 读入并加密文件
			try {
				// 输入流
				cipher.init(Cipher.ENCRYPT_MODE, key);
				BufferedInputStream in = new BufferedInputStream(
						new FileInputStream(filename));
				// 输出流
				CipherOutputStream out = new CipherOutputStream(
						new BufferedOutputStream(new FileOutputStream(
								"d:\\加密后.xml")), cipher);
				int i;
				do {
					i = in.read();
					if (i != -1)
						out.write(i);
				} while (i != -1);

				in.close();
				out.close();
				System.out.println("加密文件完成!");
			} catch (Exception ey5) {
				System.out.println("Error when encrypt the file");
				System.exit(0);
			}

			try {
				cipher.init(Cipher.DECRYPT_MODE, key);
				// 输出流
				BufferedOutputStream out = new BufferedOutputStream(
						new FileOutputStream("d:\\解密后.xml"));
				// 输入流
				CipherInputStream in = new CipherInputStream(
						new BufferedInputStream(new FileInputStream(
								"d:\\加密后.xml")), cipher);

				int i;
				do {
					i = in.read();
					if (i != -1)
						out.write(i);
				} while (i != -1);

				in.close();
				out.close();
				System.out.println("解密文件完成!");
			} catch (Exception ey5) {
				System.out.println("Error when encrypt the file");
				System.exit(0);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


要向writeToXML方法中加入加密的代码

起初的思路是:增删节点后---写出一个xml文件---读xml文件到内存---加密--输出加密后的文件----删除原未加密的文件

这种思路较好实现,但是有过多IO操作

后来的思路是:将xml文件的读写操作删掉,直接在内存中队xml加密

  这就需要将Document转化为inputStream,再通过CipherOutputStream加密后输出

将Document转化为inputStream:

一个简单需求,要将Document对象转成InputStream,在网上也没有找到方法。

辗转的解决了下:

//创建Document对象:
        Document xmldoc= new DocumentImpl();
        Element root = xmldoc.createElement("USERS");

//转成String:
        StringWriter strResponse = null;
        OutputFormat format = new OutputFormat(xmldoc);
        format.setEncoding("ISO-8859-1");
        format.setStandalone(true);
        format.setIndenting(true);
        format.setIndent(2);
        format.setLineSeparator(LineSeparator.Windows);
        strResponse = new StringWriter();
        XMLSerializer serializer = new XMLSerializer(strResponse, format);
        try {
            serializer.asDOMSerializer();
            serializer.serialize(xmldoc);
        } catch (IOException ex1) {
        }
        StringBuffer sb = strResponse.getBuffer();

//再由String转成InputStream 
        InputStream inputStream = new ByteArrayInputStream(sb.toString().getBytes());


所以writeToXML方法可以修改为

public static void writeToXML(String path, Document document) {

		String filename = path;
		System.out.println(path);
		try {
			// 创建Document对象:

			// 转成String:
			StringWriter strResponse = null;
			OutputFormat format = new OutputFormat(document);
			format.setEncoding("GB2312");
			// format.setStandalone(false);
			// format.setIndenting(true);
			// format.setIndent(2);
			// format.setLineSeparator(LineSeparator.Windows);
			strResponse = new StringWriter();
			XMLSerializer serializer = new XMLSerializer(strResponse, format);
			try {
				serializer.asDOMSerializer();
				serializer.serialize(document);
			} catch (IOException ex1) {
			}
			StringBuffer sb = strResponse.getBuffer();

			// 再由String转成InputStream
			InputStream inputStream = new ByteArrayInputStream(sb.toString()
					.getBytes());

			//
			// } catch (Exception e) {
			// e.printStackTrace();
			// }
			// try {
			// 生成一个实现指定转换的 Cipher 对象
			// 加密要用Cipher来实现
			Cipher cipher = Cipher.getInstance("DES");
			// 产生密钥
			Key key = CreateMyRegularKey("DES");
			System.out.println("Key format: " + key.getFormat());// RAW
			System.out.println("Key algorithm: " + key.getAlgorithm());// DES

			// 读入并加密文件
			try {
				// 输入流
				// 用密钥和随机源初始化此 cipher
				cipher.init(Cipher.ENCRYPT_MODE, key);
				BufferedInputStream in = new BufferedInputStream(inputStream);
				// 输出流
				CipherOutputStream out = new CipherOutputStream(
						new BufferedOutputStream(new FileOutputStream(path)),
						cipher);// 加密后.xml
				int i;
				do {
					i = in.read();
					if (i != -1)
					out.write(i);
				} while (i != -1);

				in.close();
				out.close();
				inputStream.close();
				System.out.println("加密文件完成!");

					} catch (Exception ey5) {
				System.out.println("Error when encrypt the file");
				System.exit(0);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

 

在getDocument方法中加入解密的代码
public static Document getDocument(String xmlPath) {

		Document document = null;
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder;

		try {
				// 解密要用Cipher来实现
				Cipher cipher = Cipher.getInstance("DES");
				System.out.println("get....Cipher algorithm: "
						+ cipher.getAlgorithm());// DES

				Key key = CreateMyRegularKey("DES");
				// 解密模式
				cipher.init(Cipher.DECRYPT_MODE, key);

				// 输入流
				CipherInputStream in = new CipherInputStream(
						new BufferedInputStream(new FileInputStream(xmlPath)),
						cipher);
				builder = factory.newDocumentBuilder();
                          //parse可以解析file、InputSource、InputStream和URL字符串 
				document = builder.parse(in);
				System.out.println("in");
				in.close();
			}

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

		return document;
	}


 


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
xml加密XML Encryption)是w3c加密xml的标准。这个加密过程包括加密xml文档的元素及其子元素,通过加密xml的初始内容将被替换,但其xml格式仍然被完好的保留。 介绍 我们有3个加密xml的方法 1、仅仅使用对称加密的方法加密xml 这种加密方法只使用一个密钥,也就是说无论是加密xml还是解密xml都使用一个相同的密钥。因为这个密钥不会在被加密xml中保存,所以我们需要在加密解密的过程中加载这个密钥并保护它不被窃取。 2、使用对称加密和非对称加密相结合的方法来加密xml 这种方法需要一个用于加密数据的对称密钥和一个用于保护这个对称密钥的非对称密钥。被加密的对称密钥和被加密的数据一起保存在xml文档中。当用私有非对称密钥解密密钥的时候要用公开非对称密钥对密钥进行加密。 本文就将使用这种方法。想学到其他更多的方法请参看MSDN等到更多的信息。 (译者注:非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。) 3、使用X.509加密xml,这种方法是用X.509作为非对称密钥,它由诸如VeriSign之类的第三方提供。 方法 不管xml加密是如何完成的,保存加密数据总是用两种方法之一。 1、加密后所有的元素都被命名为 2、加密后只有数据被替换,而元素名称仍然是可读的,不会发生变化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值