XML :
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<wmHotelAvailResponse xmlns="http://host.com/subPath">
<OTA_HotelAvailRS Version="1.001">
</OTA_HotelAvailRS>
</wmHotelAvailResponse>
</soap:Body>
</soap:Envelope>
Code :
String xpathString = "/soap:Envelope/soap:Body/wmHotelAvailResponse/OTA_HotelAvailRS";
AXIOMXPath xpathExpression = new AXIOMXPath(xpathString);
xpathExpression.addNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
xpathExpression.addNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
xpathExpression.addNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
OMElement rsMsg = (OMElement)xpathExpression.selectSingleNode(documentElement);
String version = rsMsg.getAttribute(new QName("Version")).getAttributeValue();
Question :
This is working perfectly when the xmlns="http://host.com/subPath" part is deleted. I wanna know how can I add xmlns="http://host.com/subPath" part to the xpathExpression to make the above work
I tried below but didn't work.
xpathExpression.addNamespace("", "http://host.com/subPath");
Solution:
.1. Add this code:
xpathExpression.addNamespace("x", "http://host.com/subPath");
.2. Change:
String xpathString = "/soap:Envelope/soap:Body/wmHotelAvailResponse/OTA_HotelAvailRS";
to:
String xpathString = "/soap:Envelope/soap:Body/x:wmHotelAvailResponse/x:OTA_HotelAvailRS";
Explanation:
Xpath always treats any unprefixed element name as belonging to "no namespace".
Therefore when evaluating the XPath expression:
/soap:Envelope/soap:Body/wmHotelAvailResponse/OTA_HotelAvailRS
the Evaluator tries to find a wmHotelAvailResponse element that is in "no namespace" and fails because the only wmHotelAvailResponse element in the document belongs to the "http://host.com/subPath" namespace.
Related
I wondered how it was possible to get the content of a SOAP response body child when the child tag looks like this:
<sth:x>...</sth:x>
In the Oracle docs I found how to loop all Elements with a specific name.
But therefore I need to create an Element first that specifies the name of the tag I want to search.
How do I create an element looking like the one above? I know how to make one like this:
<sth:id sth="asdf">
But that doesn't really work.
Here is the server-response I attempt to read.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header/>
<soapenv:Body>
<ns5:loginResponse xmlns:ns5="x">
<ns5:id>Value I am looking for</ns5:id>
<ns5:rc>0</ns5:rc>
</ns5:loginResponse>
</soapenv:Body>
</soapenv:Envelope>
Thanks for your help :)
Try this:
String xml = "YourXMl";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(xml));
Document doc = builder.parse(is);
NodeList nodes = doc.getDocumentElement().getElementsByTagNameNS("x","id");
System.err.println(nodes.item(0).getChildNodes().item(0).getNodeValue());
There are two important things factory.setNamespaceAware(true); - to turn on support for xml namespaces.
doc.getDocumentElement().getElementsByTagNameNS("x","id"); To get element using namespace uri and element name. And here is <ns5:loginResponse xmlns:ns5="x"> declaration of namespace uri. x is uri ns5 is namespace.
I found the answer:
The Element in question was within another SOAPBodyElement.
So looping through both elements gave me the correct Value:
body = reply.getSOAPBody();
Iterator replyIt = body.getChildElements();
while(replyIt.hasNext()){
SOAPBodyElement replysbe = (SOAPBodyElement) replyIt.next();
Iterator replyIt2 = replysbe.getChildElements();
SOAPElement sentSE = (SOAPElement) replyIt2.next();
sessionID = sentSE.getValue();
}
I am trying to extract a 'PartyID' from a request using XPath. This request is in the form of XML.
Here is the XML:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<s1:invokerules xmlns:s1="http://rules.kmtool.abc.com"><s1:arg0><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<kbdInitiateRequest>
<kmTestHeader>
<MessageId>USER1_MSG1</MessageId>
<TestDate>08/07/2008 07:34:15</TestDate>
<TestReference>
<ConductorReference>
<InvokeIdentifier>
<RefNum>USER1_Ref1</RefNum>
</InvokeIdentifier>
</ConductorReference>
</TestReference>
<TestParty>
<ConductorParty>
<Party PartyID="123456789" AgencyID="DUNS">
<TestContact>
<DetailedContact>
<ContactName>Michael Jackson</ContactName>
<Telephone>02071059053</Telephone>
<TelephoneExtension>4777</TelephoneExtension>
<Email>Michal.Jackson#Neverland.com</Email>
<Title>Mr</Title>
<FirstName>Michael</FirstName>
<Initials>MJ</Initials>
</DetailedContact>
</TestContact>
</Party>
</ConductorParty>
<PerformerParty>
<Party PartyID="987654321" AgencyID="DUNS">
</Party>
</PerformerParty>
</TestParty>
</kmTestHeader>
<kmToolMessage>
<controlNode>
<userRequest>INITIATE</userRequest>
</controlNode>
<customer>
<circuitID>000111333777</circuitID>
</customer>
</kmToolMessage>
</kbdInitiateRequest>
]]></s1:arg0>
</s1:invokerules>
</soapenv:Body>
</soapenv:Envelope>
I have a method in my java code called getPartyId(). This method should extract the PartyID from the XML. However I cannot get this method to return the PartyID no matter what XPath query I use, this is where I need help.
Here is the getPartyId method:
private String getPartyId(String xml) throws XPathExpressionException
{
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
if (prefix == null) throw new NullPointerException("Null prefix");
else if ("SOAP-ENV".equals(prefix)) return "http://schemas.xmlsoap.org/soap/envelope/";
else if ("xml".equals(prefix)) return XMLConstants.XML_NS_URI;
return XMLConstants.NULL_NS_URI;
}
public String getPrefix(String uri) {
throw new UnsupportedOperationException();
}
public Iterator getPrefixes(String uri) {
throw new UnsupportedOperationException();
}
});
XPathExpression expr = xpath.compile("/SOAP-ENV:Envelope/SOAP-ENV:Body/*/*/*/*/*/*/*/*/*/*/*[local-name()='PartyID']/text()");
InputSource source = new InputSource(new StringReader(xml));
String dunsId = (String) expr.evaluate(source,XPathConstants.STRING);
return dunsId;
}
I believe that the problem lies with the XPathExpression:
XPathExpression expr = xpath.compile("/SOAP-ENV:Envelope/SOAP-ENV:Body/*/*/*/*/*/*/*/*/*/*/*[local-name()='PartyID']/text()");
I have tried a number of alternatives for 'expr' however none of these have worked. Has anyone got any ideas?
Because the xml you need to parse is sitting inside a CDATA block, you'll need to re-parse the value of s1:arg0 before accessing data within it.
You will need to do this in 2 steps
You will need to access the arg0 node in the http://rules.kmtool.abc.com namespace.
Since you don't have a NamespaceContext for this inner xmlns, you can use :
/SOAP-ENV:Envelope/SOAP-ENV:Body/*[local-name()='invokerules']
/*[local-name()='arg0']/text()
You then need to load this value into another InputSource.
The PartyId attribute can be accessed via the path:
kbdInitiateRequest/kmTestHeader/TestParty/ConductorParty/Party/#PartyID
(no need to use local-name() since there aren't any xmlns in the CDATA)
Notice that your inner xml is inside CDATA node.
So basiclly you are trying to query path of an XML inside CDATA.
As this thread state
Xpath to the tag inside CDATA
Seems this is not possible :(
I would suggest take the CData inside the code and parse it into a new XML Document and query that.
Thanks,
Amir
I am very new in XPath and I have the following problem:
I have a Java method that receives data from a webservices and these data are in a XML document, so I have to use XPath to take a specific value inside this XML result document.
In particular I have that this is the entire XML output provided by my web service (the web service response):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<getConfigSettingsResponse xmlns="http://tempuri.org/">
<getConfigSettingsResult><![CDATA[<root>
<status>
<id>0</id>
<message></message>
</status>
<drivers>
<drive id="tokenId 11">
<shared-secret>Shared 11</shared-secret>
<encoding>false</encoding>
<compression />
</drive>
<drive id="tokenId 2 ">
<shared-secret>Shared 2 </shared-secret>
<encoding>false</encoding>
<compression>false</compression>
</drive>
</drivers>
</root>]]></getConfigSettingsResult>
</getConfigSettingsResponse>
</s:Body>
</s:Envelope>
Now in a Java class I perform the following operations:
XPath xPath; // An utility class for performing XPath calls on JDOM nodes
Element objectElement; // An XML element
//xPath = XPath.newInstance("s:Envelope/s:Body/getVersionResponse/getVersionResult");
try {
// XPath selection:
xPath = XPath.newInstance("s:Envelope/s:Body");
xPath.addNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
objectElement = (Element) xPath.selectSingleNode(documentXML);
if (objectElement != null) {
result = objectElement.getValue();
System.out.println("RESULT:");
System.out.println(result);
}
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
and the result of printing the content of the result variable is this output:
RESULT:
<root>
<status>
<id>0</id>
<message></message>
</status>
<drivers>
<drive id="tokenId 11">
<shared-secret>Shared 11</shared-secret>
<encoding>false</encoding>
<compression />
</drive>
<drive id="tokenId 2 ">
<shared-secret>Shared 2 </shared-secret>
<encoding>false</encoding>
<compression>false</compression>
</drive>
</drivers>
</root>
Now my problem is that I want to access only ad the content of the 0 tag, so I want that (in this case) my result variable have to contain the 0 value.
But I can't, I have try to change the previous XPath selection with:
xPath = XPath.newInstance("s:Envelope/s:Body/s:status/s:id");
But doing in this way I obtain that my objectElement is null
Why? What am I missing? What have I to do to obtain that mu result variable contains the content of the id tag?
Tnx
Andrea
Yours "root" node in "CDATA" section. Whole section interpetated as text, and you cannot search it by xPath. You can get text from "objectElement.getValue()", parse it like new XML, and then get tag "id" value with new xPath. Also you can search "objectElement.getValue()" for tag "id" value with regular expression.
Really you should be using the new XPathAPI in JDOM 2.x, and taking pasha701's answer in to consideration, your code should look more like:
Namespace soap = Namespace.getNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
Namespace tempuri = Namespace.getNamespace("turi", ""http://tempuri.org/");
XPathExpression<Element> xpath = XPathFactory.instance().compile(
"s:Envelope/s:Body/turi:getConfigSettingsResponse/turi:getConfigSettingsResult",
Filters.element(), null, soap, tempuri);
Element result = xpath.evaluateFirst(documentXML);
String resultxml = result.getValue();
Document resultdoc = new SAXBuilder().build(new StringReader(resultxml));
Element id = resultdoc.getRootElement().getChild("status").getChild("id");
How to read From XML <returnMsg>Successful</returnMsg> value of this tag in java?
How to read the data of the tags in this example.
I am getting The processing instruction target matching "[xX][mM][lL]" is not allowed. Exception is getting
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<doServiceResponse xmlns="http://ocs.ztesoft.com">
<doServiceReturn><?xml version="1.0" encoding="UTF-8"?>
<zsmart>
<Data>
<header>
<returnMsg>Successful</returnMsg>
<ACTION_ID>ModifyBalReturnAllBal</ACTION_ID>
<REQUEST_ID>0032013070900000503</REQUEST_ID>
<returnCode>0</returnCode>
</header>
<body>
<TransactionSN>503</TransactionSN>
</body>
</Data>
</zsmart>
</doServiceReturn></doServiceResponse></soapenv:Body></soapenv:Envelope>
JAVA CODE
dbf = DocumentBuilderFactory.newInstance();
db = dbf.newDocumentBuilder();
is = new InputSource();
is.setCharacterStream(new StringReader(respString));
doc = db.parse(is);
nodes = doc.getElementsByTagName("soapenv:Envelope");
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
NodeList txnStatus = element.getElementsByTagName("returnCode");
Element line = (Element) txnStatus.item(0);
bean.setTxnStatus(getCharacterDataFromElement(line));
NodeList message = element.getElementsByTagName("returnMsg");
line = (Element) message.item(0);
bean.setMessage(getCharacterDataFromElement(line));
}
Exception
org.xml.sax.SAXParseException: The processing instruction target matching "[xX][mM][lL]" is not allowed.
There are many way to convert XML file to JAVA OBJECT.
SAX and JAXB algorithms are two of them.
JAXB algorithm is more easily to use. i prefer to use JAXB.
HERE is the link that helps you to create Object from XML file.
enjoy it...
http://www.mkyong.com/java/jaxb-hello-world-example/
Following is a snippet of .xml file. I did following :
Document doc = docBuilder.parse(filesInDirectory.get(i));
doc.getDocumentElement().normalize();
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression expr1 = xPath.compile("//codes[# class ='class2']/code[#code]");
Object result1 = expr1.evaluate(doc, XPathConstants.NODESET);
NodeList nodes1 = (NodeList) result1;
Now,
System.out.println("result length"+":"+nodes1.getLength());
returns 2.
I would like to make logical decision based on the attribute names, like(pseudocode)
if(nodes1.contains(123))
or
if(nodes1.contains(123) && nodes1.contains(456))
and make decision.
how would i do it?
<metadata>
<codes class="class1">
<code code="ABC">
<detail "blah" "blah">
</code>
</codes>
<codes class="class2">
<code code="123">
<detail "blah blah"/>
</code>
<code code="456">
<detail "blah blah"/>
</code>
</codes>
</metadata>
This:
XPathExpression expr1 = xPath.compile("//codes[#class]");
Object result1 = expr1.evaluate(doc, XPathConstants.NODESET);
NodeList nodes1 = (NodeList) result1;
should return you a list of elements with a class attribute. Iterate over this node list and foreach node extract the [#code] element and use a check like
if (node.getNodeValue().equals("123"))
to establish whether your node has the value you are looking for.
Try out this:
File f = new File("test.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
InputSource src = new InputSource(new FileInputStream(f));
Object result = xpath.evaluate("//codes[#class='class2']/code/#code",src,XPathConstants.NODESET);
NodeList lst = (NodeList)result;
List<String> codeList = new ArrayList<String>();
for(int idx=0; idx<lst.getLength(); idx++){
codeList.add(lst.item(idx).getNodeValue());
}
if(codeList.contains("123")){
System.out.println("123");
}
if(codeList.contains("123") && codeList.contains("456")){
System.out.println("123 and 456");
}
Explanation:
XPath //codes[#class='class2']/code/#code will collect all code values under codes with having class as class2.
You can then build a List from NodeList so that you can use contains() method.
Use this XPath expression:
/*/codes[#class]/code[#code = '123' or #code = '456']
It selects any code element whose code attribute's string value is one of the strings "123" or "456" and that (the code element) is a child of a codes element that has a `class attribute and is a child of the top element of the XML document.
XSLT - based verification:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy-of select=
"/*/codes[#class]/code[#code = '123' or #code = '456']"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document (corrected to be made well-formed):
<metadata>
<codes class="class1">
<code code="ABC">
<detail/>
</code>
</codes>
<codes class="class2">
<code code="123">
<detail />
</code>
<code code="456">
<detail />
</code>
</codes>
</metadata>
the XPath expression is evaluated and the selected nodes are copied to the output:
<code code="123">
<detail/>
</code>
<code code="456">
<detail/>
</code>
Explanation:
Proper use of the standard XPath operator or.