3つのXMLファイルのセットが与えられた場合:
first.xml
<root>
<item1>A</item1>
<complexItem>
<item2>B</item2>
<item3>C</item2>
</complexItem>
</root>
patch1.xml
<root>
<item1>X</item1>
</root>
patch2.xml
<root>
<complexItem>
<item3>Y</item>
</complexItem>
<differentItem>Z</differentItem>
<root>
最終的にXMLを作成したいと思います。
patched.xml
<root>
<item1>X</item1>
<complexItem>
<item2>B</item2>
<item3>Y</item2>
</complexItem>
<differentItem>Z</differentItem>
</root>
したがって、パッチの新しい要素は付加的であり、パッチの既存の要素は破壊的です。これらの追加と更新は、ドキュメントツリーの任意のレベルで実行できます。理想的には、これは引数としてファイルのリストを受け取ることができるMavenプラグインですが、Javaでのソリューション(つまり、利用可能なライブラリ-すでに行われているはずの何かを再発明することを避けようとしています!)は問題ありませんプラグインを自分で書くことができるので。各ファイル(ベースとパッチ)は常に同じルート要素を持ちます。
追加する必要があります。ツリーから要素を削除するユースケースはありません(ファイル置換の階層的な性質により、パッチが適用されたファイルを使用するアプリケーションのエラーケースになります)。構築済みのツールまたはライブラリをもう少し検索しましたが、適切なものが見つからなかったため、dom4jを使用してゼロから何かを構築するというAndrewのアドバイスを受けました。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;
}
}