You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java插入XML节点时属性值丢失问题求助

问题:合并XML节点时属性值全部丢失

我尝试将一个XML文档中的一组节点插入到另一个XML文档的指定节点中,按照相关方案实现后,却发现导入的节点所有属性值都被移除了。

示例XML

XML1(目标文档)

<letterContent> 
  <key1>key1</key1> 
  <key2>key2</key2> 
  <type>456</type> 
  <object1>789</object1> 
  <effectiveDate>00</effectiveDate> 
  <expandedData attr1="case1"> 
    <expandedData attr2="value2"> 
      <data attrD="VD2">value D2</data> 
    </expandedData> 
    <expandedData attr3="value3"> 
      <data attrD="vd3">value D3</data> 
    </expandedData> 
  </expandedData>
</letterContent>

XML2(待插入的节点)

<expandedData attr4="value4"> 
  <data attrd4="vd4">value d4</data> 
  <name nameattr="specific_name"/> 
</expandedData>

期望结果

<letterContent> 
  <key1>key1</key1> 
  <key2>key2</key2> 
  <type>456</type> 
  <object1>789</object1> 
  <effectiveDate>00</effectiveDate> 
  <expandedData attr1="case1"> 
    <expandedData attr2="value2"> 
      <data attrD="VD2">value D2</data> 
    </expandedData> 
    <expandedData attr3="value3"> 
      <data attrD="vd3">value D3</data> 
    </expandedData> 
    <expandedData attr4="value4"> 
      <data attrd4="vd4">value d4</data> 
      <name nameattr="specific_name"/> 
    </expandedData> 
  </expandedData>
</letterContent>

我使用的Java代码

package org.test.XMLMERGE; 
import static javax.xml.xpath.XPathConstants.*; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult; 
import javax.xml.xpath.*; 
import org.w3c.dom.*; 
import org.xml.sax.InputSource; 

public class Xml2into1 { 
  public static void main(String[] args) throws Exception { 
    // read from files 
    InputSource xml1 = new InputSource("R:/java/dev/tmp/dest.xml"); 
    InputSource xml2 = new InputSource("R:/java/dev/tmp/orig2.xml"); 

    // find the node to add to 
    XPath xpath = XPathFactory.newInstance().newXPath(); 
    Node e1 = (Node) xpath.evaluate("//expandedData[@attr1='case1']", xml1, NODE); 
    Document doc1 = e1.getOwnerDocument(); 

    // insert the nodes 
    Node e2 = (Node) xpath.evaluate("//expandedData[@attr4='value4']", xml2, NODE); 
    e1.appendChild(doc1.adoptNode(e2)); 

    // print results 
    TransformerFactory.newInstance()
      .newTransformer()
      .transform(new DOMSource(doc1), new StreamResult(System.out)); 
  } 
}

实际得到的结果(属性值丢失)

<letterContent> 
  <key1>key1</key1> 
  <key2>key2</key2> 
  <type>456</type> 
  <object1>789</object1> 
  <effectiveDate>00</effectiveDate> 
  <expandedData attr1="case1"> 
    <expandedData attr2="value2"> 
      <data attrD="VD2">value D2</data> 
    </expandedData> 
    <expandedData attr3="value3"> 
      <data attrD="vd3">value D3</data> 
    </expandedData> 
    <expandedData attr4=""> 
      <data attrd4="">value d4</data> 
      <name nameattr=""/> 
    </expandedData> 
  </expandedData>
</letterContent>

解决思路与修复方案

这个问题的核心在于你使用的adoptNode()方法。虽然它可以将节点从源文档转移到目标文档,但当两个文档的DOM上下文(比如命名空间、实现细节)不一致时,它可能无法正确保留属性值。更可靠的做法是使用importNode()方法,它会完整复制节点及其所有子节点、属性,并适配到目标文档的环境中。

修改后的代码

只需要修改插入节点的那一行代码,将adoptNode()替换为importNode(),并设置第二个参数为true(表示深度导入,包含所有子节点和属性):

package org.test.XMLMERGE; 
import static javax.xml.xpath.XPathConstants.*; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult; 
import javax.xml.xpath.*; 
import org.w3c.dom.*; 
import org.xml.sax.InputSource; 

public class Xml2into1 { 
  public static void main(String[] args) throws Exception { 
    // read from files 
    InputSource xml1 = new InputSource("R:/java/dev/tmp/dest.xml"); 
    InputSource xml2 = new InputSource("R:/java/dev/tmp/orig2.xml"); 

    // find the node to add to 
    XPath xpath = XPathFactory.newInstance().newXPath(); 
    Node e1 = (Node) xpath.evaluate("//expandedData[@attr1='case1']", xml1, NODE); 
    Document doc1 = e1.getOwnerDocument(); 

    // insert the nodes - 这里是修改的核心
    Node e2 = (Node) xpath.evaluate("//expandedData[@attr4='value4']", xml2, NODE);
    // 使用importNode深度导入节点及所有属性、子节点
    Node importedNode = doc1.importNode(e2, true);
    e1.appendChild(importedNode); 

    // print results 
    TransformerFactory.newInstance()
      .newTransformer()
      .transform(new DOMSource(doc1), new StreamResult(System.out)); 
  } 
}

为什么这样修改有效?

  • importNode(Node importedNode, boolean deep)方法会创建一个目标文档的副本节点:
    • 当deep=true时,会递归导入所有子节点、属性和文本内容
    • 它会自动处理源文档和目标文档之间的DOM上下文差异,确保属性值被正确保留
  • 而adoptNode()只是将节点的所有权转移,不会做上下文适配,这就是导致属性值丢失的原因

修改后运行代码,你就能得到符合预期的XML结果,所有属性值都会被正确保留。

内容的提问来源于stack exchange,提问作者Zamboo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:07:17