我在生成带有签名节点的文档时遇到问题。我有一堆以文本格式签署的 XML。他们的签名是有效的,我已经用 xmlsec1 对其进行了测试。我必须加载所有 XML 并将它们放入另一个 XML 文档中,以便将其发送到另一个服务。所以,首先我创建容器文档(“sobre”是一个局部变量,一个 JAXB 根元素):
JAXBContext context = JAXBContext.newInstance("org.importe.test");
StringWriter writer = new StringWriter();
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(sobre, writer);
String xml = writer.toString();
Document doc = loadXMLFromString(xml);
然后我将 XML 添加到容器中:
for (String cfexml : cfexmls) {
Document cfe = loadXMLFromString(cfexml);
Node newNode = doc.importNode(cfe.getDocumentElement(), true);
doc.getElementsByTagName("EnvioCFE").item(0).appendChild(newNode);
}
最后我从容器文档中获取 xml:
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
StringWriter outputWriter = new StringWriter();
trans.transform(new DOMSource(doc), new StreamResult(outputWriter));
String signedxml = outputWriter.toString();
关键是我正在修改子节点,没有命名空间,因此提取节点的签名验证失败。下面是我作为子节点添加的 XML 的摘录:
<?xml version="1.0" encoding="UTF-8"?>
<CFE xmlns="http://org.importe.test" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" version="1.0">
<data>
[...]
</data>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
[...]
</Signature>
</CFE>
但是当在容器文档中导入节点时,它会被修改(实际上我注意到它松散了命名空间声明):
<?xml version="1.0" encoding="UTF-8"?>
<EnvioCFE xmlns="http://org.importe.test" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" version="1.0">
<Header version="1.0">
</Header>
<CFE version="1.0">
<data>
[...]
</data>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
[...]
</Signature>
</CFE>
</EnvioCFE>
如何将节点添加到保留命名空间声明的容器中?更一般地说,我可以添加它以确保它是“按原样”添加的,而不进行任何修改吗?(我正在使用 glassfish 4 和 Java 7)
谢谢
编辑:
这是 loadXMLFromString 的代码:
public Document loadXMLFromString(String xml) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new InputSource(new StringReader(xml)));
}