I have an unformated XML file (Just one line) and i would like indent it :
My File :
<?xml version="1.0" encoding="UTF-8" standalone="no"?><Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><test>toto</test></Document>
My java code :
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.PrintWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
public class PrettyXmlFormat {
public static void main(String[] args) throws Exception {
if(args != null && args.length > 0 && args[0].length() > 0)
{
String FileInputName = "TEST.xml";//"args[0];"
runFormat(FileInputName,true);
}
}
public static void runFormat(String FileInputName, boolean standelone) throws Exception {
String FileOutputName = FileInputName + "MOD";
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new FileInputStream(new File(FileInputName)));
doc.setXmlStandalone(standelone);
prettyPrint(doc,FileOutputName);
}
public static final void prettyPrint(Document xml , String FileOutputName) throws Exception {
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "yes");
PrintWriter FileOut = new PrintWriter(new FileWriter(FileOutputName));
tf.transform(new DOMSource(xml), new StreamResult(FileOut));
}
}
I have tried to play with the doc.setXmlStandalone(standelone);
With doc.setXmlStandalone(true) i have this result :
<?xml version="1.0" encoding="UTF-8"?><Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<test>toto</test>
</Document>
With doc.setXmlStandalone(false) i have this result :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<test>toto</test>
</Document>
I would like i result with standalone value and an escape after the xml declaration like that :
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<test>toto</test>
</Document>
Do you have an idea ?
Thank you !
You have to set the OutputKeys.DOCTYPE_PUBLIC to yes
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");
Related
I have following XML String :
<Aaaa>
<Bbbb>
<GroupC>
<KeyId>10001</KeyId>
</GroupC>
<DetailC>
<Dddd>
<Eeee>Eeee 001</Eeee>
<Ffff>Ffff 001</Ffff>
</Dddd>
</DetailC>
<DetailC>
<Dddd>
<Eeee>Eeee 002</Eeee>
<Ffff>Ffff 002</Ffff>
</Dddd>
</DetailC>
</Bbbb>
</Aaaa>
I would like to split "DetailC" it into the smaller XML:
XML 01:
<Aaaa>
<Bbbb>
<GroupC>
<KeyId>10001</KeyId>
</GroupC>
<DetailC>
<Dddd>
<Eeee>Eeee 001</Eeee>
<Ffff>Ffff 001</Ffff>
</Dddd>
</DetailC>
</Bbbb>
</Aaaa>
XML 02:
<Aaaa>
<Bbbb>
<GroupC>
<KeyId>10001</KeyId>
</GroupC>
<DetailC>
<Dddd>
<Eeee>Eeee 002</Eeee>
<Ffff>Ffff 002</Ffff>
</Dddd>
</DetailC>
</Bbbb>
</Aaaa>
Can I know how can I do so using Java?
Currently I only able to split into separate XML,
but it is without <Aaaa>, <Bbbb>, <GroupC>
Java code:
package message;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.xpath.CachedXPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.InputSource;
public class mainClass {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
String path = "D:\\abc.xml";
String xml = readFile(path);
List<String> xmlList2 = splitXML(xml, "/Aaaa/Bbbb/DetailC");
for (String xmlC : xmlList2) {
System.out.println("xmlC: " + xmlC);
}
}
private static List<String> splitXML(String xmlMessage, String xPath) throws Exception {
List<String> xmlList = new ArrayList<>();
Transformer xform = TransformerFactory.newInstance().newTransformer();
xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
InputSource parameterSource = new InputSource(new StringReader(xmlMessage));
Document doc = dBuilder.parse(parameterSource);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
CachedXPathAPI cachedXPathAPI = new CachedXPathAPI();
NodeIterator nl = cachedXPathAPI.selectNodeIterator(doc, xPath);
Node node;
while ((node = nl.nextNode()) != null) {
StringWriter buf = new StringWriter();
DOMSource dom = new DOMSource(node);
xform.transform(dom, new StreamResult(buf));
xmlList.add(buf.toString());
}
return xmlList;
}
private static String readFile(String path) {
String content = "";
try (Stream<String> lines = Files.lines(Paths.get(path))) {
content = lines.collect(Collectors.joining(System.lineSeparator()));
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
}
If you use Saxon 9 HE (availabe on Sourceforge and Maven for Java) you can solve that with XSLT 3, see the approach from Split XML file into multiple files using XSLT where you can change the code to
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0"
exclude-result-prefixes="xs">
<xsl:template match="DetailC">
<xsl:variable name="pos" as="xs:integer">
<xsl:number/>
</xsl:variable>
<xsl:result-document href="XML{format-number($pos, '000')}.xml">
<xsl:apply-templates select="/" mode="split">
<xsl:with-param name="this-detail" select="." tunnel="yes"/>
</xsl:apply-templates>
</xsl:result-document>
</xsl:template>
<xsl:template match="#* | node()" mode="split">
<xsl:copy>
<xsl:apply-templates select="#* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="DetailC" mode="split">
<xsl:param name="this-detail" tunnel="yes"/>
<xsl:if test=". is $this-detail">
<xsl:next-match/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
To run Saxon 9 in Java you can use either the JAXP transformation API http://saxonica.com/html/documentation/using-xsl/embedding/jaxp-transformation.html or the Saxon 9 specific s9api http://saxonica.com/html/documentation/using-xsl/embedding/s9api-transformation.html.
Keep in mind that Transformer can directly transform a file with StreamSource (e.g. https://docs.oracle.com/javase/8/docs/api/javax/xml/transform/stream/StreamSource.html#StreamSource-java.lang.String- or https://docs.oracle.com/javase/8/docs/api/javax/xml/transform/stream/StreamSource.html#StreamSource-java.io.File-) so there is no need to read in the file contents in a string or to build a DOM by hand, you can load any XML file directly as the input to XSLT.
How do I delete XML tags from XML document in java?
For Example, I have the following XML:
<root>
<item>
<code>100001</code>
<price>456</price>
<name>ABC</name>
</item>
<item>
<code>100002</code>
<price>123</price>
<name>DEF</name>
</item>
<item>
<code>100003</code>
<price>887</price>
<name>XYZ</name>
</item>
</root>
I want to delete the price tag from the XML and produce the XML in the following manner:
<root>
<item>
<code>100001</code>
<name>ABC</name>
</item>
<item>
<code>100002</code>
<name>DEF</name>
</item>
<item>
<code>100003</code>
<name>XYZ</name>
</item>
</root>
Additionally the requirement is such that the XML tags can change as I get this information from a webservice which can change the information it sends.
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.util.ArrayList;
public class JAXBExample {
static Root root = new Root();
public static void main(String[] args) throws JAXBException {
File file = new File("C:\\file.xml");
File file1 = new File("C:\\result.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Root rootEle = (Root) jaxbUnmarshaller.unmarshal(file);
ArrayList<item> itemList =new ArrayList<>();
for (int i = 0; i < rootEle.getItemList().size() ; i++){
item itemLocal = new item();
itemLocal.setCode(rootEle.getItemList().get(i).getCode());
itemLocal.setName(rootEle.getItemList().get(i).getName());
itemList.add(itemLocal);
}
root.setItemList(itemList);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(root, file1);
jaxbMarshaller.marshal(root, System.out);
}
}
Root class:
import org.apache.activemq.kaha.impl.data.Item;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
#XmlRootElement(name = "root")
public class Root {
public ArrayList<item> getItem() {
return itemList;
}
public void setItem(ArrayList<item> item) {
this.itemList = item;
}
private ArrayList<item> itemList;
}
Item calss:
public class item {
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String code;
private String name;
}
I hope this will help.
As commented, consider XSLT that runs the Identity Transform and an empty template on the node you wish to remove. No for loops, if logic, or use of data structures (e.g., arraylist, hashmaps) needed for this solution.
As information, XSLT is a special purpose language (sibling to XPath) designed to transform xml files into other xml, html, even text files (csv/txt). General purpose languages like Java, PHP, Python, and others maintain libraries to run XSLT 1.0 scripts and can even call external dedicated XSLT processors like libxslt/Saxon. Additionally, XSLT scripts are themselves well-formed XML files and can be parsed from file or string for any dynamic needs.
XSLT (save as .xsl script to be parsed from file in Java below)
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<!-- Identity Transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Removes all price tags -->
<xsl:template match="price"/>
</xsl:transform>
Java
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.OutputKeys;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class CourseList {
public static void main(String[] args) throws IOException, URISyntaxException,
SAXException,
ParserConfigurationException,
TransformerException {
// LOAD XML AND XSL DOCUMENTS
String inputXML = "C:\\Path\\To\\Input.xml";
String xslFile = "C:\\Path\\To\\XSLTScript.xsl";
String outputXML = "C:\\Path\\To\\Output.xml";
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse (new File(inputXML));
Source xslt = new StreamSource(new File(xslFile));
// XSLT TRANSFORMATION WITH PRETTY PRINT
TransformerFactory prettyPrint = TransformerFactory.newInstance();
Transformer transformer = prettyPrint.newTransformer(xslt);
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(outputXML));
transformer.transform(source, result);
}
}
I have added the string in beginning and end of the XML File.but the alignment is not proper after getting the result.
My XML File:
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;
import com.google.common.io.Resources;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.nio.charset.Charset;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public class ModifyXMLFile {
public static void main(String args[]) {
try {
// Point the file directory path here
String directory = "C:\\Users\\n444479\\Desktop\\SA";
int test = new File("C:\\Users\\n444479\\Desktop\\SA").listFiles().length;
File[] files = new File(directory).listFiles();
// Loop the file to run all the XML files
for (int j = 0; j < test; j++) {
System.out.println(files[j]);
String filepathext = files[j].toString();
DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filepathext);
/*
// XML file update starts here
// 1.Add the attribute element with value between the two XML
// Child elements
NodeList nodes = doc.getElementsByTagName("dummySegmentOne");
Text a = doc.createTextNode("value"); Element p =
doc.createElement("newNode"); p.appendChild(a);
nodes.item(0).getParentNode().insertBefore(p, nodes.item(0));
// 2.Add the attribute element without value between the two XML
// Child elements
NodeList nodesa =
doc.getElementsByTagName("customerLevelRegDocs"); Element q =
doc.createElement("dummySegmentOne");
nodesa.item(0).getParentNode().insertBefore(q,
nodesa.item(0));
// 3.Rename the element in parent and child both using the JAXP
// Parser
*/
// XSLT File:
String xsltResource = "C:\\Users\\n444479\\Desktop\\AB\\test.xml";
StringWriter xmlResultResource = new StringWriter();
Transformer xmlTransformer = TransformerFactory.newInstance().newTransformer(
new StreamSource(new File(xsltResource)));
xmlTransformer.transform(new StreamSource(new File(filepathext)),new StreamResult(xmlResultResource));
// XML file update end here
// write the content into XML file
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new String(filepathext));
transformer.transform(source, result);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
// Successful output once get it "Done"
String output = xmlResultResource.getBuffer().toString();
// Writing the transformed XML to a file
FileWriter fileWriter = new FileWriter(filepathext);
fileWriter.write(output);
fileWriter.close();
System.out.println("Done");
}
}
// Exception handling
catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SAXException sae) {
sae.printStackTrace();
}
}
}
Once the program executed the string get appended properly but the XML File alignment changed.
The output i am getting as below
<?xml version="1.0" encoding="UTF-8"?>{% from lxml import etree %}{% from StringIO import StringIO %}{% set tree = parse_xml(request_text) %}{% set namespaces = {'soapenv': 'http://schemas.xmlsoap.org/soap/envelope/', 'wbs': 'http://xml.ama.com/ws/2009/01/WBS_Session-2.0.xsd'}%}<soap:Envelope xmlns:xalan="http://xml.apache.org/xalan" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Session><SessionId>{{tree.xpath('//soapenv:Header/wbs:Session/wbs:SessionId', namespaces=namespaces)[0].text}}</SessionId><SequenceNumber>{{int(tree.xpath('//soapenv:Header/wbs:Session/wbs:SequenceNumber', namespaces=namespaces)[0].text)+1}}</SequenceNumber><SecurityToken>{{tree.xpath('//soapenv:Header/wbs:Session/wbs:SecurityToken', namespaces=namespaces)[0].text}}</SecurityToken></Session></soap:Header><soap:Body><reRoot><reNode> world</reNode></reRoot></soap:Body></soap:Envelope>
why the file not getting appeneded
The reason is that DataInputStream.readLine discards the newline character. So, you'll have to append it yourself.
Moreover:
Take in account that the resulting XML is incorrect, because the original XML header turns out to be included in one node. The header (if present) must stay always before the root node.
To properly transform your input XML to a SOAP, I recommend you two alternatives:
Either transform it through an XSL stylesheet.
Or either build the resulting XML with DOM and include the source XML as one child node. Then, when serializing the whole document, you may specify indentation parameters.
Update
I suggest you this XSL:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">{% from lxml import etree %}{% from StringIO import StringIO %}{% set tree = parse_xml(request_text) %}{% set namespaces = {'soapenv': 'http://schemas.xmlsoap.org/soap/envelope/', 'wbs': 'http://xml.ama.com/ws/2009/01/WBS_Session-2.0.xsd'}%}<soap:Envelope xmlns:xalan="http://xml.apache.org/xalan" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Session>
<SessionId>{{tree.xpath('//soapenv:Header/wbs:Session/wbs:SessionId', namespaces=namespaces)[0].text}}</SessionId>
<SequenceNumber>{{int(tree.xpath('//soapenv:Header/wbs:Session/wbs:SequenceNumber', namespaces=namespaces)[0].text)+1}}</SequenceNumber>
<SecurityToken>{{tree.xpath('//soapenv:Header/wbs:Session/wbs:SecurityToken', namespaces=namespaces)[0].text}}</SecurityToken>
</Session>
</soap:Header>
<soap:Body><xsl:copy-of select="."/>
</soap:Body>
</soap:Envelope>
</xsl:template>
</xsl:stylesheet>
In other words: It creates a SOAP message with a fixed format, and sets the input xml as the contents of the <soap:Body> node.
And the transformation code:
private static void transform(org.w3c.dom.Document doc, java.io.InputStream inputXsl, java.io.OutputStream out)
throws java.io.IOException,
javax.xml.transform.TransformerConfigurationException,
javax.xml.transform.TransformerException
{
javax.xml.transform.Templates templates=javax.xml.transform.TransformerFactory.newInstance().newTemplates(new javax.xml.transform.stream.StreamSource(inputXsl));
javax.xml.transform.Transformer transformer=templates.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
javax.xml.transform.Result result=new javax.xml.transform.stream.StreamResult(out);
javax.xml.transform.Source source=new javax.xml.transform.dom.DOMSource(doc);
if (doc.getInputEncoding() != null)
{
transformer.setOutputProperty("encoding", doc.getInputEncoding());
}
transformer.transform(source, result);
}
The whole result is re-indented by means of two causes:
The xsl:strip-space in the XSL.
The indent and indent-amount properties in the transformation.
The below XSL Stylesheet will be formatting the xml properly
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="/">
{% from lxml import etree %}{% from StringIO import StringIO %}{% set tree = parse_xml(request_text) %}{% set namespaces = {'soapenv': 'http://schemas.xmlsoap.org/soap/envelope/', 'wbs': 'http://xml.ama.com/ws/2009/01/WBS_Session-2.0.xsd'}%}
<soap:Envelope xmlns:xalan="http://xml.apache.org/xalan" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Session>
<SessionId>{{tree.xpath('//soapenv:Header/wbs:Session/wbs:SessionId', namespaces=namespaces)[0].text}}</SessionId>
<SequenceNumber>{{int(tree.xpath('//soapenv:Header/wbs:Session/wbs:SequenceNumber', namespaces=namespaces)[0].text)+1}}</SequenceNumber>
<SecurityToken>{{tree.xpath('//soapenv:Header/wbs:Session/wbs:SecurityToken', namespaces=namespaces)[0].text}}</SecurityToken>
</Session>
</soap:Header>
<soap:Body><xsl:copy-of select="."/>
</soap:Body>
</soap:Envelope>
</xsl:template>
</xsl:stylesheet>
#Little Santi thanks for helping me and getting understand things.
I am trying to parse an XML and the code that I use is as follows:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
public class Main {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:comm3=\"http://www.csapi.org/schema/parlayx/common/v3_1\" xmlns:sms7=\"http://www.csapi.org/schema/parlayx/sms/notification/v3_1/local\">\r\n <SOAP-ENV:Header>\r\n <comm3:NotifySOAPHeader>\r\n <spId>37</spId>\r\n </comm3:NotifySOAPHeader>\r\n </SOAP-ENV:Header>\r\n <SOAP-ENV:Body SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n <sms7:notifySmsDeliveryReceipt>\r\n <sms7:correlator>123</sms7:correlator>\r\n <sms7:deliveryStatus>\r\n <address>tel:959257118550</address>\r\n <deliveryStatus>DeliveredToTerminal</deliveryStatus>\r\n </sms7:deliveryStatus>\r\n </sms7:notifySmsDeliveryReceipt>\r\n </SOAP-ENV:Body>\r\n</SOAP-ENV:Envelope>\r\n";
System.out.println("xml:");
System.out.println(xml);
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder loader = factory.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xml));
Document doc = loader.parse(is);
NodeList nodeList = doc.getElementsByTagNameNS("http://www.csapi.org/schema/parlayx/sms/notification/v3_1/local", "correlator");
Element correlatorElement = (Element) nodeList.item(0);
System.out.println(correlatorElement);
NodeList addressNodeList = doc.getElementsByTagName("address");
System.out.println(addressNodeList.item(0));
}
}
Without throwing any exception, the code prints the results but what we get is not what we would expect.
xml:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:comm3="http://www.csapi.org/schema/parlayx/common/v3_1" xmlns:sms7="http://www.csapi.org/schema/parlayx/sms/notification/v3_1/local">
<SOAP-ENV:Header>
<comm3:NotifySOAPHeader>
<spId>37</spId>
</comm3:NotifySOAPHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<sms7:notifySmsDeliveryReceipt>
<sms7:correlator>123</sms7:correlator>
<sms7:deliveryStatus>
<address>tel:959257118550</address>
<deliveryStatus>DeliveredToTerminal</deliveryStatus>
</sms7:deliveryStatus>
</sms7:notifySmsDeliveryReceipt>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
[sms7:correlator: null]
[address: null]
Process finished with exit code 0
Why are the values null?
There is 3 reason, why ist not working:
The node really doesn't exist!
The node is in a different namespace and you need to use the version of the method that also accepts the namespace: Element#getChild(String, Namespace) or Element#getChildText(String, Namespace).
Most importantly, remember that these methods return only immediate descendents of a node! So if you're looking to get a node nested at the nth level, you will need to walk the tree to its parent and only then can you call #getChild() and actually get the child!
for eg. root=
<root>
<param value="abc">
<param value="bc">
</root>
NodeToInsert could be
<insert><parameterDesc>afds</parameterDesc></insert>
The output should be:
<root>
<insert><parameterDesc>afds</parameterDesc></insert>
<param value="abc">
<param value="bc">
</root>
I'll be really irritated if it turns out I just did your homework for you.
package com.akonizo.examples;
import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
public class XmlInsertExample {
/**
* #param args
*/
public static void main(String[] args) {
String initial = "<root><param value=\"abc\"/><param value=\"bc\"/></root>";
try {
// Parse the initial document
ByteArrayInputStream is = new ByteArrayInputStream(initial.getBytes());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
// Create the new xml fragment
Text a = doc.createTextNode("afds");
Node p = doc.createElement("parameterDesc");
p.appendChild(a);
Node i = doc.createElement("insert");
i.appendChild(p);
Element r = doc.getDocumentElement();
r.insertBefore(i, r.getFirstChild());
r.normalize();
// Format the xml for output
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
System.out.println(result.getWriter().toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
The result will be:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<insert>
<parameterDesc>afds</parameterDesc>
</insert>
<param value="abc"/>
<param value="bc"/>
</root>