I have below xml response and I need to assert for 'result' value using karate
<Values version="2.0">
<value name="num1">4</value>
<value name="num2">3</value>
<value name="n1">4</value>
<value name="result">7</value>
<value name="n2">3</value>
<value name="value">7</value>
</Values>
I am able to get data for 'Values' object but not for 'result' element.
* def response =
"""
<Values version="2.0">
<value name="num1">4</value>
<value name="num2">3</value>
<value name="n1">4</value>
<value name="result">7</value>
<value name="n2">3</value>
<value name="value">7</value>
</Values>
"""
* match /Values//value[#name='result'] == '7'
Related
On Python 3.7, I am looking to create a subset of a XML. For example, the larger XML is:
<data>
<student>
<result>
<grade>A</grade>
</result>
<details>
<name>John</name>
<id>100</id>
<age>16</age>
<email>john#mail.com</email>
</details>
</student>
<student>
<result>
<grade>B</grade>
</result>
<details>
<name>Alice</name>
<id>101</id>
<age>17</age>
<email>alice#mail.com</email>
</details>
</student>
<student>
<result>
<grade>F</grade>
</result>
<details>
<name>Bob</name>
<id>102</id>
<age>16</age>
<email>bob#mail.com</email>
</details>
</student>
<student>
<result>
<grade>A</grade>
</result>
<details>
<name>Hannah</name>
<id>103</id>
<age>17</age>
<email>hannah#mail.com</email>
</details>
</student>
</data>
and am looking for a new XML like below, the condition to create a smaller subset depends on a list of ids in this case 101 and 102. All other student blocks will be deleted.
<data>
<student>
<result>
<grade>B</grade>
</result>
<details>
<name>Alice</name>
<id>101</id>
<age>17</age>
<email>alice#mail.com</email>
</details>
</student>
<student>
<result>
<grade>F</grade>
</result>
<details>
<name>Bob</name>
<id>102</id>
<age>16</age>
<email>bob#mail.com</email>
</details>
</student>
</data>
i.e. The output XML will depend on a list of id's, in this case ['101',102']
This is what I tried:
import lxml.etree
#Original Large XML
tree = etree.parse(open('students.xml'))
root = tree.getroot()
results = root.findall('student')
textnumbers = [r.find('details/id').text for r in results]
print(textnumbers)
required_ids = ['101','102']
wanted = tree.xpath("//student/details/[not(#id in required_ids)]")
for node in unwanted:
node.getparent().remove(node)
#New Smaller XML
tree.write(open('student_output.xml', 'wb'))
But I am getting an expected error of "Invalid expression" for
wanted = tree.xpath("//student/details/[not(#id in required_ids)]")
I know it's a read, but i am fairly new to Python, thanks in advance for your help.
I think you can do it like this:
from lxml import etree as ET
required_ids = ['101','102']
for event, element in ET.iterparse('students.xml'):
if element.tag == 'student' and not(element.xpath('.//id/text()')[0] in required_ids):
element.clear()
element.getparent().remove(element)
if element.tag == 'data':
ET.dump(element)
Instead of the dump you would of course want to write to a file, that is use
if element.tag == 'data':
tree = ET.ElementTree(element)
tree.write('student_output.xml')
Your attempt fails as you can't simply use a Python list variable in XPath and in is not an XPath 1.0 operator.
I have the following SQL script (and the XML structure at the bottom):
DECLARE #questions XML
SELECT
t.Col.value('QuestionId[1]', 'int') AS QuestionId,
t.Col.value('Options[1]/string[1]', 'varchar(MAX)') Options
FROM
#questions.nodes ('//Question') t(Col)
WHERE
t.Col.value('QuestionId[1]', 'int') = 5
The SELECT query is returning only first row for Options child string (Blue). How can I get all the values as 4 rows (Blue, Red, White, Black) by changing t.Col.value('Options[1]/string[1]', 'varchar(MAX)') ?
SET #questions = '<?xml version="1.0" encoding="UTF-8"?>
<Questions>
<Question>
<RowType>Question</RowType>
<Required>False</Required>
<QuestionText>select color</QuestionText>
<QuestionType>Radio Buttons</QuestionType>
<QuestionId>5</QuestionId>
<Options>
<string>Blue</string>
<string>Red</string>
<string>White</string>
<string>Black</string>
</Options>
</Question>
<Question>
<RowType>Question</RowType>
<Required>False</Required>
<QuestionText>select color</QuestionText>
<QuestionType>Radio Buttons</QuestionType>
<QuestionId>6</QuestionId>
<Options />
</Question>
</Questions>'
You need apply :
SELECT t.col.value('(./QuestionId)[1]','int') AS QuestionId,
t1.Col.value('(text())[1]', 'varchar(max)') AS Options
FROM #questions.nodes ('/Questions/Question') t(Col) OUTER APPLY
t.Col.nodes('Options/*') t1(Col);
You can go down to reach <string> tag level with Questions/Question/Options/string and then go back one level to get QuestionId:
SELECT
t.col.value('(//QuestionId)[1]','int') AS QuestionId,
t.Col.value('(.)[1]' ,'varchar(50)') AS Options
FROM #questions.nodes ('Questions/Question/Options/string') t(Col)
WHERE t.Col.value('(//QuestionId)[1]', 'int') = 5
Results:
As pointed out in comments the above solution will not work when another <question> tag appears before the one that must be selected.
This is the new input scenario with 4 <question> tags:
<?xml version="1.0" encoding="UTF-8"?>
<Questions>
<Question>
<RowType>Question</RowType>
<Required>False</Required>
<QuestionText>select color</QuestionText>
<QuestionType>Radio Buttons</QuestionType>
<QuestionId>6</QuestionId>
<Options />
</Question>
<Question>
<RowType>Question</RowType>
<Required>False</Required>
<QuestionText>select color</QuestionText>
<QuestionType>Radio Buttons</QuestionType>
<QuestionId>5</QuestionId>
<Options>
<string>Blue</string>
<string>Red</string>
<string>White</string>
<string>Black</string>
</Options>
</Question>
<Question>
<RowType>Question</RowType>
<Required>False</Required>
<QuestionText>select color</QuestionText>
<QuestionType>Radio Buttons</QuestionType>
<QuestionId>7</QuestionId>
<Options />
</Question>
<Question>
<RowType>Question</RowType>
<Required>False</Required>
<QuestionText>select color</QuestionText>
<QuestionType>Radio Buttons</QuestionType>
<QuestionId>8</QuestionId>
<Options>
<string>Blue</string>
<string>Red</string>
<string>White</string>
<string>Black</string>
</Options>
</Question>
</Questions>
Using the following query:
SELECT
t.col.value('((.)/QuestionId)[1]','int') AS QuestionId,
u.Col.value('(.)[1]' ,'varchar(50)') AS Options
FROM #questions.nodes ('Questions/*') t(Col)
OUTER APPLY t.Col.nodes('Options/*') u(Col)
these are the results:
applying the where clause leads to the desired results:
I have a SharePoint page which shows new employees from an employee list. I uses the start date of the employee and displays them for 30 days. We have outsourced 2 departments and managers do not want to see them as new employees since they are from a third party firm. Below is the code I tried but can not get to work. I have moved the 'And' up to include all three filter and I get an error '(soap:ServerException of t.SharePoint.SoapServer.SoapServerException' was thrown. Cannot complete this action. Please try again.0x80004005)'.
I move the 'And' near the 'Neq' and they get ignored. I am trying to keep the 30 days for start date and exclude the two departments.
`<Query>
<OrderBy>
<FieldRef Name="Full_x0020_Name"/>
</OrderBy>
<Where>
<And>
<Geq>
<FieldRef Name="StartDate"/>
<Value Type="DateTime">
<Today OffsetDays="-30"/>
</Value>
</Geq>
<Neq>
<FieldRef Name="Department"/>
<Value Type="Text">G4S Security</Value>
</Neq>
<Neq>
<FieldRef Name="Department"/>
<Value Type="Text">Budd Group</Value>
</Neq>
</And>
</Where>
</Query>`
I found a solution, there can be only two within an And. This is the code I changed below.
'<Where>
<And>
<And>
<Geq>
<FieldRef Name="StartDate"/>
<Value Type="DateTime">
<Today OffsetDays="-30"/>
</Value>
</Geq>
<Neq>
<FieldRef Name="Department"/>
<Value Type="Text">G4S Security</Value>
</Neq>
</And>
<Neq>
<FieldRef Name="Department"/>
<Value Type="Text">Budd Group</Value>
</Neq>
</And>
</Where>'
https://msdn.microsoft.com/en-us/library/office/ms196939(v=office.14).aspx
This element can be nested inside other And and Or elements. The server supports unlimited complicated queries. However, any given And element can have only two conjuncts; that is, only two child elements. If you need to conjoin three or more conditions, you must nest the And elements [...]
<Where>
<And>
<And>
<Geq>
<FieldRef Name="StartDate"/>
<Value Type="DateTime">
<Today OffsetDays="-30"/>
</Value>
</Geq>
<Neq>
<FieldRef Name="Department"/>
<Value Type="Text">G4S Security</Value>
</Neq>
</And>
<Neq>
<FieldRef Name="Department"/>
<Value Type="Text">Budd Group</Value>
</Neq>
</And>
</Where>
There is also the issue of the query method itself.
If you are using the method "query" in the "list" class, then you cannot use the <Query></Query> tags in your CAML. The reason is the method already wraps your query with this tag automatically and adding it breaks the query.
See my code for example:
Private Function GenerateCamlForCurrentUserMessages(list As SPList, isActiveOnly As Boolean) As SPQuery
Dim qResult As SPQuery
Dim sCaml As String = ""
Dim web As SPWeb = SPContext.Current.Web
If isActiveOnly Then
sCaml = "<Where><And><Eq><FieldRef Name='Author' /><Value Type='User'>" & web.CurrentUser.Name.ToString() & "</Value></Eq><Eq><FieldRef Name='IsActive' /><Value Type='Boolean'>1</Value></Eq></And></Where>"
Else
sCaml = "<Where><Eq><FieldRef Name='Author' /><Value Type='User'>" & web.CurrentUser.Name.ToString() & "</Value></Eq></Where>"
End If
qResult = New SPQuery()
'sCaml = sCaml & list.DefaultView.Query
qResult.Query = sCaml
Return qResult
End Function
I have the following XML:
<Matter>
<CriticalDates>
<CriticalDate>
<CriticalDateId>2</CriticalDateId>
<Name>Instruction Date</Name>
<Value_FieldId>9F21</Value_FieldId>
<Confirmed_FieldId />
<Status>In Progress</Status>
<ConfirmStatus />
<CompPercent>0</CompPercent>
<Order>0</Order>
<Value>2014-03-28T06:00:00+11:00</Value>
<Confirmed>false</Confirmed>
</CriticalDate>
<CriticalDate>
<CriticalDateId>-2</CriticalDateId>
<Name>Completion Date</Name>
<Value_FieldId>9F22</Value_FieldId>
<Confirmed_FieldId>9F27</Confirmed_FieldId>
<Status>Complete</Status>
<ConfirmStatus />
<CompPercent>0</CompPercent>
<Order>1</Order>
<Value />
<Confirmed>false</Confirmed>
</CriticalDate>
<CriticalDate>
<CriticalDateId>-3</CriticalDateId>
<Name>Not Proceeding Date</Name>
<Value_FieldId>9F23</Value_FieldId>
<Confirmed_FieldId />
<Status>Not Proceeding</Status>
<ConfirmStatus />
<CompPercent>0</CompPercent>
<Order>2</Order>
<Value />
<Confirmed>false</Confirmed>
</CriticalDate>
</CriticalDates>
</Matter>
To select all the nodes as rows i'm using:
SELECT
MatterId,
MatterXml,
MD.CD.value('(Name)[1]', 'VARCHAR(50)') AS 'Name',
MD.CD.value('(Status)[1]', 'VARCHAR(50)') AS 'Status',
MD.CD.value('(value)[1]', 'DATE') AS 'CriticalDate',
MD.CD.value('(Confirmed)[1]', 'VARCHAR(50)') AS 'Confirmed'
FROM
dbo.Matter m
CROSS APPLY m.MatterXml.nodes('/Matter/CriticalDates/CriticalDate') AS MD(CD)
When i run this i get 3 rows back but all CriticalDates return as NULL even the first one when there is a date in the XML. Please help!
XML is case sensitive. Try is with:
MD.CD.value('(Value)[1]', 'DATE') AS 'CriticalDate',
I have a XMLType object and I want to extract opening times into table.
<workspace>
<title>workspace1</title>
<item>
<day>1</day>
<openingTime>8:00</openingTime>
<closingTime>12:00</closingTime>
</item>
<item>
<day>1</day>
<openingTime>13:00</openingTime>
<closingTime>18:00</closingTime>
</item>
<workspace>
<workspace>
<title>workspace2</title>
<item>
<day>1</day>
<openingTime>9:00</openingTime>
<closingTime>14:00</closingTime>
</item>
<item>
<day>3</day>
<openingTime>12:00</openingTime>
<closingTime>16:00</closingTime>
</item>
<workspace>
I would use something like:
SELECT ExtractValue(Value(p),'workspace/item/day/text()') as day
,ExtractValue(Value(p),'workspace/item/openingTime/text()') as open
,ExtractValue(Value(p),'workspace/item/closingTime/text()') as close
FROM TABLE (XMLSequence(Extract(y,'workspace'))) p
WHERE ExtractValue(Value(p),'/workspace/title/text()') LIKE 'workspace1';
where y is XMLType above. But that won't work, because it will still find more than one item node. I need to extract ALL element values for title workspace2 (values 1, 9:00, 14:00, 3, 12:00, 16:00). It would help if I could extract not only value, but whole part of XMLType. Any ideas?
Thanks, Michal
Your target may be achieved by using XMLTable :
with x as ( -- Just to introduce XML parameter
select
xmltype('
<workspace_list>
<workspace>
<title>workspace1</title>
<item>
<day>1</day>
<openingTime>8:00</openingTime>
<closingTime>12:00</closingTime>
</item>
<item>
<day>1</day>
<openingTime>13:00</openingTime>
<closingTime>18:00</closingTime>
</item>
</workspace>
<workspace>
<title>workspace2</title>
<item>
<day>1</day>
<openingTime>9:00</openingTime>
<closingTime>14:00</closingTime>
</item>
<item>
<day>3</day>
<openingTime>12:00</openingTime>
<closingTime>16:00</closingTime>
</item>
</workspace>
</workspace_list>
') xfield
from dual
)
select
workspace, day, opening_time, closing_time
from
XMLTable(
'
for $i in $doc//workspace[title eq $workspace_filter]
for $j in $i/item
return
<wks_item>
<wks_name>{$i/title/text()}</wks_name>
{$j/*}
</wks_item>
'
passing
(select xfield from x) as "doc",
('workspace1') as "workspace_filter"
columns
workspace varchar2(100) path '//wks_name',
day varchar2(100) path '//day',
opening_time varchar2(100) path '//openingTime',
closing_time varchar2(100) path '//closingTime'
)
SQLFiddle Example
Note that I introduced <workspace_list> top element and added slash for closing <workspace> elements to make XML valid.
With some #ThinkJet tricks your query may look like this
with x as (
select
xmltype('
<workplaces>
<workspace>
<title>workspace1</title>
<item>
<day>1</day>
<openingTime>8:00</openingTime>
<closingTime>12:00</closingTime>
</item>
<item>
<day>1</day>
<openingTime>13:00</openingTime>
<closingTime>18:00</closingTime>
</item>
</workspace>
<workspace>
<title>workspace2</title>
<item>
<day>1</day>
<openingTime>9:00</openingTime>
<closingTime>14:00</closingTime>
</item>
<item>
<day>3</day>
<openingTime>12:00</openingTime>
<closingTime>16:00</closingTime>
</item>
</workspace>
</workplaces>
') xfield
from dual
)
SELECT "day", "openingTime", "closingTime"
FROM xmltable('$doc//workspace[title=$workspace_filter]/item'
passing (select xfield from x) as "doc",
('workspace1') as "workspace_filter"
columns "openingTime" path '//openingTime',
"closingTime" path '//closingTime',
"day" path '//day')