How to remove prefix and namespace in SOAPElement? - java

Collogues, i have cycle which create soap xml with nessesary structure (don't ask about the structure)
log.info("Body elements: ");
NodeList nodeList = body.getElementsByTagName("*") ;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
log.info(node.getNodeName());
if (node.getNodeName().equals("ns2:request")) {
log.info("Set namespace and prefix for " + node.getNodeName());
SOAPElement childX = (SOAPElement) node;
childX.removeNamespaceDeclaration(childX.getPrefix()) ;
childX.addNamespaceDeclaration("ns3", "http://mayacomp/Generic/Ws");
childX.setPrefix("ns3");
}
else {
if (node.getNodeName().equals("ns2:in") ) {
log.info("Remove namespace for " + node.getNodeName());
SOAPElement childX = (SOAPElement) node;
childX.removeNamespaceDeclaration(childX.getPrefix()) ;
childX.addNamespaceDeclaration("", "");
childX.setPrefix("");
}
SOAPElement childX = (SOAPElement) node;
childX.removeNamespaceDeclaration(childX.getPrefix()) ;
childX.setPrefix("");
}
}
}
As a result I receive xml:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns3:request xmlns:ns3="http://mayacomp/Generic/Ws">
<in xmlns="http://mayacomp/Generic/Ws">
<requestHeader>
My question is how to remove only xmlns="http://mayacomp/Generic/Ws" from <in> element and receive:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns3:request xmlns:ns3="http://mayacomp/Generic/Ws">
<in>
<requestHeader>
UPDATE
I tried to config xml element:
/*Config body elements*/
while (itBodyElements.hasNext())
{
Object o = itBodyElements.next();
SOAPBodyElement bodyElement = (SOAPBodyElement) o;
log.info("Elements from 'Body' element = " + bodyElement.getLocalName() );
Iterator it2 = bodyElement.getChildElements();
while (it2.hasNext())
{
Object requestElement = it2.next();
SOAPBodyElement bodyRequest = (SOAPBodyElement) requestElement;
log.info(" Elements from '"+ bodyElement.getLocalName() + "' element = " + bodyRequest.getLocalName());
log.info(" Delete namespace from IN element " + bodyRequest.getLocalName());
bodyRequest.removeNamespaceDeclaration(bodyRequest.getPrefix());
bodyRequest.setPrefix("");
Iterator it3 = bodyRequest.getChildElements();
while (it3.hasNext())
{ //work with other elements
But it has not effect to 'in' element. After run i still have:
<in xmlns="http://mayacomp/Generic/Ws">
UPDATE
I solved the problem by calling ws as next:
getWebServiceTemplate().marshalSendAndReceive(
"URL",
request,
new WebServiceMessageCallback()
{ public void doWithMessage(WebServiceMessage message) {
SaajSoapMessage saajSoapMessage = (SaajSoapMessage)message;
SOAPMessage soapMessage = UtilsClass.createSOAPMessage(in);
saajSoapMessage.setSaajMessage(soapMessage);
}
}
);
Method createSOAPMessage configure soap message using javax.xml.soap library.

If I understand the question correctly, your code gets the following XML as input:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns2:request xmlns:ns3="http://mayacomp/Generic/Ws">
<ns2:in>
<ns2:requestHeader>
And you want to transform it into the following XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns3:request xmlns:ns3="http://mayacomp/Generic/Ws">
<in>
<requestHeader>
In this case, adjusting the namespace declarations and namespace prefixes is not enough because in the DOM the in and requestHeader elements will still be in the http://mayacomp/Generic/Ws namespace. That is because the namespace URI of a DOM element is determined at creation/parse time and doesn't change when namespace declarations are added or removed later. When the DOM is serialized, the serializer will automatically generate the necessary namespace declarations to make sure that the elements in the output effectively have the namespaces they had in the DOM. That is why you get xmlns="http://mayacomp/Generic/Ws" in the output, although that namespace declaration is not present in the DOM.
What you really need to do is to change the namespace URI for these elements. Unfortunately, DOM nodes don't have a setNamespaceURI method and you need to use Document.renameNode instead.

You could just remove the attribute using something like
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nList = (NodeList)xPath.evaluate("/Envelope/Body/request/in", body, XPathConstants.NODESET);
for (int i = 0; i < nList.getLength(); ++i) {
Element e = (Element) nList.item(i);
e.removeAttribute("xmlns");
}
The following test shows that it does work.
#Test
public void removeXmlns() throws Exception {
String xml = "" +
"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
" <soapenv:Body>\n" +
" <ns3:request xmlns:ns3=\"http://mayacomp/Generic/Ws\">\n" +
" <in xmlns=\"http://mayacomp/Generic/Ws\">\n" +
" <requestHeader>\n" +
" </requestHeader>\n" +
" </in>\n" +
" </ns3:request>\n" +
" </soapenv:Body>\n" +
"</soapenv:Envelope>";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(ResourceUtils.getFile("/soaptest.xml").getAbsolutePath());
Element body = document.getDocumentElement();
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nList = (NodeList)xPath.evaluate("/Envelope/Body/request/in", body, XPathConstants.NODESET);
for (int i = 0; i < nList.getLength(); ++i) {
Element e = (Element) nList.item(i);
e.removeAttribute("xmlns");
}
DOMSource domSource = new DOMSource(document);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
logger.info("XML IN String format is: \n" + writer.toString());
}
The output is
2015-11-26-11-46-24[]::[main]:(demo.TestCode.removeXmlns(TestCode.java:174):174):INFO :TestCode:XML IN String format is:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns3:request xmlns:ns3="http://dfg/Ws">
<in>
<requestHeader>
</requestHeader>
</in>
</ns3:request>
</soapenv:Body>
</soapenv:Envelope>

Related

How to use Java XPath with KML files and namespaces on Android

I'm struggling with how to use XPath on KML files that contain the new gx:Track and gx:coord tags. The problem is with how to use XPath with namespaces under Android.
I've looked at a number of examples, including these
https://www.ibm.com/developerworks/library/x-nmspccontext/index.html
https://howtodoinjava.com/xml/xpath-namespace-resolution-example/
XPath with namespace in Java
NamespaceContext and using namespaces with XPath
but I can't seem to get even those examples to work.
The following code and output illustrates my problem:
public App() {
super();
try {
test( testDoc1() );
test( testDoc2() );
} catch( Exception e ) {
e.printStackTrace();
} finally {
Log.d( "TEST-FINISHED", "test is finished" );
}
}
private String toXmlString( Document document ) throws TransformerException {
DOMSource domSource = new DOMSource( document );
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult( writer );
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform( domSource, result );
return writer.toString();
}
private Document testDoc1() throws ParserConfigurationException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware( true );
Document mDocument = documentBuilderFactory.newDocumentBuilder().newDocument();
String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
Element mKmlElement = mDocument.createElement( "kml" );
mKmlElement.setAttributeNS( XMLNS_NAMESPACE_URI, "xmlns", "http://www.opengis.net/kml/2.2" );
mKmlElement.setAttributeNS( XMLNS_NAMESPACE_URI, "xmlns:gx", "http://www.google.com/kml/ext/2.2" );
mDocument.appendChild( mKmlElement );
Element mPlacemarkElement = mDocument.createElement( "Placemark" );
mKmlElement.appendChild( mPlacemarkElement );
Element gxTrackElement = mDocument.createElement( "gx:Track" );
mPlacemarkElement.appendChild( gxTrackElement );
Element gxCoordElement = mDocument.createElement( "gx:coord" );
gxCoordElement.setTextContent( "-122.207881 37.371915 156.000000" );
gxTrackElement.appendChild( gxCoordElement );
return mDocument;
}
private Document testDoc2() throws ParserConfigurationException, IOException, SAXException {
String kmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark><gx:Track><gx:coord>-122.207881 37.371915 156.000000</gx:coord></gx:Track></Placemark></kml>";
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware( true );
Document mDocument = documentBuilderFactory.newDocumentBuilder().parse( new InputSource( new StringReader( kmlString ) ) );
return mDocument;
}
private void test( Document mDocument ) throws Exception {
String xml = toXmlString( mDocument );
Log.d( "TEST-XML", xml );
XPath xPath = XPathFactory.newInstance().newXPath();
xPath.setNamespaceContext( new NamespaceContext() {
#Override
public String getNamespaceURI( String prefix ) {
switch( prefix ) {
case XMLConstants.DEFAULT_NS_PREFIX:
return "http://www.opengis.net/kml/2.2";
case "gx":
return "http://www.google.com/kml/ext/2.2";
}
return XMLConstants.NULL_NS_URI;
}
#Override
public String getPrefix( String namespaceURI ) {
return null;
}
#Override
public Iterator getPrefixes( String namespaceURI ) {
return null;
}
} );
NodeList result1 = (NodeList) xPath.evaluate( "/kml", mDocument, XPathConstants.NODESET );
Log.d( "TEST-RESULT1", String.valueOf( result1.getLength() ) );
NodeList result2 = (NodeList) xPath.evaluate( "/kml/Placemark", mDocument, XPathConstants.NODESET );
Log.d( "TEST-RESULT2", String.valueOf( result2.getLength() ) );
NodeList result3 = (NodeList) xPath.evaluate( "/kml/Placemark/gx:Track", mDocument, XPathConstants.NODESET );
Log.d( "TEST-RESULT3", String.valueOf( result3.getLength() ) );
}
The test() method executes 3 XPath statements/patterns and is called once for each of two test documents. The 2 documents are constructed using different methods but the contents should be identical. However, the results I get from the 3 XPath statements are different.
These are the results with document 1:
2018-11-17 17:51:28.289 22837-22837/ca.csdesigninc.offroadtracker D/TEST-XML: <?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2"><Placemark><gx:Track><gx:coord>-122.207881 37.371915 156.000000</gx:coord></gx:Track></Placemark></kml>
2018-11-17 17:51:28.324 22837-22837/ca.csdesigninc.offroadtracker D/TEST-RESULT1: 1
2018-11-17 17:51:28.334 22837-22837/ca.csdesigninc.offroadtracker D/TEST-RESULT2: 1
2018-11-17 17:51:28.343 22837-22837/ca.csdesigninc.offroadtracker D/TEST-RESULT3: 0
and these are the results with document 2:
2018-11-17 17:51:28.348 22837-22837/ca.csdesigninc.offroadtracker D/TEST-XML: <?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2"><Placemark><gx:Track><gx:coord>-122.207881 37.371915 156.000000</gx:coord></gx:Track></Placemark></kml>
2018-11-17 17:51:28.358 22837-22837/ca.csdesigninc.offroadtracker D/TEST-RESULT1: 0
2018-11-17 17:51:28.363 22837-22837/ca.csdesigninc.offroadtracker D/TEST-RESULT2: 0
2018-11-17 17:51:28.372 22837-22837/ca.csdesigninc.offroadtracker D/TEST-RESULT3: 0
There are at least 2 problems:
since the 2 documents are identical (I think), why are the results of the tests different? (i.e., the first 2 XPath statements succeed with document 1 but neither succeeds with document 2.)
and why does the 3rd XPath statement fail to find the gx:Track element in both document 1 and document 2?
UPDATE: This problem seems to have something to do with having
xmlns="http://www.opengis.net/kml/2.2"
included in document 2. If I remove it, the results of the first 2 XPath tests are the correct (for both documents) - and in fact XPath test 3 now works on document 2. Unfortunately, I still don't have a handle on this behavior.
I'm probably missing something obvious and would appreciate any help.
The differences are due to namespaces. Both in how the XML is being produced, and when you are selecting content in the XPath.
Unfortunately, it is difficult to see the difference because the XML that happens to be serialized by the toXmlString() for testDoc1() doesn't exactly match the state of the in-memory document.
When you construct the kml element, using createElement() it creates an element that is bound to the "no namespace". Then, you added namespace attributes, which happen to come out when serializing with toXmlString() and make the kml element appear to be in the http://www.opengis.net/kml/2.2 namespace.
If you were to marshal that XML back to a new Document object, the kml element would be bound to that namespace. However, the current in-memory object for that element is not.
You can observe this by adding some additional diagnostics println messages:
NodeList result1 = (NodeList) xPath.evaluate("/kml", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result1.getLength()));
System.out.println("Namespace URI: " + result1.item(0).getNamespaceURI());
System.out.println("Prefix: " + result1.item(0).getPrefix());
You can round-trip your XML and observe that it behaves different when you marshall the serialized XML:
private void test(Document mDocument) throws Exception {
String xml = toXmlString(mDocument);
System.out.println( xml);
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
mDocument = documentBuilderFactory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
However, that's cheating. What you really want to do is ensure that the elements are created properly in the first place. When you create an element that you want to be bound to a namespace, use the createElementNS() method, as indicated in the JavaDoc comments for createElement():
To create an element with a qualified name and namespace URI, use the createElementNS method.
So, to create an element that is bound to the http://www.opengis.net/kml/2.2 namespace, you would want to use:
Element mKmlElement = mDocument.createElementNS("http://www.opengis.net/kml/2.2", "kml");
and:
Element mKmlElement = mDocument.createElementNS("http://www.opengis.net/kml/2.2", "Placemark");
and the same goes for the gx:Track element:
Element gxTrackElement = mDocument.createElementNS("http://www.google.com/kml/ext/2.2","gx:Track");
Once you get your Document objects truly equal and correct, you then need to adjust your XPath.
With XPath, if you don't apply a namespace prefix, it will select elements bound to the "no namespace". So, /kml will only select kml elements that are not bound to a namespace. But since your kml elements are bound to the http://www.opengis.net/kml/2.2 namespace, it won't select them.
In your override of the getNamespaceURI() function, you could reserve gx for the Google KML Extension namespace, and then default any other namespace-prefix to resolve to http://www.opengis.net/kml/2.2:
#Override
public String getNamespaceURI(String prefix) {
return "gx".equals(prefix) ? "http://www.google.com/kml/ext/2.2" : "http://www.opengis.net/kml/2.2";
}
Then, adjust your XPath statements to use a prefix for those KML elements. If you use the above code, it doesn't matter what prefix you use. Anything other than gx will return the http://www.opengis.net/kml/2.2 namespace.
NodeList result1 = (NodeList) xPath.evaluate("/k:kml", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result1.getLength()));
System.out.println("Namespace URI: " + result1.item(0).getNamespaceURI());
System.out.println("Prefix: " + result1.item(0).getPrefix());
NodeList result2 = (NodeList) xPath.evaluate("/k:kml/k:Placemark", mDocument, XPathConstants.NODESET);
System.out.println( String.valueOf(result2.getLength()));
NodeList result3 = (NodeList) xPath.evaluate("/k:kml/k:Placemark/gx:Track", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result3.getLength()));
Putting it all together:
public App() {
super();
try {
test( testDoc1() );
test( testDoc2() );
} catch( Exception e ) {
e.printStackTrace();
} finally {
Log.d( "TEST-FINISHED", "test is finished" );
}
}
private String toXmlString(Document document) throws TransformerException {
DOMSource domSource = new DOMSource(document);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
return writer.toString();
}
private Document testDoc1() throws ParserConfigurationException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document mDocument = documentBuilderFactory.newDocumentBuilder().newDocument();
String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
//Element mKmlElement = mDocument.createElement("kml");
Element mKmlElement = mDocument.createElementNS("http://www.opengis.net/kml/2.2", "kml");
//mKmlElement.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns", "http://www.opengis.net/kml/2.2");
mKmlElement.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns:gx", "http://www.google.com/kml/ext/2.2");
mDocument.appendChild(mKmlElement);
//Element mPlacemarkElement = mDocument.createElement("Placemark");
Element mPlacemarkElement = mDocument.createElementNS("http://www.opengis.net/kml/2.2", "Placemark");
//mPlacemarkElement.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns", "http://www.opengis.net/kml/2.2");
mKmlElement.appendChild(mPlacemarkElement);
//Element gxTrackElement = mDocument.createElement("gx:Track");
Element gxTrackElement = mDocument.createElementNS("http://www.google.com/kml/ext/2.2","gx:Track");
mPlacemarkElement.appendChild(gxTrackElement);
//Element gxCoordElement = mDocument.createElement("gx:coord");
Element gxCoordElement = mDocument.createElementNS("http://www.google.com/kml/ext/2.2", "gx:coord");
gxCoordElement.setTextContent("-122.207881 37.371915 156.000000");
gxTrackElement.appendChild(gxCoordElement);
return mDocument;
}
private Document testDoc2() throws ParserConfigurationException, IOException, SAXException {
String kmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\"><Placemark><gx:Track><gx:coord>-122.207881 37.371915 156.000000</gx:coord></gx:Track></Placemark></kml>";
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
Document mDocument = documentBuilderFactory.newDocumentBuilder().parse(new
InputSource(new StringReader(kmlString)));
return mDocument;
}
private void test(Document mDocument) throws Exception {
String xml = toXmlString(mDocument);
System.out.println( xml);
XPath xPath = XPathFactory.newInstance().newXPath();
xPath.setNamespaceContext(new NamespaceContext() {
#Override
public String getNamespaceURI(String prefix) {
return "gx".equals(prefix) ? "http://www.google.com/kml/ext/2.2" : "http://www.opengis.net/kml/2.2";
}
#Override
public String getPrefix(String namespaceURI) {
if ("http://www.google.com/kml/ext/2.2".equals(namespaceURI)) {
return "gx";
}
return null;
}
#Override
public Iterator getPrefixes(String namespaceURI) {
List<String> ns = new ArrayList<>();
ns.add("gx");
return ns.iterator();
}
});
NodeList result1 = (NodeList) xPath.evaluate("/k:kml", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result1.getLength()));
System.out.println("Namespace URI: " + result1.item(0).getNamespaceURI());
System.out.println("Prefix: " + result1.item(0).getPrefix());
NodeList result2 = (NodeList) xPath.evaluate("/k:kml/k:Placemark", mDocument, XPathConstants.NODESET);
System.out.println( String.valueOf(result2.getLength()));
NodeList result3 = (NodeList) xPath.evaluate("/k:kml/k:Placemark/gx:Track", mDocument, XPathConstants.NODESET);
System.out.println(String.valueOf(result3.getLength()));
}

How to read a generic XML file in java

I'm looking for ways to read a generic xml file
Here is an example of a normal xml file
<?xml version="1.0"?>
<students>
<student>
<name>John</name>
<grade>B</grade>
<age>12</age>
</student>
<student>
<name>Mary</name>
<grade>A</grade>
<age>11</age>
</student>
<student>
<name>Simon</name>
<grade>A</grade>
<age>18</age>
</student>
</students>
and here is example of a typical xml parser that would read that code and print it out
public class XMLParser {
public void getAllUserNames(String fileName) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
File file = new File(fileName);
if (file.exists()) {
Document doc = db.parse(file);
Element docEle = doc.getDocumentElement();
// Print root element of the document
System.out.println("Root element of the document: "
+ docEle.getNodeName());
NodeList studentList = docEle.getElementsByTagName("student");
// Print total student elements in document
System.out
.println("Total students: " + studentList.getLength());
if (studentList != null && studentList.getLength() > 0) {
for (int i = 0; i < studentList.getLength(); i++) {
Node node = studentList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
System.out
.println("=====================");
Element e = (Element) node;
NodeList nodeList = e.getElementsByTagName("name");
System.out.println("Name: "
+ nodeList.item(0).getChildNodes().item(0)
.getNodeValue());
nodeList = e.getElementsByTagName("grade");
System.out.println("Grade: "
+ nodeList.item(0).getChildNodes().item(0)
.getNodeValue());
nodeList = e.getElementsByTagName("age");
System.out.println("Age: "
+ nodeList.item(0).getChildNodes().item(0)
.getNodeValue());
}
}
} else {
System.exit(1);
}
}
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
XMLParser parser = new XMLParser();
parser.getAllUserNames("c:\\test.xml");
}
}
This code needs lines like this
NodeList studentList = docEle.getElementsByTagName("student");
NodeList nodeList = e.getElementsByTagName("name");
In order to work correctly.
My questions comes from how would I make that generic. Is there any way where I could read that same XML file without having to get specific elements by tagNames and yet still print it out in a view able format.
In the above example you are using Dom parser. By using Jaxb Context unmarshaller you can convert the xml to java object, then you can achive your task.
You need to have a generic function to handle.
Generic function is as follows:
/* Prints the Node Value */
public void PrintNodeValue(Element element, String tagName, String msg)
{
NodeList nodeList = element.getElementsByTagName(tagName);
System.out.println(msg + nodeList.item(0).getChildNodes().item(0).getNodeValue());
}
Function is called as below:
PrintNodeValue(e, "name", "Name: ");
PrintNodeValue(e, "grade", "Grade: ");

Get Soap Body using XPath and XML XPath Api

I use XML XPath API in my application
This is my soap request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tes="http://testwork/">
<soapenv:Header/>
<soapenv:Body>
<tes:sayHelloWorldFrom>
<!--Optional:-->
<arg0>value</arg0>
</tes:sayHelloWorldFrom>
</soapenv:Body>
</soapenv:Envelope>
I want to retrieve the body from this message, thus I want to have
<soapenv:Body>
<tes:sayHelloWorldFrom>
<!--Optional:-->
<arg0>value</arg0>
</tes:sayHelloWorldFrom>
</soapenv:Body>
My piece of code looks like
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
org.w3c.dom.Document doc = null;
try {
doc = factory.newDocumentBuilder().parse(is);
XPathFactory xFactory = XPathFactory.newInstance();
XPath xPath = xFactory.newXPath();
Object result = xPath.compile("/soapenv:Envelope/soapenv:Body").evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
log.info("result " + nodes);
But the result is result com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList#19f76837
So what am I doing wrong?
XPathConstants.NODESET instructs the API to return a NodeList of the results it finds matching the query.
This is useful when you are expecting a variable number of matches. You can iterate over the list...
for (int index = 0; index < nodes.getLength(); index++) {
Node node = nodes.item(index);
//...
}
If you are confident that you will only receive a single result (or you just want the first match), you can use XPathConstants.NODE instead
Object result = xPath.compile("/soapenv:Envelope/soapenv:Body").evaluate(doc, XPathConstants.NODE);
Node node = (Node)result;
Updated
There's probably away to do this without doing the following, but name spaces do my head...
After you create the factory, set it's name space awareness tofalse`, then drop the node name space context from your search, for example...
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
org.w3c.dom.Document doc = null;
try {
doc = factory.newDocumentBuilder().parse(new File("Soap.xml"));
XPathFactory xFactory = XPathFactory.newInstance();
XPath xPath = xFactory.newXPath();
Object result = xPath.compile("/Envelope/Body").evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
System.out.println("Found " + nodes.getLength() + " matches");
for (int index = 0; index < nodes.getLength(); index++) {
Node node = nodes.item(index);
System.out.println(node);
}
} catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException exp) {
exp.printStackTrace();
}

Generating XPATH Query issue

I have a SOAP Response as below
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<NTService.DisconnectResourceResult xmlns="http://www.evolving.com/NumeriTrack/xsd">
<retData xmlns="">
<retCode>rcSuccess</retCode>
<retMsg/>
<resErrList/>
</retData>
</NTService.DisconnectResourceResult>
</soapenv:Body>
</soapenv:Envelope>
Am not good in generating XPATH query, but using SOAPUI I was able to fetch the XPATH query to fetch retCode as below :
//ns1:NTService.DisconnectResourceResult[1]/retData[1]/retCode[1]/text()
In Java, am trying to fetch retCode but am unable to fetch the output.
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new SoapNamespaceContext());
String sxpath="//ns1:NTService.DisconnectResourceResult[1]/retData[1]/retCode[1]/text()";
System.out.println("sxpath is " + sxpath);
XPathExpression expr;
expr = xpath.compile(sxpath);
System.out.println("expr is " + expr);
Object result;
result = expr.evaluate(sb, XPathConstants.NODESET);
System.out.println("result is " + result);
NodeList nodes = (NodeList) result;
System.out.println("Length of result is " + nodes.getLength());
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
I have set the namespace as well.
public String getNamespaceURI(String prefix) {
System.out.println("Prefix is " +prefix);
if (prefix == null) throw new NullPointerException("Null prefix");
else if ("ns1".equals(prefix)) {
System.out.println("Returning http://www.evolving.com/NumeriTrack/xsd");
return "http://www.evolving.com/NumeriTrack/xsd";
}
else if ("n".equals(prefix)) {
System.out.println("Returning http://schemas.xmlsoap.org/soap/envelope/");
return "http://schemas.xmlsoap.org/soap/envelope/";
}
else if ("xml".equals(prefix)) return XMLConstants.XML_NS_URI;
return XMLConstants.NULL_NS_URI;
}
`
Can anyone please suggest me to get retCode from the SOAP Message response.
Thanks
Here's the anserw :
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File("D:\\Loic_Workspace\\Test2\\res\\test.xml"));
System.out.println(doc.getElementsByTagName("retCode").item(0).getTextContent());
You should use .getTextContent() method.
Will output rcSuccess as you want :)
Hope it's helps,

java xml dom parsing

I have this project I'm working on where I want to parse an xml file that looks like this:
<?xml version='1.0' encoding='UTF-8'?>
<projectlist>
<project>
<name>SuperDuperApp</name>
<type>batch</type>
<prod>
<server>testserver01</server>
</prod>
<qa>
<server>testserver01</server>
</qa>
<dev>
<server>testserver01</server>
</dev>
</project>
<project>
<name>Calculator</name>
<type>deploy</type>
<prod>
<server>testserver02</server>
<server>testserver03</server>
<server>testserver04</server>
</prod>
<qa>
<server>testserver05</server>
<server>testserver06</server>
<server>testserver07</server>
</qa>
<dev>
<server>testserver12</server>
<server>testserver13</server>
<server>testserver14</server>
</dev>
</project>
</projectlist>
With this method parsing the file and trying to print out in the format:
name: SuperDuperApp
type: batch
server: testserver01
name: Calculator
type: deploy
environment: dev
server: testserver12
server: testserver13
server: testserver14
etc.
public void parseXML() {
ArrayList al = new ArrayList();
HashSet hs = new HashSet();
try {
InputStream file = this.getClass().getResourceAsStream(
"/net/swing/sandbox/util/config/projectlist.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(file);
doc.getDocumentElement().normalize();
System.out.println("Root element: " + doc.getDocumentElement().getNodeName());
NodeList nList = doc.getElementsByTagName("project");
System.out.println("Information of all servers...");
for (int i=0;i<nList.getLength();i++){
Node fstNode = nList.item(i);
if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
Element fstElement = (Element) fstNode;
NodeList nameElementList = fstElement.getElementsByTagName("name");
Element nameElement = (Element) nameElementList.item(0);
NodeList name = nameElement.getChildNodes();
System.out.println("project name: " + ((Node) name.item(0)).getNodeValue());
hs.add(((Node) name.item(0)).getNodeValue());
NodeList typeElementList = fstElement.getElementsByTagName("type");
Element typeElement = (Element) typeElementList.item(0);
NodeList type = typeElement.getChildNodes();
System.out.println("Deploy type: " + ((Node) type.item(0)).getNodeValue());
//print out server list can't do it for some reason
}
}
} catch (Exception e) {
e.printStackTrace();
}
try {
al.clear();
al.addAll(hs);
Collections.sort(al);
for (int z = 0; z < al.size(); z++) {
listModel.addElement(al.get(z));
}
} catch (Exception e) {
e.printStackTrace();
}
lstProject.validate();
}
So I rewrote my method and now I'm just stuck <---newb
Check the documentation for Node. Each node has a method getChildNodes. Check that for the existence of children nodes and than iterate over them like you are doing.
If your xml was created using an xsd schema, you could instead use JAXB to create classes for it, using the xjc tool. That should make your life a bit easier.
I think it's appropriate to use XSLT transform in your case (much less boilerplate code) Look at TransformerFactory and java api for xml processing.
As a q&d solution you could apply the same strategy as for getting "project" node:
...
System.out.println("servers:");
NodeList sList = eElement.getElementsByTagName("server");
for (int i = 0; i < sList.getLength(); i++) {
String stuff = sList.item(i).getFirstChild().getNodeValue();
System.out.println(stuff);
}

Categories