如何在Java中合并两个XML

如何在Java中合并两个XML,java,xml,merge,stax,Java,Xml,Merge,Stax,我正在尝试在Java中合并两个XML。我正在使用staxapi编写这些xml。我在互联网上搜索了很多关于如何合并XML的内容,但没有一个像这样直截了当。在Java中使用StAX有没有直接的方法可以做到这一点?xslt可能不是正确的解决方案,因为文件大小可能很大 File1.xml <TestCaseBlock> <TestCase TestCaseID="1"> <Step ExecutionTime="2011-03-29 12:08:31

我正在尝试在Java中合并两个XML。我正在使用staxapi编写这些xml。我在互联网上搜索了很多关于如何合并XML的内容,但没有一个像这样直截了当。在Java中使用StAX有没有直接的方法可以做到这一点?xslt可能不是正确的解决方案,因为文件大小可能很大

File1.xml

<TestCaseBlock>
    <TestCase TestCaseID="1">
        <Step ExecutionTime="2011-03-29 12:08:31 EST">
            <Status>Passed</Status>
            <Description>foo</Description>
            <Expected>foo should pass</Expected>
            <Actual>foo passed</Actual>
        </Step>
       </TestCase>
</TestCaseBlock> 

通过
福
福应该通过
福通过
File2.xml

<TestCaseBlock>
    <TestCase TestCaseID="2">
        <Step ExecutionTime="2011-03-29 12:08:32 EST">
            <Status>Failed</Status>
            <Description>test something</Description>
            <Expected>something expected</Expected>
            <Actual>not as expected</Actual>
        </Step>
    </TestCase>
</TestCaseBlock>

失败
试验
期待的事情
不像预期的那样
Merged.xml

<TestCaseBlock>
<TestCase TestCaseID="1">
    <Step ExecutionTime="2011-03-29 12:08:33 EST">
        <Status>Passed</Status>
        <Description>foo</Description>
        <Expected>foo should pass</Expected>
        <Actual>foo passed</Actual>
    </Step>
</TestCase>
<TestCase TestCaseID="2">
    <Step ExecutionTime="2011-03-29 12:08:34 EST">
        <Status>Failed</Status>
        <Description>test something</Description>
        <Expected>something expected</Expected>
        <Actual>not as expected</Actual>
    </Step>
</TestCase>
</TestCaseBlock>

通过
福
福应该通过
福通过
失败
试验
期待的事情
不像预期的那样

一般的解决方案仍然是XSLT,但您需要首先使用包装器元素将两个文件合并成一个大XML(XSLT与一个输入源一起工作)


...
...
然后只需对match=“//TestCase”执行XSLT,并转储所有测试用例,忽略它们所属的测试用例块

在您尝试之前,不要担心性能。JAva中的XML API比2003年要好得多

这是您需要的样式表:

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/">
            <TestCaseBlock>
                <xsl:apply-templates/>
            </TestCaseBlock>
    </xsl:template>

    <xsl:template match="//TestCase">
          <xsl:copy-of select="."/> 
    </xsl:template>

</xsl:stylesheet>

经过测试,它是有效的


顺便说一句,这个XSLT是在这个(小)示例上以1ms的时间编译和执行的。

我认为XSLT和SAX可能是一个解决方案

如果您使用的是STaX是解决方案的Stream,我阅读了Sun教程,我认为这非常有帮助:


拜尔

如果结构足够规则,所以可以使用数据绑定,我会考虑使用JAXB将两个文件中的XML绑定到对象,然后合并对象,将其序列化为XML。
如果文件大小很大,也可以绑定子树;为此,您可以使用XMLStreamReader(来自Stax api,javax.xml.stream)迭代到根元素,将该元素(及其子元素)绑定到您想要的对象,迭代到下一个根元素。

我有一个适合我的解决方案。现在,专家们,请建议这是否是一条可行之路

谢谢, -尼利斯

XMLEventWriter事件编写器;
XMLEventFactory事件工厂;
XMLOutputFactory outputFactory=XMLOutputFactory.newInstance();
XMLInputFactory inputFactory=XMLInputFactory.newInstance();
eventWriter=outputFactory.createXMLEventWriter(新文件outputStream(“testMerge1.xml”);
eventFactory=XMLEventFactory.newInstance();
XMLEvent newLine=eventFactory.createDTD(“\n”);
//创建并写入开始标记
StartDocument StartDocument=eventFactory.createStartDocument();
eventWriter.add(startDocument);
eventWriter.add(换行符);
StartElement configStartElement=eventFactory.createStartElement(“,”,“TestCaseBlock”);
添加(配置StartElement);
eventWriter.add(换行符);
String[]filenames=新字符串[]{“test1.xml”、“test2.xml”、“test3.xml”};
for(字符串文件名:文件名){
XMLEventReader测试=inputFactory.createXMLEventReader(文件名,
新文件输入流(文件名));
while(test.hasNext()){
XMLEvent事件=test.nextEvent();
//避免文档的开始()和结束;
if(event.getEventType()!=XMLEvent.START\u文档和event.getEventType()!=XMLEvent.END\u文档)
添加(事件);
eventWriter.add(换行符);
test.close();
}           
添加(eventFactory.createEndElement(“,”,“TestCaseBlock”);
eventWriter.add(换行符);
添加(eventFactory.createEndDocument());
eventWriter.close();
检查哪一个Java库正是以这种方式实现XML合并的。它松散地基于库提供的类似功能

在您的情况下,还应根据属性“TestCaseID”的值匹配标记。以下是完整示例:

import org.atteo.xmlcombiner.XmlCombiner;

// create combiner
XmlCombiner combiner = new XmlCombiner("TestCaseID");
// combine files
combiner.combine(firstFile);
combiner.combine(secondFile);
// store the result
combiner.buildDocument(resultFile);

免责声明:我是图书馆的作者。

可以将XML视为文本文件并将它们组合起来。与其他方法相比,这是非常快的。请看下面的代码:-< /p>
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class XmlComb {

    static Set<String> lstheader = new HashSet<String>();

    public static void main(String[] args) throws IOException {
        Map<String,List<String>> map1 = getMapXml("J:\\Users\\Documents\\XMLCombiner01\\src\\main\\resources\\File1.xml");
        Map<String,List<String>> map2 = getMapXml("J:\\Users\\Documents\\XMLCombiner01\\src\\main\\resources\\File2.xml");
        Map<String,List<String>> mapCombined = combineXML(map1, map2);

        lstheader.forEach( lst -> {
            System.out.println(lst);
        });

        try {
            mapCombined.forEach((k,v) -> {

                System.out.println(k);
                v.forEach(val -> System.out.println(val));


            });
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static Map<String,List<String>> combineXML(Map<String, List<String>> map1, Map<String, List<String>> map2 ) {

        Map<String,List<String>> map2Modified = new TreeMap<String, List<String>>();
        Map<String,List<String>> mapCombined = new TreeMap<String, List<String>>();
        // --- Modifying map ---
            for(String strKey2 : map2.keySet()) {

                if(map1.containsKey(strKey2)) {
                    map2Modified.put(strKey2.split("\">")[0] + "_1\">", map2.get(strKey2));
                }
                else {
                    map2Modified.put(strKey2 , map2.get(strKey2));
                }
            }   

            //---- Combining map ---

            map1.putAll(map2Modified);

            return map1;
    }


     public static Map<String,List<String>> getMapXml(String strFilePath) throws IOException{
         File file = new File(strFilePath);

        BufferedReader br = new BufferedReader(new FileReader(file));
        Map<String, List<String>> testMap = new TreeMap<String, List<String>>();
        List<String> lst = null;

        String st;
        String strCatalogName = null;
        while ((st = br.readLine()) != null) {
            //System.out.println(st);
            if(st.toString().contains("<TestCase")){
                lst = new ArrayList<String>();
                strCatalogName = st;
                testMap.put(strCatalogName, lst);
            }
            else if(st.contains("</TestCase")){
                lst.add(st);
                testMap.put(strCatalogName,lst);
            }
            else {
                if(lst != null){
                    lst.add(st);
                }else {
                    lstheader.add(st);
                }

            }

        }

        return testMap;
    }
}
import java.io.*;
导入java.util.ArrayList;
导入java.util.HashMap;
导入java.util.HashSet;
导入java.util.List;
导入java.util.Map;
导入java.util.Set;
导入java.util.TreeMap;
公共类XmlComb{
静态集合lstheeader=newhashset();
公共静态void main(字符串[]args)引发IOException{
Map map1=getMapXml(“J:\\Users\\Documents\\XMLCombiner01\\src\\main\\resources\\File1.xml”);
Map map2=getMapXml(“J:\\Users\\Documents\\XMLCombiner01\\src\\main\\resources\\File2.xml”);
Map mapCombined=combineXML(map1,map2);
lstheader.forEach(lst->{
系统输出打印项次(lst);
});
试一试{
mapCombined.forEach((k,v)->{
系统输出println(k);
v、 forEach(val->System.out.println(val));
});
}捕获(例外e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
公共静态映射组合XML(映射map1、映射map2){
Map map2Modified=new TreeMap();
Map mapCombined=新树映射();
//---修改地图---
for(字符串strKey2:map2.keySet()){
if(地图1.containsKey(strKey2)){
map2Modified.put(strKey2.split(“\”>”)[0]+“\u 1\”>”,map2.get(strKey2));
}
否则{
map2Modified.put(strKey2,map2.get(strKey2));
}
}   
//----组合图---
map1.putAll(map2Modified);
返回map1;
}
公共静态映射getMapXml(Str
import org.atteo.xmlcombiner.XmlCombiner;

// create combiner
XmlCombiner combiner = new XmlCombiner("TestCaseID");
// combine files
combiner.combine(firstFile);
combiner.combine(secondFile);
// store the result
combiner.buildDocument(resultFile);
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class XmlComb {

    static Set<String> lstheader = new HashSet<String>();

    public static void main(String[] args) throws IOException {
        Map<String,List<String>> map1 = getMapXml("J:\\Users\\Documents\\XMLCombiner01\\src\\main\\resources\\File1.xml");
        Map<String,List<String>> map2 = getMapXml("J:\\Users\\Documents\\XMLCombiner01\\src\\main\\resources\\File2.xml");
        Map<String,List<String>> mapCombined = combineXML(map1, map2);

        lstheader.forEach( lst -> {
            System.out.println(lst);
        });

        try {
            mapCombined.forEach((k,v) -> {

                System.out.println(k);
                v.forEach(val -> System.out.println(val));


            });
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static Map<String,List<String>> combineXML(Map<String, List<String>> map1, Map<String, List<String>> map2 ) {

        Map<String,List<String>> map2Modified = new TreeMap<String, List<String>>();
        Map<String,List<String>> mapCombined = new TreeMap<String, List<String>>();
        // --- Modifying map ---
            for(String strKey2 : map2.keySet()) {

                if(map1.containsKey(strKey2)) {
                    map2Modified.put(strKey2.split("\">")[0] + "_1\">", map2.get(strKey2));
                }
                else {
                    map2Modified.put(strKey2 , map2.get(strKey2));
                }
            }   

            //---- Combining map ---

            map1.putAll(map2Modified);

            return map1;
    }


     public static Map<String,List<String>> getMapXml(String strFilePath) throws IOException{
         File file = new File(strFilePath);

        BufferedReader br = new BufferedReader(new FileReader(file));
        Map<String, List<String>> testMap = new TreeMap<String, List<String>>();
        List<String> lst = null;

        String st;
        String strCatalogName = null;
        while ((st = br.readLine()) != null) {
            //System.out.println(st);
            if(st.toString().contains("<TestCase")){
                lst = new ArrayList<String>();
                strCatalogName = st;
                testMap.put(strCatalogName, lst);
            }
            else if(st.contains("</TestCase")){
                lst.add(st);
                testMap.put(strCatalogName,lst);
            }
            else {
                if(lst != null){
                    lst.add(st);
                }else {
                    lstheader.add(st);
                }

            }

        }

        return testMap;
    }
}