使用 XPATH 和 Java 中的 DOM 更新空 XML 元素
Update empty XML element using XPATH and DOM in Java
我将以下 XML 文档存储为字符串,并希望使用 XPATH 和 DOM.
更新空的 SubID
元素
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.com/2.0/" xmlns:pfx="http://example.com/1.0">
<soapenv:Header/>
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Client</faultcode>
<faultstring>Authentication Failed</faultstring>
<detail>
<pfx:Fault>
<ns2:MessageHeader xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns1="example.com/1.0/" xmlns:ns2="http://www.example.com/MessageHeader/1.0/">
<ns2:SubId></ns2:SubId>
<ns2:CnsmrId></ns2:CnsmrId>
</ns2:MessageHeader>
</pfx:Fault>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
我使用以下代码首先使用 xpath 获取节点并使用 DOM 更新它。由于 XML 文档使用命名空间,我在 xpath 中使用 local-name()
。
public void updateXML(String xmlString, String textToAdd) {
Document responseDoc = convertStringToXMLDocument(xmlString.trim());
responseDoc.getDocumentElement().normalize();
XPath xpath = XPathFactory.newInstance().newXPath();
String destinationPath = "//*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='Fault']/*[local-name()='detail']/*[local-name()='Fault']/*[local-name()='MessageHeader']/*[local-name()='SubId']";
Node destinationNode = (Node) xpath.compile(destinationPath).evaluate(responseDoc, XPathConstants.NODE);
destinationNode.setNodeValue(textToAdd);
String respDoc = convertDOMtoXMLString(responseDoc);
System.out.println(respDoc);
}
private static Document convertStringToXMLDocument(String xmlString) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
factory.setNamespaceAware(true);
builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
return doc;
}
private static String convertDOMtoXMLString(Document doc) {
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer;
transformer = tf.newTransformer();
transformer.transform(domSource, result);
return writer.toString();
}
在目标节点中设置值后,我尝试将其转换回字符串并打印出来进行验证,但我看到 SubId
字段已折叠且未添加任何内容。这是我得到的输出(仅发布 XML 输出的相关部分):
<pfx:Fault>
<ns2:MessageHeader xmlns:ns1="qwerty.com/1.0/" xmlns:ns2="http://www.abcd.com/MessageHeader/1.0/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ns2:SubId />
<ns2:CnsmrId />
</ns2:MessageHeader>
</pfx:Fault>
我做错了什么?
我发现如果元素为空,使用 setNodeValue 将不起作用,我们可以创建一个文本节点,然后将其作为子节点追加到目标节点中。
public void updateXML(String xmlString, String textToAdd) {
Document responseDoc = convertStringToXMLDocument(xmlString.trim());
responseDoc.getDocumentElement().normalize();
XPath xpath = XPathFactory.newInstance().newXPath();
String destinationPath = "//*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='Fault']/*[local-name()='detail']/*[local-name()='Fault']/*[local-name()='MessageHeader']/*[local-name()='SubId']";
Node destinationNode = (Node) xpath.compile(destinationPath).evaluate(responseDoc, XPathConstants.NODE);
Text txt = responseDoc.createTextNode("Hello");
destinationNode.appendChild(txt);
String respDoc = convertDOMtoXMLString(responseDoc);
System.out.println(respDoc);
}
我将以下 XML 文档存储为字符串,并希望使用 XPATH 和 DOM.
更新空的SubID
元素
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://example.com/2.0/" xmlns:pfx="http://example.com/1.0">
<soapenv:Header/>
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Client</faultcode>
<faultstring>Authentication Failed</faultstring>
<detail>
<pfx:Fault>
<ns2:MessageHeader xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns1="example.com/1.0/" xmlns:ns2="http://www.example.com/MessageHeader/1.0/">
<ns2:SubId></ns2:SubId>
<ns2:CnsmrId></ns2:CnsmrId>
</ns2:MessageHeader>
</pfx:Fault>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
我使用以下代码首先使用 xpath 获取节点并使用 DOM 更新它。由于 XML 文档使用命名空间,我在 xpath 中使用 local-name()
。
public void updateXML(String xmlString, String textToAdd) {
Document responseDoc = convertStringToXMLDocument(xmlString.trim());
responseDoc.getDocumentElement().normalize();
XPath xpath = XPathFactory.newInstance().newXPath();
String destinationPath = "//*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='Fault']/*[local-name()='detail']/*[local-name()='Fault']/*[local-name()='MessageHeader']/*[local-name()='SubId']";
Node destinationNode = (Node) xpath.compile(destinationPath).evaluate(responseDoc, XPathConstants.NODE);
destinationNode.setNodeValue(textToAdd);
String respDoc = convertDOMtoXMLString(responseDoc);
System.out.println(respDoc);
}
private static Document convertStringToXMLDocument(String xmlString) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
factory.setNamespaceAware(true);
builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
return doc;
}
private static String convertDOMtoXMLString(Document doc) {
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer;
transformer = tf.newTransformer();
transformer.transform(domSource, result);
return writer.toString();
}
在目标节点中设置值后,我尝试将其转换回字符串并打印出来进行验证,但我看到 SubId
字段已折叠且未添加任何内容。这是我得到的输出(仅发布 XML 输出的相关部分):
<pfx:Fault>
<ns2:MessageHeader xmlns:ns1="qwerty.com/1.0/" xmlns:ns2="http://www.abcd.com/MessageHeader/1.0/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ns2:SubId />
<ns2:CnsmrId />
</ns2:MessageHeader>
</pfx:Fault>
我做错了什么?
我发现如果元素为空,使用 setNodeValue 将不起作用,我们可以创建一个文本节点,然后将其作为子节点追加到目标节点中。
public void updateXML(String xmlString, String textToAdd) {
Document responseDoc = convertStringToXMLDocument(xmlString.trim());
responseDoc.getDocumentElement().normalize();
XPath xpath = XPathFactory.newInstance().newXPath();
String destinationPath = "//*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='Fault']/*[local-name()='detail']/*[local-name()='Fault']/*[local-name()='MessageHeader']/*[local-name()='SubId']";
Node destinationNode = (Node) xpath.compile(destinationPath).evaluate(responseDoc, XPathConstants.NODE);
Text txt = responseDoc.createTextNode("Hello");
destinationNode.appendChild(txt);
String respDoc = convertDOMtoXMLString(responseDoc);
System.out.println(respDoc);
}