Canonicalize XML in Java

  sonic0002        2016-01-20 01:39:45       18,988        0          English  简体中文  繁体中文  ภาษาไทย  Tiếng Việt 

การทำให้ XML เป็นมาตรฐานมักใช้เมื่อมีความจำเป็นต้องสร้างลายเซ็นดิจิทัลเพื่อส่งให้คู่ค้าตรวจสอบ เนื่องจากลายเซ็นดิจิทัลสร้างขึ้นจากข้อมูล XML ข้อมูล XML จึงต้องถูกทำให้เป็นมาตรฐานก่อนจึงจะสามารถคำนวณค่าลายเซ็นได้ แม้แต่ช่องว่างพิเศษก็อาจส่งผลต่อค่าลายเซ็นที่คำนวณได้ ดังนั้นจึงต้องปฏิบัติตามกฎบางอย่างเพื่อทำให้ข้อมูล XML เป็นมาตรฐานเพื่อให้มีรูปแบบมาตรฐาน นี่คือเหตุผลที่ W3C สร้างข้อกำหนด Canonical XML Version 1.1

ข้อกำหนดนี้มีกฎในการจัดรูปแบบโหนดองค์ประกอบ โหนดแอตทริบิวต์ และโหนดเนมสเปซ ฯลฯ ภาษาโปรแกรมต่างๆ ได้นำข้อกำหนดนี้ไปใช้เพื่อให้เราสามารถใช้เพื่อทำให้ข้อมูล XML เป็นมาตรฐานได้อย่างง่ายดายโดยไม่ต้องทราบรายละเอียดเกี่ยวกับข้อกำหนด

ในบทช่วยสอนนี้ เราจะไม่ลงรายละเอียดในข้อกำหนด เราจะเน้นเฉพาะวิธีการเรียก Java API เพื่อทำให้ข้อมูล XML เป็นมาตรฐานเท่านั้น ตาม XPath data model เอกสาร XML แสดงด้วยชุดของโหนด -- ชุดโหนด ในขณะที่ XML API ใน Java รับออบเจ็กต์ Data ที่จะทำให้เป็นมาตรฐาน เพื่อสาธิตการทำให้เป็นมาตรฐาน เราจะสร้าง NodeSetDataImpl ที่กำหนดเองซึ่งใช้ NodeSetData และอินเทอร์เฟซ Iterator

import java.util.Iterator;
import javax.xml.crypto.NodeSetData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.NodeIterator;

public class NodeSetDataImpl implements NodeSetData, Iterator {
	private Node ivNode;
	private NodeFilter ivNodeFilter;
	private Document ivDocument;
	private DocumentTraversal ivDocumentTraversal;
	private NodeIterator ivNodeIterator;
	private Node ivNextNode;

	public NodeSetDataImpl(Node pNode, NodeFilter pNodeFilter) throws Exception {
		ivNode = pNode;
		ivNodeFilter = pNodeFilter;

		if (ivNode instanceof Document) {
			ivDocument = (Document) ivNode;
		} else {
			ivDocument = ivNode.getOwnerDocument();
		}

		ivDocumentTraversal = (DocumentTraversal) ivDocument;
	}

	private NodeSetDataImpl(NodeIterator pNodeIterator) {
		ivNodeIterator = pNodeIterator;
	}

	public Iterator iterator() {
		NodeIterator nodeIterator = ivDocumentTraversal.createNodeIterator(ivNode, NodeFilter.SHOW_ALL, ivNodeFilter, false);
		return new NodeSetDataImpl(nodeIterator);
	}

	private Node checkNextNode() {
		if (ivNextNode == null && ivNodeIterator != null) {
			ivNextNode = ivNodeIterator.nextNode();
			if (ivNextNode == null) {
				ivNodeIterator.detach();
				ivNodeIterator = null;
			}
		}
		return ivNextNode;
	}

	private Node consumeNextNode() {
		Node nextNode = checkNextNode();
		ivNextNode = null;
		return nextNode;
	}

	public boolean hasNext() {
		return checkNextNode() != null;
	}

	public Node next() {
		return consumeNextNode();
	}

	public void remove() {
		throw new UnsupportedOperationException("Removing nodes is not supported.");
	}

	public static NodeFilter getRootNodeFilter() {
		return new NodeFilter() {
			public short acceptNode(Node pNode) {
				if (pNode instanceof Element && pNode.getParentNode() instanceof Document) {
					return NodeFilter.FILTER_SKIP;
				}
				return NodeFilter.FILTER_ACCEPT;
			}
		};
	}
}

จากนั้นเราต้องสร้าง CanonicalizationMethod เพื่อดำเนินการทำให้เป็นมาตรฐานจริง มีตัวเลือกสองสามตัวที่นี่:

CanonicalizationMethod.INCLUSIVE
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS
CanonicalizationMethod.EXCLUSIVE
CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS

ในบทช่วยสอนนี้ เราจะสาธิตเฉพาะการทำให้เป็นมาตรฐานแบบรวมเท่านั้น ด้านล่างนี้คือโค้ดเพื่อทำสิ่งนี้

import java.io.ByteArrayInputStream;
import javax.xml.crypto.Data;
import javax.xml.crypto.OctetStreamData;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

public class CanonicalizationTest {
	private static String INPUT = 
			"" +
			"hello" +
			"world" +
			"";
	
	public static void main(String[] args){
		transform(INPUT);
	}
	
	/**
	 * Create new document with data
	 * 
	 * @param xml
	 * @return
	 */
	private static Document createNewDocument(String xml){
		try{
			byte[] bytes = xml.getBytes("UTF-8");
			ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
			
			DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance();
			fac.setNamespaceAware(true);
			
			DocumentBuilder docBuilder = fac.newDocumentBuilder();
			
			Document doc = docBuilder.parse(bin);

			return doc;
		} catch (Exception ex){
			ex.printStackTrace();
		}
		return null;
	}
	
	/**
	 * Transform a XML string
	 * 
	 * @param xml
	 */
	private static void transform(String xml){
		Document doc = createNewDocument(xml);
		
		try{
			Data data = new NodeSetDataImpl(doc, NodeSetDataImpl.getRootNodeFilter());
			XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
			CanonicalizationMethod canonicalizationMethod = fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec)null);
			// Doing the actual canonicalization
			OctetStreamData transformedData =(OctetStreamData) canonicalizationMethod.transform(data, null);
			byte[] bytes = tool.Util.readStream(transformedData.getOctetStream());
			String str = new String(bytes);
			System.out.println(str);
		} catch (Exception ex){
			ex.printStackTrace();
		}
	}
}

มาดูผลลัพธ์กันก่อน:

<my:Node xmlns:my="http://example.com" Id="1">hello</my:Node><my:Node xmlns:my="http://example.com" Id="2">world</my:Node>

การทดสอบจะสร้าง Document ก่อน จากนั้น Document นี้จะถูกส่งไปยัง NodeSetDataImpl เพื่อสร้างชุดโหนดที่จะทำให้เป็นมาตรฐาน จากเอาต์พุต เราจะเห็นว่าโหนด Root ถูกลบออกในข้อมูลที่ทำให้เป็นมาตรฐาน นี่เป็นเพราะ NodeFilter ใน NodeSetDataImpl ได้กรองโหนดนี้ออกไป ถัดไป my:Node ที่สองมีโหนด xmlns:my ก่อนโหนด Id ในรูปแบบที่ทำให้เป็นมาตรฐาน นี่เป็นไปตามข้อกำหนด Canonical XML ที่โหนดควรอยู่ในลำดับตามตัวอักษร

สำหรับวิธีการทำให้เป็นมาตรฐานอื่นๆ ตรรกะก็เหมือนกันที่นี่ ความแตกต่างคือเอาต์พุตไม่เหมือนกันเนื่องจากวิธีการทำให้เป็นมาตรฐานที่แตกต่างกันมีกฎที่แตกต่างกัน

JAVA  JAVA SECURITY  XML 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

Drinking is really a good way of decompression