xml合并工具【原】

我的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>
View Code

 

右报文为:
<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>
View Code

 

最终效果为:
<?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>
View Code

 

 同事文亮大师代码,非常棒,值得借鉴.抽空再找个时间来分析.(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;
    }
}

 

转载于:https://www.cnblogs.com/whatlonelytear/p/6444994.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值