I am trying to extract operation name from incoming request.
Request:
<soapenv:Envelope xmlns:ser="http://visa.com/sd/pc/service" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
</soapenv:Header>
<soapenv:Body wsu:Id="id-058C2E38D966BC3F2E15372874505064" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<ser:ReportRequest FromDate="2017-11-01" Timezone="GMT" ToDate="2017-11-30" TransactionType="All"/>
</soapenv:Body>
</soapenv:Envelope>
Xpath used: /*[local-name()='Envelope']/*[local-name()='Body']/*
Getting the output: <ser:ReportRequest xmlns:ser="http://visa.com/sd/pc/service" FromDate="2017-11-01" Timezone="GMT" ToDate="2017-11-30" TransactionType="All"/>
expected output: ReportRequest
Any suggestion?
To retrieve the expected output ReportRequest you have to modify your XPath expression to
local-name(/*[local-name()='Envelope']/*[local-name()='Body']/*)
This gets the local-name of the first child in XPath-1.0.
If you'd want to get the names of all children you'd have to iterate over the core path expression and get the local-name() of each item separately.
If you'd have XPath-2.0 available, you could simplify that and use the following expression
/*[local-name()='Envelope']/*[local-name()='Body']/*/local-name()
to get all names of all the children of the soapenv:Body element.
Related
sample_xml='<employees>\
<person id="p1">\
<name value="Alice">ALICE</name>\
</person>\
<person id="p2">\
<name value="Alice">BOB</name>\
</person>\
<person id="p3">\
<name value="Alice"/>\
</person>\
</employees>'
data = [
[f'{sample_xml}']
]
df = spark.createDataFrame(data, ['data'])
df=df.selectExpr(
'xpath(data,"/employees/person/name[#value=\'Alice\']/text()") test'
)
this gives expcted ["ALICE", "BOB"]
Problem:
I want my result to be ["ALICE", "BOB","NA"]
i.e for empty path like below
<name value="Alice"/>
I want to return a default NA .
is it possible to achieve this ?
Regards
With XPath itself this is not possible. It can only return you the actual values of the matching nodes or nothing if no match.
In order to get NA or any other data that is not actually contained in the XML, you should wrap the basic XPath request with some additional, external code to return the customized output in case of no match.
In XPath 2.0, use /employees/person/name[#value=\'Alice\'] /(string(text()), 'NA')[1]".
It can't be done in XPath 1.0. In XPath 1.0 there's no such thing as a sequence of strings; you can only return a sequence of nodes, and you can only return nodes that are actually present in the input document.
Below is the sample XML fragment, from it i'm trying to filter out id's of articles matching both conditions as below. Currently i could extract id's for individual condition with help of expression below
get Avaialable articles, Xpath2 expression = (//*//*//*//*[starts-with(state,'Avaialable')])/id
get articles name starting with 'A' () , Xpath2 expression = (//*//*//*//*[starts-with(name,'A')])/id
I want to merge these conditions in a single expression and would like to
fetch id's of Articles where Name starts with 'A' AND articles which
are Available
. Tried multiple ways but not working as expected.
Dummy XML fragment:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:GetArtclesResponse
xmlns:ns2="XXX"
xmlns:ns4="XXX"
xmlns:ns3="XXX"
xmlns:ns6="XXX"
xmlns:ns5="XXX"
xmlns:ns8="XXX"
xmlns:ns7="XXX"
xmlns:ns13="XXX"
xmlns:ns9="XXX"
xmlns:ns12="XXX"
xmlns:ns11="XXX">
<serverTimeInfo timezone="+00:00" timestamp="1606409365419"/>
<items>
<count>2</count>
<articles>
<article>
<name>ABC</name>
<id>1234</id>
<state>Avaialable</state>
</article>
<article>
<name>XYZ</name>
<id>3456</id>
<state>Avaialable_Conditional</state>
</article>
</articles>
</items>
</ns3:GetArtclesResponse>
You can use and to check both:
(//*//*//*//*[starts-with(state,'Avaialable') and starts-with(name,'A')])/id
If you want to combine 2 different XPath expressions you can use | (union) operator like:
//article[state = 'Avaialable'] | //article[starts-with(name,'A')]
it will return you both:
nodes which have state=Available
and nodes which name starts with A
If you want to combine 2 conditions in a single XPath expression - go for and operator like:
//article[state = 'Avaialable' and starts-with(name,'A')]
it will return
nodes which nave state=available and whose name attribute starts with a
More information:
XPath Operators
The JMeter XPath2 Extractor: How to Achieve Better Correlations
As XML content in an HTTP POST request, I receive the following which I process in Xquery 3.1 (eXist-db 5.2):
<request id="foo">
<p>The is a description with a line break<br/>and another linebreak<br/>and
here is an ampersand&.</p>
<request>
My objective is to take the node <p> and insert it into a TEI file in eXist-db. If I just insert the fragment as-is, no errors are thrown.
However I need to transform any instances of string <br/> into element <lb/> before adding it to the TEI document. I try that with fn:parse-xml.
Applying the following, however, throws an error on &...which surprises me:
let $xml := <request id="foo">
<p>The is a description with a line break<br/>and
another linebreak<br/>and here is an ampersand&.</p>
<request>
let $newxml := <p>{replace($xml//p/text(),"<br/>","<lb/>")}</p>
return <p>{fn:parse-xml($newxml)}</p>
error:
Description: err:FODC0006 String passed to fn:parse-xml is not a well-formed XML document.: Document is not valid.
Fatal : The entity name must immediately follow the '&' in the entity reference.
If I remove & the fragment parses just fine. Why is this producing an error if it is legal XML? How can I achieve the needed result?
Many thanks in advance.
ps. I am open to both Xquery and XSLT solutions.
It seems that the issue is the HTML entities. It would work with numeric entities (i.e. < instead of < and > instead of >), but the XML parser doesn't know about HTML character entities.
Useutil:parse-html() instead of fn:parse-xml().
let $xml := <request id="foo">
<p>The is a description with a line break<br/>and
another linebreak<br/>and here is an ampersand&.</p>
</request>
return <p>{util:parse-html($xml/p/text())/HTML/BODY/node()}</p>
From my Response Data:
<?xml version="1.0"?>
<PERSON>
<NAME>Harry</NAME>
<AGE>24</AGE>
<REMARKS></REMARKS>
<DETAILS>
<GENDER>MALE</GENDER>
<EYE_COLOR>BLUE</EYE_COLOR>
</DETAILS>
</PERSON>
<?xml version="1.0"?>
<PERSON>
<NAME>Andrew</NAME>
<AGE>4</AGE>
<REMARKS></REMARKS>
<DETAILS>
<GENDER>MALE</GENDER>
<EYE_COLOR>GREEN</EYE_COLOR>
</DETAILS>
<DETAILS>
<WEIGHT>85KG</WEIGHT>
<HEIGHT>173CM</HEIGHT>
</DETAILS>
</PERSON>
..... and so on
I wish to Extract the whole of the 2nd Sequence and Verify its contents
<?xml version="1.0"?>
<PERSON>
<NAME>Andrew</NAME>
<AGE>4</AGE>
<REMARKS></REMARKS>
<DETAILS>
<GENDER>MALE</GENDER>
<EYE_COLOR>GREEN</COLOR>
</DETAILS>
<DETAILS>
<WEIGHT>85KG</WEIGHT>
<HEIGHT>173CM</HEIGHT>
</DETAILS>
</PERSON>
This Response can be very large, any help would be most appreciated.
You can use any one of the available post processor like "CSS/JQuery Extractor",Boundary Extractor,Regular Expression Extractor or JSR223 etc. All of them will help you to get the required data in a variable/s
But, if you need to just validate the response then you can use "Assertion" to check the response contains the required values or not.
I have used your example and getting the response and only validating the 2nd sequence as shown below:-
I have just copied your second sequence code and used "Add from Clipboard" option to put assertion. You can modify this as per your need.
Assertion consumes a lot of memory and should be avoided in load test.
Hope it help
Add a Regular Expression Extractor as a child of the request which returns the above response
Configure it as follows:
Name of created variable: anything meaningful, i.e. 2ndPerson
Regular Expression: <PERSON>[\s\S]*?<\/PERSON>
Template: $1$
Match No: 2
Add a Response Assertion as a child of the request
Configure it as follows:
Apply to: JMeter Variable -> 2ndPerson_g0
Pattern Matching Rules: Equals
Pattern:
<PERSON>
<NAME>Andrew</NAME>
<AGE>4</AGE>
<REMARKS></REMARKS>
<DETAILS>
<GENDER>MALE</GENDER>
<EYE_COLOR>GREEN</EYE_COLOR>
</DETAILS>
<DETAILS>
<WEIGHT>85KG</WEIGHT>
<HEIGHT>173CM</HEIGHT>
</DETAILS>
</PERSON>
Demo of Regular Expression:
I have a xml document
<?xml version="1.0" encoding="UTF-16"?>
<APIDATA xmlns="api-com">
<ORDER EngineID="1" OrderID="66" OtherInfo="100"><INSTSPECIFIER InstID="27" SeqID="17"/>
</ORDER>
<ORDER EngineID="2" OrderID="67" OtherInfo="200"><INSTSPECIFIER InstID="28" SeqID="18"/>
</ORDER>
<ORDER EngineID="3" OrderID="68"><INSTSPECIFIER InstID="29" SeqID="19"/></ORDER>
</APIDATA>
How do i get the value of OtherInfo attribute using xpath
but when it does not exist i want Null to be returned
If i used the following xpath /APIDATA/ORDER/#OtherInfo i get the output as
100
200
But since for OrderID 68 the OtherInfo is missing i want the output to be
100
200
0
There is a post here which is close to my solution but i somehow cant get it to work
Can I create a value for a missing tag in XPath?
Unfortunately, the approach in the answer to the linked question only work if there is only one value to be returned from a given XML document (see below for a demo on this point). So given the XML sample posted in this question, short answer would be this can't be done using pure XPath 1.0.
If the XPath is used within a programming language, one possible approach would be, to use XPath expression that always return a value, for example /APIDATA/ORDER. Then, for each <ORDER> element returned, usually there are plenty of options to get OtherInfo attribute and provide default value in case the attribute is not found.
Applying the linked post approach to your case would results in the following XPath expression :
substring(concat("0", //ORDER[3]/#OtherInfo), 2 * number(boolean(//ORDER[3]/#OtherInfo)))
The XPath successfully return 0 when applied to the 3rd <ORDER> element which doesn't have attribute OtherInfo, see the demo* : xpathtester, xpatheval
default namespace has been removed in the demo for the sake of simplifying the XPath
Implementation of the same approach in XSLT 1.0, as requested :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:d="api-com">
<xsl:output method="text" indent="yes"/>
<xsl:template match="d:ORDER">
<xsl:value-of select="substring(concat('0', #OtherInfo), 2 * number(boolean(#OtherInfo)))"/>
</xsl:template>
</xsl:stylesheet>
output :
100
200
0
Demo : xpathtester