I am linking to a webservice all works fine. Below is my codes.
private static void printSOAPResponse(SOAPMessage soapResponse) throws Exception {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
Source sourceContent = soapResponse.getSOAPPart().getContent();
System.out.print("\nResponse SOAP Message = \n");
StreamResult result = new StreamResult(System.out);
transformer.transform(sourceContent, result);
}
I am not too sure of the transformerfactory. What I need to do now is to traverse through the results and look for below tag.
<Table diffgr:id="Table1" > and there after there will be few tags in it for e.g.
<rID>1212</rID>
<sNo>15677</sNo>
So what is the best way as some require to covert it into string is that necessary?
Transform to document (unchecked):
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMResult result = new DOMResult();
transformer.transform(sourceContent, result);
Document doc = (Document) result.getNode();
Find in document:
String tag = "Table";
String attr = "diffgr:id";
String attrValue = "Table1";
NodeList list = doc.getElementsByTagName("Table");
Element tableNode = null;
for (int i = 0; i < list.getLength(); i++) {
tableNode = ((Element) list.item(i));
String currentAttrValue = tableNode.getAttribute(attr);
if (attrValue.equals(currentAttrValue)) {
break;
}
}
String childTag1 = "rID";
String childTag2 = "sNo";
Node child1 = (Node) tableNode.getElementsByTagName(childTag1).item(0);
Node child2 = (Node) tableNode.getElementsByTagName(childTag2).item(0);
String rIDValue = child1.getTextContent();
String sNoValue = child1.getTextContent();
You code Transformer transformer = transformerFactory.newTransformer(); is creating an "identity transformer" which copies the input unchanged, so it's not really doing anything useful. What you want here is a real (XSLT) transformer which actually extracts the information you need: something like
<xsl:template match="/">
<xsl:copy-of select="//Table[#diffgr:id='Table1']"/>
</xsl:template>
which you can compile using transformerFactory.newTemplates().
Related
I have been trying to modify values of more than one XML tag in java. So far I am able to get the values of the two nodes that I want to modify but while setting up values it always overrides the first one with the second one.
XML
<driver>
<BirthDate>1977-07-18</BirthDate>
<Age>40</Age>
<Gender>M</Gender>
<PrimaryResidence>OwnCondo</PrimaryResidence>
</driver>
I am trying to change Gender and PrimaryResidence tags.
Code
// Modifies multiple XML nodes
public static String changeCoreDiscountType(String reqXML) {
Document document = null;
String updatedXML = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(reqXML));
document = builder.parse(is);
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression expression = xPath.compile("/driver/Gender | /driver/PrimaryResidence");
NodeList nodeList = (NodeList) expression.evaluate(document,XPathConstants.NODESET);
for(int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
node.setTextContent("F");
node.setTextContent("OwnCondo");
String value = node.getTextContent();
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(new StringWriter());
transformer.transform(source, result);
updatedXML = result.getWriter().toString();
} catch (Exception ex) {
ex.printStackTrace();
}
return updatedXML;
}
Any help is appreciated.
You need to check you are updating the correct node first, e.g.
for(int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if(node.getNodeName() == "Gender")
node.setTextContent("F");
if(node.getNodeName() == "PrimaryResidence")
node.setTextContent("OwnCondo");
}
Full Demo
How do I include the delimiter when performing a substring operation?
i.e. given the string message which looks like this:
<nutrition>
<daily-values>
<total-fat units="g">65</total-fat>
<saturated-fat units="g">20</saturated-fat>
<cholesterol units="mg">300</cholesterol>
<sodium units="mg">2400</sodium>
<carb units="g">300</carb>
<fiber units="g">25</fiber>
<protein units="g">50</protein>
</daily-values>
</nutrition>
<food>
<name>Avocado Dip</name>
<mfr>Sunnydale</mfr>
<serving units="g">29</serving>
<calories total="110" fat="100"/>
<total-fat>11</total-fat>
<saturated-fat>3</saturated-fat>
<cholesterol>5</cholesterol>
<sodium>210</sodium>
<carb>2</carb>
<fiber>0</fiber>
<protein>1</protein>
<vitamins>
<a>0</a>
<c>0</c>
</vitamins>
<minerals>
<ca>0</ca>
<fe>0</fe>
</minerals>
</food>
and then
message = message.substring(message.indexOf("<food>"), message.indexOf("</food>"));
returns
<food>
<name>Avocado Dip</name>
<mfr>Sunnydale</mfr>
<serving units="g">29</serving>
<calories total="110" fat="100"/>
<total-fat>11</total-fat>
<saturated-fat>3</saturated-fat>
<cholesterol>5</cholesterol>
<sodium>210</sodium>
<carb>2</carb>
<fiber>0</fiber>
<protein>1</protein>
<vitamins>
<a>0</a>
<c>0</c>
</vitamins>
<minerals>
<ca>0</ca>
<fe>0</fe>
</minerals>
How do I get it to keep the last </food> tag given I don't know the surrounding content of the XML file?
Here's a solution using javax.xml. It aims to solve the case when multiple <food> elements are present in the document. In order to handle this case correctly, you need to
deserialize your XML into org.w3c.dom.Document
extract the list of <food> nodes as org.w3c.dom.NodeList
serialize back to String at the end
Here's a simplified example:
private static final String XML =
"<?xml version = \"1.0\" encoding = \"UTF-8\"?>\n"
+ "<message>\n"
+ " <food>\n"
+ " <name>A</name>\n"
+ " </food>\n"
+ " <food>\n"
+ " <name>B</name>\n"
+ " </food>\n"
+ "</message>\n";
#Test
public void xpath() throws Exception {
// Deserialize
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document document;
try (InputStream in = new ByteArrayInputStream(XML.getBytes(StandardCharsets.UTF_8))) {
document = factory.newDocumentBuilder().parse(in);
}
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xPath.compile("//food");
NodeList nodeList = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
System.out.println(node.getNodeName() + ": " + node.getTextContent().trim());
}
// Serialize
Document exportDoc = factory.newDocumentBuilder().newDocument();
Node exportNode = exportDoc.importNode(nodeList.item(0), true);
exportDoc.appendChild(exportNode);
String content = serialize(exportDoc);
System.out.println(content);
}
private static String serialize(Document doc) throws TransformerException {
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
// set indent
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(domSource, result);
return writer.toString();
}
The 1st output shows all <food> elements are deserialized correctly:
food: A
food: B
The 2nd output shows the 1st element are serialized back to string:
<food>
<name>A</name>
</food>
I am trying to update multiple nodes in xml using nodelist. I am able to do it but i don't think my code is efficient. For updating two nodes I am repeating my code twice. I dont know how to loop it. I tried it from for loop, or tried making it an arraylist and everything but it is not working at all.
Here is my code:
String expressionDisclosure = "/DOCUMENT/ishobject/ishfields/ishfield[#name='FHPIDISCLOSURELEVEL']";
String expressionLanguage = "/DOCUMENT/ishobject/ishfields/ishfield[#name='DOC-LANGUAGE']";
String key = "";
String value = "";
try {
DocumentBuilderFactory documentbuilderfactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentbuilder = documentbuilderfactory.newDocumentBuilder();
Document doc = documentbuilder.parse(filepath);
XPath xPath = XPathFactory.newInstance().newXPath();
Node updateNode = null;
NodeList nodelistLanguage = (NodeList) xPath.evaluate(expressionLanguage,
doc.getDocumentElement(), XPathConstants.NODESET);
NodeList nodelistDisclosure = (NodeList) xPath.evaluate(expressionDisclosure,
doc.getDocumentElement(), XPathConstants.NODESET);
key = nodelistLanguage.item(0).getTextContent();
if (key != null) {
value = getHashmap().get(key);
updateNode = nodelistLanguage.item(0);
updateNode.setTextContent(value);
}
key = nodelistDisclosure.item(0).getTextContent();
if (key != null) {
value = getHashmap().get(key);
updateNode = nodelistDisclosure.item(0);
updateNode.setTextContent(value);
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult stream = new StreamResult(new File(filepath));
transformer.transform(source, stream);
} catch (Exception ex) {
ex.printStackTrace();
}
I am updating the node twice. Is this the proper way to do or can it be more efficient?
This is my demo.jsp page
String filename = "TestNode.xml";
ServletContext app = getServletContext();
String projectPath = app.getRealPath("/");
String result = projectPath + filename;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new FileInputStream(new File(result)));
Element rootElement = doc.getDocumentElement();
Element element1 = doc.getDocumentElement();
Element element2 = doc.createElement("hai");
rootElement.appendChild(element2);
Element name = doc.createElement("welcome");
element2.appendChild(name);
element1.appendChild(element2);
DOMSource src = new DOMSource(doc);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = null;
transformer = transformerFactory.newTransformer();
StreamResult rslt = new StreamResult(result);
transformer.transform(src, rslt);
for this i'm getting output as:
<root>
<hai>
<welcome/>
</hai>
</root>
but expected output is:
<root>
<hai>
<welcome>
</welcome>
</hai>
</root>
Where should I change the code to get expected result?
To obtain the output:
<root>
<hai>
<welcome>
</welcome>
</hai>
</root>
Where the <welcome> </welcome> element is actually not empty but contains at least one whitespace character, you need to create a text node and add it as the child of the welcome element:
Element name = doc.createElement("welcome");
Node textNode = doc.createTextNode(" ");
name.appendChild(textNode);
element2.appendChild(name);
Sorry I'm a Java/XML newbie - and can't seem to figure this one out. It seems it's possible to convert a Document object to a string. However, I want to convert a Node object into a string. I am using org.ccil.cowan.tagsoup Parser for my purpose.
I'm retrieving the Node by something like...
parser = new org.ccil.cowan.tagsoup.Parser()
parser.setFeature(namespaceaware, false)
Transformer transformer = TransformerFactory.newInstance().newTransformer();
DOMResult domResult = new DOMResult();
transformer.transform(new SAXSource(parser, new InputSource(in)), domResult);
Node n = domResult.getNode();
// I'm interested in the first child, so...
Node myNode = n.getChildNodes().item(0);
// convert myNode to string..
// what to do here?
The answer may be obvious, but I can't seem to figure out from the core Java libraries how to achieve this. Any help is much appreciated!
You can use a Transformer (error handling and optional factory configuration omitted for clarity):
Node node = ...;
StringWriter writer = new StringWriter();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(new DOMSource(node), new StreamResult(writer));
String xml = writer.toString();
// Use xml ...
String getNodeString(Node node) {
try {
StringWriter writer = new StringWriter();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(new DOMSource(node), new StreamResult(writer));
String output = writer.toString();
return output.substring(output.indexOf("?>") + 2);//remove <?xml version="1.0" encoding="UTF-8"?>
} catch (TransformerException e) {
e.printStackTrace();
}
return node.getTextContent();
}
This is way to convert Node to html
public static String getInnerHTML(Node node) throws TransformerConfigurationException, TransformerException
{
StringWriter sw = new StringWriter();
Result result = new StreamResult(sw);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer proc = factory.newTransformer();
proc.setOutputProperty(OutputKeys.METHOD, "html");
for (int i = 0; i < node.getChildNodes().getLength(); i++)
{
proc.transform(new DOMSource(node.getChildNodes().item(i)), result);
}
return sw.toString();
}