XPath failing for namespaced XML via SQL EXTRACTVALUE? - sql

I have am trying to parse FaultMessage from an XML response using EXTRACTVALUE. Below is my SQL code:
SELECT EXTRACTVALUE( XMLTYPE('
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang="tr-TR">İstek şeması doğrulanamadı. Lütfen tüm bilgileri kontrol edin.</faultstring>
<detail>
<Fault xmlns="http://schemas.datacontract.org/2004/07/CustomServiceLibrary.DataContract" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<FaultCode>Schema_Customer_005|1e8c66-c333-4357-9c7d-3f4fcd553</FaultCode>
<FaulCategory>Schema</FaulCategory>
<FaultMessage> Customer name can not be blank, can not contain spaces, or any special characters. LASTNAMEFIRSTNAME is the required format. </FaultMessage>
<FaultDetailedMessage>UMUT DEMIRCI</FaultDetailedMessage>
</Fault>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>'),
'/s:Envelope/s:Body/s:Fault/detail/*:Fault/FaultMessage',
'xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="http://schemas.datacontract.org/2004/07/CustomServiceLibrary.DataContract" ') a
FROM DUAL
Please suggest how I can get FaultMessage.

Given:
The deeper Fault element and its descendents are in the http://schemas.datacontract.org/2004/07/CustomServiceLibrary.DataContract namespace.
You appear to have already defined the a namespace prefix for http://schemas.datacontract.org/2004/07/CustomServiceLibrary.DataContract
Using * as a wildcard for a namespace prefix requires XPath 2.0+.
Change
/s:Envelope/s:Body/s:Fault/detail/*:Fault/FaultMessage
to
/s:Envelope/s:Body/s:Fault/detail/a:Fault/a:FaultMessage
so that your XPath will be correct and not require an XPath 2.0+ processor.

Related

SQL Server Xml query with cascading namespaces

How do I select the value of "pagekey" from the xml below with SQL on SQL Server? I tried .nodes using namespaces but cannot find the correct syntax.
Thank you,
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<WorkContext xmlns="http://oracle.com/weblogic/soap/workarea/">rO03ZWJsb2dpYy5hcHAuU0JNLVJhcG9yV1MAAADWAAAAI3dlYmxvZ2ljLndvcmthcmVhL0cmluZ1dvcmtDb250ZXh0ABIyMDIwLE4LjE0MjIuNDAAAA==</WorkContext>
</S:Header>
<S:Body>
<ns0:getReportOutputResponse xmlns:ns0="http://report_xml.org">
<return>
<pagekey>i6161140E964FF7A072CD2E3F2BB9C0</pagekey>
<report><?xml version="1.0"?><dataSet xmlns="http://report_xml.org/dataSet/201006"><dataTable><id>C1</id></dataTable></dataSet></report>
</return>
</ns0:getReportOutputResponse>
</S:Body>
</S:Envelope>
Something like this?
DECLARE #data XML = '<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<WorkContext xmlns="http://oracle.com/weblogic/soap/workarea/">rO03ZWJsb2dpYy5hcHAuU0JNLVJhcG9yV1MAAADWAAAAI3dlYmxvZ2ljLndvcmthcmVhL0cmluZ1dvcmtDb250ZXh0ABIyMDIwLE4LjE0MjIuNDAAAA==</WorkContext>
</S:Header>
<S:Body>
<ns0:getReportOutputResponse xmlns:ns0="http://report_xml.org">
<return>
<pagekey>i6161140E964FF7A072CD2E3F2BB9C0</pagekey>
<report><?xml version="1.0"?><dataSet xmlns="http://report_xml.org/dataSet/201006"><dataTable><id>C1</id></dataTable></dataSet></report>
</return>
</ns0:getReportOutputResponse>
</S:Body>
</S:Envelope>';
-- define the two relevant XML namespaces
WITH XMLNAMESPACES('http://schemas.xmlsoap.org/soap/envelope/' AS soap,
'http://report_xml.org' AS RP)
SELECT
-- get the "pagekey" element from the "body"
XC.value('(RP:getReportOutputResponse/return/pagekey/text())[1]', 'VARCHAR(100)')
FROM
-- get the <s:Body> part as XML fragment
#data.nodes('/soap:Envelope/soap:Body') AS XT(XC)

pasring xml response from a soap webservice to save in table

I am Calling a Soap Service in plsql and i get response in xml format
i want to parse the xml and want to save a single value in Oracle Table.
Below xml ouput :
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<ActivityId xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics" CorrelationId="3c08103b-65da-4f34-95e7-ec2c90ba5b74">00000000-0000-0000-0000-000000000000</ActivityId>
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
<u:Timestamp u:Id="_0">
<u:Created>2019-04-16T20:21:06.467Z</u:Created>
<u:Expires>2019-04-16T20:26:06.467Z</u:Expires>
</u:Timestamp>
</o:Security>
</s:Header>
<s:Body>
<SaveSalesResponse xmlns="https://unifree.com.tr/services/custom">
<SaveSalesResult xmlns:a="http://schemas.datacontract.org/2004/07/CustomServiceLibrary.DataContract" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Result>true</a:Result>
<a:Provision>
<a:ProvisionNo>245982</a:ProvisionNo>
</a:Provision>
</SaveSalesResult>
</SaveSalesResponse>
</s:Body>
</s:Envelope>
I want to save <a:ProvisionNo>245982</a:ProvisionNo> this number in table
Please suggest an easy way to store value in table
With the premise that the example document you provided is representative of the layout of document being used (that there is only one <s:Body>, with only one <SaveSalesResponse>, and so forth to a single <a:PorivisionNo> per document, then EXTRACTVALUE is all that should be required.
If your data set includes more complex structures housing multiple <a:ProvisionNo> per document, I would recommend extracting the values with XMLQUERY/XMLTABLE instead.
An example of loading a table with the <a:ProvisionNo> via EXTRACTVALUE is below.
CREATE TABLE PROVISION_NO(THE_PROVISION_NO INTEGER);
Table created.
Then run the load:
INSERT INTO PROVISION_NO(THE_PROVISION_NO)
SELECT EXTRACTVALUE( XMLTYPE('<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<ActivityId xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics" CorrelationId="3c08103b-65da-4f34-95e7-ec2c90ba5b74">00000000-0000-0000-0000-000000000000</ActivityId>
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
<u:Timestamp u:Id="_0">
<u:Created>2019-04-16T20:21:06.467Z</u:Created>
<u:Expires>2019-04-16T20:26:06.467Z</u:Expires>
</u:Timestamp>
</o:Security>
</s:Header>
<s:Body>
<SaveSalesResponse xmlns="https://unifree.com.tr/services/custom">
<SaveSalesResult xmlns:a="http://schemas.datacontract.org/2004/07/CustomServiceLibrary.DataContract" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Result>true</a:Result>
<a:Provision>
<a:ProvisionNo>245982</a:ProvisionNo>
</a:Provision>
</SaveSalesResult>
</SaveSalesResponse>
</s:Body>
</s:Envelope>'),
'/s:Envelope/s:Body/*:SaveSalesResponse/*:SaveSalesResult/a:Provision/a:ProvisionNo',
'xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="http://schemas.datacontract.org/2004/07/CustomServiceLibrary.DataContract" ')
FROM DUAL;
1 row created.
And the result:
SELECT THE_PROVISION_NO FROM PROVISION_NO;
THE_PROVISION_NO
___________________
245982
1 row selected.

exctractvalue from xmltype / soap oracle

i need to get "ineedthis" value from field
REQUEST_INFO:
...
<s:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<X-dynaTrace xmlns="http://ns.dynatrace.com/wcf" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">FW3;-1003312095;1;-56375709;115092;0;975784079;78</X-dynaTrace>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<storeContract xmlns="xxx/integration">
<storeRequest>
<contract>
<contractSeries>ineedthis</contractSeries>
select extractvalue(XMLType(sap.REQUEST_INFO),'s/s/storeContract/storeRequest/contract/contractSeries')
from sap
cant get the value
You're trying to extract the path
s/s/storeContract/storeRequest/contract/contractSeries
but your SOAP response doesn't have any nodes called s; it has nodes called Envelope, Header and Body in the namespace s. So you potentially want the path:
/s:Envelope/s:Body/storeContract/storeRequest/contract/contractSeries
which on its own gets an LPX-00601: Invalid token error because it doesn't know what s: is. You can supply the namespaces with the third argument:
select extractvalue(XMLType(sap.request_info),
'/s:Envelope/s:Body/storeContract/storeRequest/contract/contractSeries',
'xmlns="xxx/integration" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"'
) as contractseries
from sap;
or the lazy way is to wildcard the namespace and only identify the final node you want:
select extractvalue(XMLType(sap.request_info),'//*:contractSeries') as contractseries
from sap;
But extractvaue is deprecated so it's better to use XMLQuery - still being lazy:
select XMLQuery('//*:contractSeries/text()'
passing XMLType(sap.request_info)
returning content) as contractseries
from sap;
or with explicit namespaces:
select XMLQuery('
declare default element namespace "xxx/integration";
declare namespace s="http://schemas.xmlsoap.org/soap/envelope/";
/s:Envelope/s:Body/storeContract/storeRequest/contract/contractSeries/text()'
passing XMLType(sap.request_info)
returning content) as contractseries
from sap;
CONTRACTSERIES
------------------------------
ineedthis
db<>fiddle

How to retrive value from soap response jmeter

I have this soap response and i need to get the value of the tag platformMessage i writed a xpath query but it doesnt work, checking the log file in jmeter in tells me this "Prefix must resolve to a namespace: ns2", heres the xpath query
/S:Envelope[#xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"]/S:Body/ns2:activateProductResponse[#xmlns:ns2="http://ws.business.api.fulfillmentengine.com/"]/return/platformMessage
heres the xml
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:activateProductResponse xmlns:ns2="http://ws.business.api.fulfillmentengine.millicom.com/">
<return>
<platformCode>1</platformCode>
<platformMessage>Fail operation.El set-top box ya existe. Code Response:|22098: 22098: 1</platformMessage>
<responseCode>13</responseCode>
<responseMessage>Error executing action in platforn</responseMessage>
<UUID>3cb49b29-513e-11e6-b5db-005056807f0c</UUID>
<platformName>INTRAWAY</platformName>
</return>
</ns2:activateProductResponse>
</S:Body>
</S:Envelope>
Using #xmlns:ns2 in the xpath is not valid because despite appearances a namespace is not the same as an attribute.
If you enable "use namespaces", then the following xpath should work:
/S:Envelope/S:Body/ns2:activateProductResponse/return/platformMessage
Or if you want a dirty (and slow) workaround, you can reference the node names like so:
/*[local-name()='Envelope']/*[local-name()='Body']/*/[local-name()='activateProductResponse]/return/platformMessage
you should read:
https://jmeter.apache.org/usermanual/component_reference.html#XPath_Extractor
https://jmeter.apache.org/usermanual/component_reference.html#XPath_Assertion
pay particular attention to:
As a work-round for namespace limitations of the Xalan XPath parser implementation on which JMeter is based, you can provide a Properties file which contains mappings for the namespace prefixes:
prefix1=Full Namespace 1
prefix2=Full Namespace 2
…
You reference this file in jmeter.properties file using the property:
xpath.namespace.config
Look in jmeter.properties for this property and everything is explained clearly

SQL Server Grabbing Value from XML parameter to use in later query

I am really new to SQL Server and stored procedures to begin with. I need to be able to parse an incoming XML file for a specific element's value and compare/save it later in the procedure.
I have a few things stacked against me. One the Element I need is buried deeply inside the document. I have had no luck in searching for it by name using methods similar to this:
select CurrentBOD = c.value('(local-name(.))[1]', 'VARCHAR(MAX)'),
c.value('(.)[1]', 'VARCHAR(MAX)') from #xml.nodes('PutMessage/payload/content/AcknowledgePartsOrder/ApplicationArea/BODId') as BODtable(c)
It always returns null.
So, I am trying something similar to this:
declare #BODtable TABLE(FieldName VARCHAR(MAX),
FieldValue VARCHAR(MAX))
SELECT
FieldName = nodes.value('local-name(.)', 'varchar(50)'),
FieldValue = nodes.value('(.)[1]', 'varchar(50)')
FROM
#xml.nodes('//*') AS BODtable(nodes)
declare #CurrentBOD VARCHAR(36)
set #CurrentBOD = ''
SET #CurrentBOD = (SELECT FieldValue from #BODtable WHERE FieldName = 'BODId')
This provides me the list of node names and values correctly (I test this in a query and BODtable has all elements listed with the correct values), but when I set #CurrentBOD it comes up null.
Am I missing an easier way to do this? Am I messing these two approaches up somehow?
Here is a part of the xml I am parsing for reference:
<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" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity- secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-wssecurity-utility-1.0.xsd">
<soap:Header>
<payloadManifest xmlns="???">
<c contentID="Content0" namespaceURI="???" element="AcknowledgePartsOrder" version="4.0" />
</payloadManifest>
<wsa:Action>http://www.starstandards.org/webservices/2005/10/transport/operations/PutMessage</wsa:Action>
<wsa:MessageID>uuid:df8c66af-f364-4b8f-81d8-06150da14428</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous</wsa:Address>
</wsa:ReplyTo>
<wsa:To>???</wsa:To>
<wsse:Security soap:mustUnderstand="1">
<wsu:Timestamp wsu:Id="Timestamp-bd91e76f-c212-4555-9b23-f66f839672bd">
<wsu:Created>2013-01-03T21:52:48Z</wsu:Created>
<wsu:Expires>2013-01-03T21:53:48Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken xmlns:wsu="???" wsu:Id="???">
<wsse:Username>???</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">???</wsse:Password>
<wsse:Nonce>???</wsse:Nonce>
<wsu:Created>2013-01-03T21:52:48Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<PutMessage xmlns="??????">
<payload>
<content id="???">
<AcknowledgePartsOrder xmlns="???" xmlns:xsi="???" xsi:schemaLocation="??? ???" revision="???" release="???" environment="???n" lang="en-US" bodVersion="???">
<ApplicationArea>
<Sender>
<Component>???</Component>
<Task>???</Task>
<ReferenceId>???</ReferenceId>
<CreatorNameCode>???</CreatorNameCode>
<SenderNameCode>???</SenderNameCode>
<DealerNumber>???</DealerNumber>
<PartyId>???</PartyId>
<LocationId />
<ServiceId />
</Sender>
<CreationDateTime>2013-01-03T21:52:47</CreationDateTime>
<BODId>71498800-c098-4885-9ddc-f58aae0e5e1a</BODId>
<Destination>
<DestinationNameCode>???</DestinationNameCode>
You need to respect the XML namespaces!
First of all, your target XML node <BODId> is inside the <soap:Envelope> and <soap:Body> tags - both need to be included in your selection.
Secondly, both the <PutMessage> as well as the <AcknowledgePartsOrder> nodes appear to have default XML namespaces (those xmlns=.... without a prefix) - and those must be respected when you select your data using XPath.
So assuming that <PutMessage xmlns="urn:pm"> and <AcknowledgePartsOrder xmlns="urn:apo"> (those are just guesses on my part - replace with the actual XML namespaces that you haven't shown use here), you should be able to use this XPath to get what you're looking for:
;WITH XMLNAMESPACES('http://schemas.xmlsoap.org/soap/envelope/' AS soap,
'urn:pm' AS ns, 'urn:apo' AS apo)
SELECT
XC.value('(apo:BODId)[1]', 'varchar(100)')
FROM
#YourXmlVariable.nodes('/soap:Envelope/soap:Body/ns:PutMessage/ns:payload/ns:content/apo:AcknowledgePartsOrder/apo:ApplicationArea') AS XT(XC)
This does return the expected value (71498800-c098-4885-9ddc-f58aae0e5e1a) in my case.