import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

class XmlMerge {

    public static void main(String[] args) {
        if (args == null || args.length != 3) {
            System.out.println("Usage: java -jar XmlMerge.jar"
                    + " <base-xml> <source-xml> <out-xml>");
            System.exit(1);
        }
        File baseXml = new File(args[0]);
        File sourceXml = new File(args[1]);
        File outXml = new File(args[2]);
        merge(baseXml, sourceXml, outXml);
    }

    private static void merge(File baseXml, File sourceXml, File outXml) {
        try {
            JAXBContext jaxb = JAXBContext.newInstance(Data.class);
            Unmarshaller reader = jaxb.createUnmarshaller();
            Marshaller writer = jaxb.createMarshaller();
            writer.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            
            Data baseData = (Data) reader.unmarshal(baseXml);
            Data sourceData = (Data) reader.unmarshal(sourceXml);
            baseData.getLineMap().putAll(sourceData.getLineMap());
            
            writer.marshal(baseData, outXml);
        } catch (JAXBException ex) {
            System.err.println(ex);
        }
    }
}


@XmlRootElement(name = "data")
class Data {
    Map<String, String> lineMap = new LinkedHashMap<>();
    
    @XmlElement(name = "line")
    public List<Line> getLines() {
        List<Line> lines = new ArrayList<>();
        for (Map.Entry<String, String> entry : lineMap.entrySet()) {
            Line line = new Line();
            line.setKey(entry.getKey());
            line.setData(entry.getValue());
            lines.add(line);
        }
        return lines;
    }
    
    public void setLines(List<Line> lines) {
        for (Line line : lines) {
            lineMap.put(line.getKey(), line.getData());
        }
    }

    @XmlTransient
    public Map<String, String> getLineMap() {
        return lineMap;
    }

    public void setLineMap(Map<String, String> lineMap) {
        this.lineMap = lineMap;
    }
}

@XmlRootElement(name = "line")
class Line {
    private String key;
    private String data;

    @XmlAttribute(name = "key", required = true)
    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }
    
    @XmlElement(name = "data")
    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
    
}
