我的xml文章
xml转换: xml/map转换器
xml合并: xml合并
dupliate()方法思路图:
左报文为:
<PACKET> <HEAD> <REQUEST_TYPE>type1</REQUEST_TYPE> <ERROR_CODE>0001</ERROR_CODE> <ERROR_MESSAGE>message01</ERROR_MESSAGE> </HEAD> <BODY> <BOOK_LIST> <BOOK> <NAME>abc</NAME> <PRICE>12.3</PRICE> </BOOK> <BOOK> <NAME>same</NAME> <PRICE>4</PRICE> </BOOK> </BOOK_LIST> <VHL> <A>1</A> <B>3</B> <C>4</C> <D></D> </VHL> </BODY> </PACKET>
右报文为:
<PACKET> <HEAD> <REQUEST_TYPE>type2</REQUEST_TYPE> <ERROR_CODE>0002</ERROR_CODE> <ERROR_MESSAGE>message02</ERROR_MESSAGE> </HEAD> <BODY> <BOOK_LIST> <BOOK> <NAME>YUI</NAME> <PRICE>12.3</PRICE> </BOOK> <BOOK> <NAME>OIY</NAME> <PRICE>4</PRICE> </BOOK> </BOOK_LIST> <VHL> <A>89</A> <B>39</B> <C></C> <D>have</D> <E>00</E> </VHL> </BODY> </PACKET>
最终效果为:
<?xml version="1.0" encoding="UTF-8"?> <PACKET> <HEAD> <REQUEST_TYPE>type1|type2</REQUEST_TYPE> <ERROR_CODE>0001</ERROR_CODE> <ERROR_MESSAGE>message01</ERROR_MESSAGE> </HEAD> <BODY> <BOOK_LIST> <BOOK> <NAME>abc</NAME> <PRICE>12.3</PRICE> </BOOK> <BOOK> <NAME>same</NAME> <PRICE>4</PRICE> </BOOK> <BOOK> <NAME>YUI</NAME> <PRICE>12.3</PRICE> </BOOK> <BOOK> <NAME>OIY</NAME> <PRICE>4</PRICE> </BOOK> </BOOK_LIST> <VHL> <A>1</A> <B>3</B> <C>4</C> <D>have</D> <E>00</E> </VHL> </BODY> </PACKET>
同事文亮大师代码,非常棒,值得借鉴.抽空再找个时间来分析.(mark)
package d; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.lang.StringUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; //****************************************************************** /** * 类名:com.testdemo.pcis.common.utils.XMLMergeUtils * * <pre> * 描述: xml文件内容合并 * 基本思路: * public方法: * 特别说明: * 编写者:wlsun * Email:wlsun@isoftstone.com * 版权: Copyright (C) 2017 软通动力版权所有 * 创建时间:2017年2月23日 下午9:58:09 * 修改说明: 类的修改说明 * </pre> */ // ***************************************************************** public class XMLMergeUtils { /** * ****************************************************************** * XML文件的合并处理,不做任何处理,直接合并 <br><pre> * 方法xmlMerging2Str的详细说明 <br> * 编写者:wlsun * Email:wlsun@isoftstone.com * 创建时间:2017年2月25日 下午3:45:40 </pre> * @param mainXml 待合并处理的xml文件,合并后将更新此文件 * @param subXml 被合并的xml文件 * @return 合并成功返回合并版本,否则返回未合并报文第一个参数 * @throws Exception ******************************************************************* */ public static String xmlMerging2Str(String mainXml, String subXml) throws Exception { return xmlMerging2Str(mainXml, subXml, new HashMap(), new HashMap()); } //****************************************************************** /** * XML文件的合并处理 <br><pre> * 方法xmlMerging2Str的详细说明 <br> * 编写者:wlsun * Email:wlsun@isoftstone.com * 创建时间:2017年2月23日 下午10:38:37 </pre> * @param mainXml 待合并处理的xml文件,合并后将更新此文件 * @param subXml 被合并的xml文件 * @param Map<String, String> dupliateNodes 合并节点不替换集合 * 当前节点相同需要合并 如<COVERAGE_LIST> 中的 <COVERAGE>需要合并 * @param Map<String, String> dupliateTexts 合并节点内容替换集合 * 当前节点相同不合并节点,合并指定节点内容处理如<HEAD> 中的<REQUEST_TYPE> * @return 合并成功返回合并版本,否则返回未合并报文第一个参数 * @throws Exception */ //***************************************************************** public static String xmlMerging2Str(String mainXml, String subXml, Map<String, String> dupliateNodes, Map<String, String> dupliateTexts) throws Exception { if(dupliateNodes == null) dupliateNodes = new HashMap<String, String>(); if(dupliateTexts == null) dupliateTexts = new HashMap<String, String>(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = null; try { db = dbf.newDocumentBuilder(); } catch (ParserConfigurationException e) { e.printStackTrace(); System.err.println(e); // 出现异常时,输出异常信息 } Document doc_main = null; Document doc_vice = null; // 获取两个XML文件的Document try { doc_main = db.parse(new InputSource(new StringReader(mainXml))); doc_vice = db.parse(new InputSource(new StringReader(subXml))); } catch (Exception e) { e.printStackTrace(); System.err.println(e); } // 获取两个文件的根节点 Element root_main = (Element) doc_main.getDocumentElement(); Element root_vice = (Element) doc_vice.getDocumentElement(); // 下面添加被合并文件根节点下的每个节点 NodeList messageItems = root_vice.getChildNodes(); int item_number = messageItems.getLength(); // 如果去掉根节点下的第一个节点,那么i从item_number开始,否则i从1开始 for (int i = 1; i < item_number; i = i + 2) { // 调用dupliate(),依次复制被合并XML文档中根节点下的节点 Element messageItem = (Element) messageItems.item(i); dupliate(doc_main, root_main, messageItem, dupliateNodes, dupliateTexts); } String result = outResultString(doc_main); return result; } /** * ****************************************************************** * Document 转换为xml字符串内容<br><pre> * 方法outResultString的详细说明 <br> * 编写者:wlsun * Email:wlsun@isoftstone.com * 创建时间:2017年2月23日 下午10:38:37 </pre> * @param Document doc_main * @return String 说明 * @throws 异常类型 说明 ******************************************************************* */ private static String outResultString(Document doc_main) throws TransformerFactoryConfigurationError, IOException { // 创建输出(目标) 创建输出流 创建输出格式 StringWriter strWtr = new StringWriter(); StreamResult strResult = new StreamResult(strWtr); TransformerFactory tfac = TransformerFactory.newInstance(); String result = ""; try { javax.xml.transform.Transformer t = tfac.newTransformer(); // 设置xml的输出编码和是否去掉头文件 t.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); t.setOutputProperty(OutputKeys.INDENT, "yes"); t.setOutputProperty(OutputKeys.METHOD, "xml"); // xml, html, text t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); t.transform(new DOMSource(doc_main.getDocumentElement()), strResult); // 输出格式化的串到目标中,执行后。 result = strResult.getWriter().toString(); } catch (Exception e) { e.printStackTrace(); System.err.println("DocumentToXmlString error:" + e); } finally { if(strWtr != null) strWtr.close(); } return result; } //****************************************************************** /** * 合并节点 <br><pre> * 方法dupliate的详细说明 <br> * 编写者:wlsun * Email:wlsun@isoftstone.com * 创建时间:2017年2月23日 下午10:19:39 </pre> * @param Map<String, String> dupliateNodes 需合并节点不替换集合 * @param Map<String, String> dupliateTexts 需合并节点内容替换集合 * @return boolean 说明 * @throws Exception */ //***************************************************************** private static boolean dupliate(Document doc_dup, Element father, Element son, Map<String, String> dupliateNodes, Map<String, String> dupliateTexts) throws Exception { boolean isdone = false; Element parentElement = null; CopyChildElementObject childElementObject = isChildElement(father, son, dupliateNodes, dupliateTexts); if (!childElementObject.isNeedCopy()) { // 节点相同不用合并 isdone = true; parentElement = childElementObject.getElement(); } else if (childElementObject.getElement() != null) { parentElement = childElementObject.getElement(); } else { parentElement = father; } String son_name = son.getNodeName(); Element subITEM = null; if (!isdone) { subITEM = doc_dup.createElement(son_name); //判断是否存在子节点,存在则不取节点文本,否则取文本节点 NodeList sub_messageItems = son.getChildNodes(); int sub_item_number = sub_messageItems.getLength(); if (sub_item_number < 2) { subITEM.appendChild(doc_dup.createTextNode(son.getTextContent())); } // 复制节点的属性 if (son.hasAttributes()) { NamedNodeMap attributes = son.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { String attribute_name = attributes.item(i).getNodeName(); String attribute_value = attributes.item(i).getNodeValue(); subITEM.setAttribute(attribute_name, attribute_value); } } parentElement.appendChild(subITEM); } else { subITEM = parentElement; } // 复制子结点 NodeList sub_messageItems = son.getChildNodes(); int sub_item_number = sub_messageItems.getLength(); if (sub_item_number < 2) { // 如果没有子节点,则返回 isdone = true; } else { for (int j = 1; j < sub_item_number; j = j + 2) { // 如果有子节点,则递归调用本方法 Element sub_messageItem = (Element) sub_messageItems.item(j); isdone = dupliate(doc_dup, subITEM, sub_messageItem, dupliateNodes, dupliateTexts); } } return isdone; } //****************************************************************** /** * 判断是否存在子节点 <br><pre> * 方法isChildElement的详细说明 <br> * 编写者:wlsun * Email:wlsun@isoftstone.com * 创建时间:2017年2月23日 下午10:20:12 </pre> * @param Element father * @param Element son * @param Map<String, String> dupliateNodes 需合并节点不替换集合 * @param Map<String, String> dupliateTexts 需合并节点内容替换集合 * @return CopyChildElementObject 说明 * @throws 异常类型 说明 */ //***************************************************************** private static CopyChildElementObject isChildElement(Element father, Element son, Map<String, String> dupliateNodes, Map<String, String> dupliateTexts) { CopyChildElementObject childElementObject = new CopyChildElementObject(); NodeList messageItems = father.getChildNodes(); int item_number = messageItems.getLength(); // 首先遍历所有节点,查找是否有完全相同的节点,防止同一节点已定义多次 for (int i = 1; i < item_number; i = i + 2) { Element messageItem = (Element) messageItems.item(i); if (!messageItem.getNodeName().equals(son.getNodeName())) { continue; } if (messageItem.isEqualNode(son)) {// 同时判断子节点是否一致 childElementObject.setNeedCopy(false); childElementObject.setElement(messageItem); return childElementObject; } } for (int i = 1; i < item_number; i = i + 2) { Element messageItem = (Element) messageItems.item(i); // 判断节点是否处于同一级别 String msgItemNodeName = messageItem.getNodeName(); if (!msgItemNodeName.equals(son.getNodeName())) { continue; } if (isEqualNode(messageItem, son)) {// 仅判断当前节点是否一致 if (hasEqualAttributes(messageItem, son) && !msgItemNodeName.equalsIgnoreCase(dupliateNodes.get(msgItemNodeName))) { // 1、当前节点完全相同不需要合并 // 2、当前节点相同需要合并 如<COVERAGE_LIST> 中的 <COVERAGE>需要合并 // 3、当前节点相同不合并节点,合并指定节点内容处理如<HEAD> 中的<REQUEST_TYPE> String keyName = messageItem.getParentNode().getNodeName() + "/" + msgItemNodeName; if(keyName.equals(dupliateTexts.get(keyName))) { messageItem.setTextContent(messageItem.getTextContent() + "|" + son.getTextContent()); } else { //4、当前节点相同,报文一节点不存在内容,报文二节点存在内容,已存在内容的替换 if("".equals(messageItem.getTextContent()) && !"".equals(son.getTextContent())) { messageItem.setTextContent(son.getTextContent()); } } childElementObject.setNeedCopy(false); childElementObject.setElement(messageItem); return childElementObject; } else {// 当前节点的属性不相同,需要合并 childElementObject.setNeedCopy(true); childElementObject.setElement(father); return childElementObject; } } } // 目标文档该节点不存在,需要合并到目标文档中 childElementObject.setNeedCopy(true); childElementObject.setElement(father); return childElementObject; } //****************************************************************** /** * 判断两个节点是否相同,未判断节点的属性<br><pre> * 方法isEqualNode的详细说明 <br> * 编写者:wlsun * Email:wlsun@isoftstone.com * 创建时间:2017年2月23日 下午10:20:35 </pre> * @param 参数类型 参数名 说明 * @return boolean 说明 */ //****************************************************************** private static boolean isEqualNode(Node arg0, Node arg) { if (arg == arg0) { return true; } if (arg.getNodeType() != arg0.getNodeType()) { return false; } if (arg0.getNodeName() == null) { if (arg.getNodeName() != null) { return false; } } else if (!arg0.getNodeName().equals(arg.getNodeName())) { return false; } if (arg0.getLocalName() == null) { if (arg.getLocalName() != null) { return false; } } else if (!arg0.getLocalName().equals(arg.getLocalName())) { return false; } if (arg0.getNamespaceURI() == null) { if (arg.getNamespaceURI() != null) { return false; } } else if (!arg0.getNamespaceURI().equals(arg.getNamespaceURI())) { return false; } if (arg0.getPrefix() == null) { if (arg.getPrefix() != null) { return false; } } else if (!arg0.getPrefix().equals(arg.getPrefix())) { return false; } if (arg0.getNodeValue() == null) { if (arg.getNodeValue() != null) { return false; } } else if (!arg0.getNodeValue().equals(arg.getNodeValue())) { return false; } return true; } //****************************************************************** /** * 判断节点的属性是否相同<br><pre> * 方法hasEqualAttributes的详细说明 <br> * 编写者:wlsun * Email:wlsun@isoftstone.com * 创建时间:2017年2月23日 下午10:22:29 </pre> * @param 参数类型 参数名 说明 * @return boolean 说明 * @throws 异常类型 说明 */ //***************************************************************** private static boolean hasEqualAttributes(Node arg0, Node arg) { NamedNodeMap map1 = arg0.getAttributes(); NamedNodeMap map2 = arg.getAttributes(); int len = map1.getLength(); if (len != map2.getLength()) { return false; } for (int i = 0; i < len; i++) { Node n1 = map1.item(i); if (n1.getNodeName() != null) { Node n2 = map2.getNamedItem(n1.getNodeName()); if (n2 == null) { return false; } else if (!n1.getNodeValue().equals(n2.getNodeValue())) { return false; } } } return true; } public static void main(String[] args) { try { FileHelper fileHelper = new FileHelper(); String sourcefile = "src/d/file1.xml"; String main = fileHelper.readTxt(sourcefile, "UTF-8"); String targetfile = "src/d/file2.xml"; String sub = fileHelper.readTxt(targetfile, "UTF-8"); long start = new Date().getTime(); Map<String, String> dupliateNodes = new HashMap<String, String>(); dupliateNodes.put("COVERAGE", "COVERAGE"); Map<String, String> dupliateTexts = new HashMap<String, String>(); dupliateTexts.put("HEAD/REQUEST_TYPE", "HEAD/REQUEST_TYPE"); String mergStr = XMLMergeUtils.xmlMerging2Str(main, sub, dupliateNodes, dupliateTexts); long end = new Date().getTime(); System.out.println(mergStr); System.out.println((end-start)); } catch (Exception e) { e.printStackTrace(); } } } //****************************************************************** /** * 类名:com.isoftstone.pcis.common.utils.CopyChildElementObject <pre> * 描述: 复制子节点对象, 记录该节点是否需要复制, 记录该节点的父节点 * 基本思路: * public方法: * 特别说明: * 编写者:wlsun * Email:wlsun@isoftstone.com * 版权: Copyright (C) 2017 软通动力版权所有 * 创建时间:2017年2月23日 下午10:39:45 * 修改说明: 类的修改说明 * </pre> */ //***************************************************************** class CopyChildElementObject { private boolean needCopy = true;// 记录该节点是否需要复制 private Element element = null;// 记录该节点的父节点 public CopyChildElementObject() { super(); } public boolean isNeedCopy() { return needCopy; } public void setNeedCopy(boolean needCopy) { this.needCopy = needCopy; } public Element getElement() { return element; } public void setElement(Element element) { this.element = element; } }