如何在Java中合并两个XML

| 我正在尝试在Java中合并两个xml。我正在使用STaX API编写这些XML。我在互联网上搜索了很多有关如何合并xml的内容,但似乎没有一个比C#更为直接。使用StAX在Java中有任何简单的方法吗?由于文件大小可能很大,因此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>
合并文件
<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>
    
已邀请:
我有一个适合我的解决方案。现在专家,请告知这是否可行。 谢谢, -尼罗什
    XMLEventWriter eventWriter;
    XMLEventFactory eventFactory;
    XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
    XMLInputFactory inputFactory = XMLInputFactory.newInstance();
    eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(\"testMerge1.xml\"));
    eventFactory = XMLEventFactory.newInstance();
    XMLEvent newLine = eventFactory.createDTD(\"\\n\");                
    // Create and write Start Tag
    StartDocument startDocument = eventFactory.createStartDocument();
    eventWriter.add(startDocument);
    eventWriter.add(newLine);
    StartElement configStartElement = eventFactory.createStartElement(\"\",\"\",\"TestCaseBlock\");
    eventWriter.add(configStartElement);
    eventWriter.add(newLine);
    String[] filenames = new String[]{\"test1.xml\", \"test2.xml\",\"test3.xml\"};
    for(String filename:filenames){
           XMLEventReader test = inputFactory.createXMLEventReader(filename,
                             new FileInputStream(filename));
        while(test.hasNext()){
            XMLEvent event= test.nextEvent();
        //avoiding start(<?xml version=\"1.0\"?>) and end of the documents;
        if (event.getEventType()!= XMLEvent.START_DOCUMENT && event.getEventType() != XMLEvent.END_DOCUMENT)
                eventWriter.add(event);         
        eventWriter.add(newLine);
            test.close();
        }           
    eventWriter.add(eventFactory.createEndElement(\"\", \"\", \"TestCaseBlock\"));
    eventWriter.add(newLine);
    eventWriter.add(eventFactory.createEndDocument());
    eventWriter.close();
    
通用解决方案仍然是XSLT,但是您首先需要使用包装元素将两个文件合并为一个大XML(XSLT使用一个输入源)。
<root>
    <TestCaseBlock>
        <TestCase TestCaseID=\"1\">
        ...
        </TestCase>
    </TestCaseBlock>
    <TestCaseBlock>
        <TestCase TestCaseID=\"2\">
        ...
        </TestCase>
    </TestCaseBlock>
</root>
然后只需对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内编译并执行。     
如果结构足够规则,则可以使用数据绑定,我实际上会考虑使用JAXB将两个文件中的XML绑定到对象中,然后合并对象,并序列化为XML。 如果文件很大,您也可以绑定子树。为此,您使用XMLStreamReader(来自Stax api,javax.xml.stream)来迭代到作为根元素的元素,将该元素(及其子元素)绑定到所需的对象,并迭代到下一个根元素。     
检查XmlCombiner,这是一个完全以这种方式实现XML合并的Java库。它大致基于plexus-utils库提供的类似功能。 在您的情况下,还应该根据属性\'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);
免责声明:我是图书馆的作者。     
我认为XSLT和SAX可能是一个解决方案。 如果您将STaX作为解决方案与Stream一起使用,请阅读Sun教程,我认为这非常有帮助: STaX上的Sun Tutorail 再见     
您可以将XML视为文本文件并将其组合。与其他方法相比,这非常快。请看下面的代码:
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;
    }
}
    

要回复问题请先登录注册