给定一组三个 XML 文件:
第一个.xml
<root>
<item1>A</item1>
<complexItem>
<item2>B</item2>
<item3>C</item2>
</complexItem>
</root>
补丁1.xml
<root>
<item1>X</item1>
</root>
补丁2.xml
<root>
<complexItem>
<item3>Y</item>
</complexItem>
<differentItem>Z</differentItem>
<root>
我想以 XML 结尾:
补丁.xml
<root>
<item1>X</item1>
<complexItem>
<item2>B</item2>
<item3>Y</item2>
</complexItem>
<differentItem>Z</differentItem>
</root>
所以补丁中的新元素是附加的,而补丁中的现有元素是破坏性的。这些添加和更新可以在文档树的任何级别进行。理想情况下,这将是一个 maven 插件,它可以将文件列表作为参数,尽管 Java 中的解决方案(即可用库 - 我试图避免重新发明似乎应该已经完成的东西!)很好因为我可以自己编写插件。每个文件(基础和补丁)将始终具有相同的根元素。
我应该补充一点,没有从树中删除元素的用例(我们的文件替换的分层性质导致这对于使用修补文件的应用程序来说是一个错误情况)。我做了更多的搜索来寻找一个预先构建的工具或库,但找不到任何合适的东西,所以接受了 Andrew 的建议,即使用 dom4j 从头开始构建一些东西。对 dom4j 很不熟悉,但这大致是我想出的(没有审查/错误处理/正确评论等):
public void execute(){
// Environment specific file loading removed
SAXReader reader = new SAXReader();
Document patchedDocument = null;
for (InputStream is : loadedFiles) {
Document d = null;
try {
d = reader.read(is);
} catch (DocumentException e) {
e.printStackTrace();
}
if (patchedDocument == null) {
patchedDocument = d;
} else {
Element root = d.getRootElement();
patch(patchedDocument, root);
}
}
// Environment specific file writing
}
private void patch(Document patchedDocument, Element element) {
for (Iterator i = element.elementIterator(); i.hasNext();) {
Element nextElement = (Element) i.next();
if (nextElement.isTextOnly()) {
String path = nextElement.getUniquePath();
Node n = patchedDocument.selectSingleNode(path);
if (n != null)
{
// This already exists and needs content replacing
n.setText(nextElement.getText());
}else{
// This doesn't exist and needs to be added to the tree
addElement(patchedDocument, nextElement);
}
} else {
patch(patchedDocument, nextElement);
}
}
}
private Node addElement(Document patchedDocument, Element element)
{
Element parent = element.getParent();
String parentPath = parent.getPath();
Node n = patchedDocument.selectSingleNode(parentPath);
if (n == null){
return addElement(patchedDocument, parent);
} else {
((Branch)n).add(element.detach());
return n;
}
}