在不修改文档的情况下使用javax解析器向XML添加元素

在不修改文档的情况下使用javax解析器向XML添加元素,java,xml,parsing,Java,Xml,Parsing,我正在尝试向xml文档添加元素。元素添加成功,但问题是,解析器在其他地方修改原始xml文件,例如它交换名称空间和id属性或删除重复的名称空间定义。我需要得到完全相同的文档(相同的语法,保留的空白),只需要添加特定的元素。如有任何建议,我将不胜感激。这是我的密码: public void appendTimestamp(String timestamp, String signedXMLFile, String timestampedXMLFile){ DocumentBuilderFac

我正在尝试向xml文档添加元素。元素添加成功,但问题是,解析器在其他地方修改原始xml文件,例如它交换名称空间和id属性或删除重复的名称空间定义。我需要得到完全相同的文档(相同的语法,保留的空白),只需要添加特定的元素。如有任何建议,我将不胜感激。这是我的密码:

public void appendTimestamp(String timestamp, String signedXMLFile, String timestampedXMLFile){
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    try{
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new File(signedXMLFile));

        XPath xPath = XPathFactory.newInstance().newXPath();
        NodeList list = (NodeList)xPath.evaluate("//*[local-name()='Signature']/*[local-name()='Object']/*[local-name()='QualifyingProperties']", doc, XPathConstants.NODESET);

        if(list.getLength() != 1){
            throw new Exception();
        }

        Node node = list.item(0);
        Node unsignedProps = doc.createElement("xades:UnsignedProperties");
        Node unsignedSignatureProps = doc.createElement("xzep:UnsignedSignatureProperties");
        Node timestampNode = doc.createElement("xzep:SignatureTimeStamp");
        timestampNode.appendChild(doc.createTextNode(timestamp));

        unsignedSignatureProps.appendChild(timestampNode);
        unsignedProps.appendChild(unsignedSignatureProps);
        node.appendChild(unsignedProps);

        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

        DOMSource source = new DOMSource(doc);

        StringWriter writer = new StringWriter();
        StreamResult stringWriter = new StreamResult(writer);
        transformer.transform(source, stringWriter);

        writer.flush();
        System.out.println(writer.toString());

    }catch(Exception e){
        e.printStackTrace();
    }
}
原始xml文件:

...    
<ds:Object Id="objectIdVerificationObject" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
...
...
<ds:Object xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="objectIdVerificationObject">
...
。。。
...
修改的xml文件:

...    
<ds:Object Id="objectIdVerificationObject" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
...
...
<ds:Object xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="objectIdVerificationObject">
...
。。。
...

如果使用dom模型,则整个xml文件将被读取,然后在内存中表示为节点树,然后以编写器确定的方式保存为xml。因此,几乎不可能保留原始xml格式,因为您无法控制它,例如,在节点树中根本不表示空白

您需要部分读取原始xml,并将其内容输出到新文件中,保留已读取的内容,然后在“正确”的位置添加新内容,然后继续对原始内容进行简单的压缩

例如,您可以使用
XMLStreamWriter
XMLStreamReader
来实现这一点,因为它们提供“低级”操作


但是,在识别插入点之前,将xml作为文本逐行复制,然后创建新的xml部分并将其作为文本追加,然后继续复制,可能会容易得多

作为一个快速和肮脏的修复(如果这是紧急的),考虑修改你的代码在字符串级别上的最终输出来交换这些属性吗?谢谢你的响应。我想利用xpath和方便的节点操作,所以将xml视为文本是我最后的选择。到目前为止,我还并没有遇到一个解决方案,即如何在不修改解析器元素的情况下解析xml。最后,我按照您的建议将xml加载到字符串中,然后将xml部分插入到所需的位置。