XPATH in Nokogiri - ruby-on-rails

I have an XML + SOAP with Nokogiri and I want only the body to appear but I have some errors.
The XML SOAP is:
data = <SOAP:Envelope xmlns:SOAP=\"http://schemas.xmlsoap.org/soap/envelope/\">
<SOAP:Header><header xmlns=\"xmlapi_1.0\">
<requestID>aquiroga:0001</requestID>
<requestTime>Mar 14, 2018 11:33:27 PM</requestTime>
<responseTime>Mar 14, 2018 11:33:27 PM</responseTime>
</header>
</SOAP:Header>
<SOAP:Body>
<findResponse xmlns=\"xmlapi_1.0\">
<result>
<service.SapEgrQosQueueStatsLogRecord>
<queueId>2</queueId>
<droppedInProfOctets>0</droppedInProfOctets>
<droppedOutProfOctets>0</droppedOutProfOctets>
<timeCaptured>1521072355115</timeCaptured>
<periodicTime>0</periodicTime>
<displayedName>eNodo_B-HOTELPUERTOPALMERA-S1UX2</displayedName>
<monitoredObjectSiteName>SMT-TRS-AN01</monitoredObjectSiteName>
</service.SapEgrQosQueueStatsLogRecord>
<service.SapEgrQosQueueStatsLogRecord>
<queueId>1</queueId>
<droppedInProfOctets>0</droppedInProfOctets>
<droppedOutProfOctets>70450698</droppedOutProfOctets>
<timeCaptured>1521072355051</timeCaptured>
<periodicTime>199796</periodicTime>
<displayedName>to_eNODOB Tarapoto Sur-S1-MME</displayedName>
<monitoredObjectSiteName>SMT-TRS-AN01</monitoredObjectSiteName>
</service.SapEgrQosQueueStatsLogRecord>
</result>
</findResponse>
</SOAP:Body>
</SOAP:Envelope>
The code I am using is:
data_stats = data.xpath('/SOAP:Envelope/SOAP:Body')
The result is:
=> #<Nokogiri::XML::Element:0x3fee745c1c94 name="Body" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1e60 prefix="SOAP" href="http://schemas.xmlsoap.org/soap/envelope/"> children=[#<Nokogiri::XML::Element:0x3fee745c16b8 name="findResponse" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Element:0x3fee745c126c name="result" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Element:0x3fee745c0e84 name="service.SapEgrQosQueueStatsLogRecord" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Element:0x3fee745c0a60 name="queueId" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Text:0x3fee745c0664 "1">]>, #<Nokogiri::XML::Element:0x3fee745c0498 name="droppedInProfOctets" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Text:0x3fee745c00b0 "0">]>, #<Nokogiri::XML::Element:0x3fee745adec4 name="droppedOutProfOctets" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Text:0x3fee745adaa0 "0">]>, #<Nokogiri::XML::Element:0x3fee745ad8d4 name="timeCaptured" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Text:0x3fee745ad4c4 "1521158716279">]>, #<Nokogiri::XML::Element:0x3fee745ad2f8 name="periodicTime" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Text:0x3fee745aceac "284992">]>, #<Nokogiri::XML::Element:0x3fee745acce0 name="displayedName" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Text:0x3fee745ac8bc "RTN VillaSalvador3 Tdp-VillaBaja">]>, #<Nokogiri::XML::Element:0x3fee745ac6dc name="monitoredObjectSiteName" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0"> children=[#<Nokogiri::XML::Text:0x3fee745ac2b8 "LIM-SPO-AN02">]>]>, #<Nokogiri::XML::Element:0x3fee74593f9c name="service.SapEgrQosQueueStatsLogRecord" namespace=#<Nokogiri::XML::Namespace:0x3fee745c1668 href="xmlapi_1.0">
I want it to appear only from service.SapEgrQosQueueStatsLogRecord. The code I use is the following:
data_stats = qos7705egressdiscard_summary.xpath('/SOAP:Envelope/SOAP:Body/findResponse/result/service.SapEgrQosQueueStatsLogRecord')
But the result is an empty arrangement => []

You can use data.remove_namespaces! ( see http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Document:remove_namespaces! ). Then this query works:
data.xpath('/Envelope/Body/findResponse/result/service.SapEgrQosQueueStatsLogRecord')

Related

remove outertag from spyne wsdl input and output

I am using spyne for creating my webservice.
#urls.py
urlpatterns = [
url(
r'^InventoryService.wsdl', DjangoView.as_view(
name="InventoryService",
services=[InventoryService],
tns='InventoryService',
in_protocol=Soap12(validator='lxml'),
out_protocol=Soap12(),
cache_wsdl=False
)
),
]
views.py
#views.py
spyne.const.RESULT_SUFFIX =''
spyne.const.REQUEST_SUFFIX ='Request'
class GetFilterValuesRequest(ComplexModel):
id = String(min_occurs=1, max_length=64, nillable=False)
password = String(min_occurs=0, max_length=64, nillable=False)
productId = String(min_occurs=1, max_length=64, nillable=False)
class FilterValues(ComplexModel):
productId = String(min_occurs=1, max_length=64, default='55', nillable=False)
class InventoryService(Service):
#rpc(GetFilterValuesRequest, _returns=FilterValues, )
def getFilterValues(ctx, GetFilterValuesRequest):
return FilterValues(productId='33', )
I want to remove the outer "GetFilterValuesRequest" from the input and update "getFilterValues" in output response to "FilterValues".
I will add my current input and output also my expected input and output.
Following is the current input and output when I call this request through soapui
#Current input
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:inv="InventoryService" xmlns:core="core.views">
<soap:Header/>
<soap:Body>
<inv:getFilterValuesRequest>
<!--Optional:-->
<inv:GetFilterValuesRequest>
<core:id>?</core:id>
<!--Optional:-->
<core:password>?</core:password>
<core:productId>?</core:productId>
</inv:GetFilterValuesRequest>
</inv:getFilterValuesRequest>
</soap:Body>
</soap:Envelope>
#Current output
<soap12env:Envelope xmlns:soap12env="http://www.w3.org/2003/05/soap-envelope" xmlns:tns="InventoryService" xmlns:s0="core.views">
<soap12env:Body>
<tns:getFilterValuesResponse>
<tns:getFilterValues>
<s0:productId>33</s0:productId>
</tns:getFilterValues>
</tns:getFilterValuesResponse>
</soap12env:Body>
</soap12env:Envelope>
Following is my expected output in soap ui.
#Expected input
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:inv="InventoryService" xmlns:core="core.views">
<soap:Header/>
<soap:Body>
<inv:GetFilterValuesRequest>
<core:id>?</core:id>
<!--Optional:-->
<core:password>?</core:password>
<core:productId>?</core:productId>
</inv:GetFilterValuesRequest>
</soap:Body>
</soap:Envelope>
#Expected output
<soap12env:Envelope xmlns:soap12env="http://www.w3.org/2003/05/soap-envelope" xmlns:tns="InventoryService" xmlns:s0="core.views">
<soap12env:Body>
<tns:GetFilterValuesResponse>
<tns:FilterValues>
<s0:productId>33</s0:productId>
</tns:FilterValues>
</tns:GetFilterValuesResponse>
</soap12env:Body>
</soap12env:Envelope>
use
#rpc(GetFilterValuesRequest, _returns=FilterValues,_body_style = "bare" )

XQuery: How to get a specific value out of a tag?

Suppose we have this xml:
<question>
<test id="1">
<tag k="a" v="1"/>
<tag k="a" v="2"/>
<tag k="b" v="3"/>
</test>
<test id="2">
<tag k="a" v="1"/>
<tag k="a" v="4"/>
<tag k="b" v="5"/>
</test>
<test id="3">
<tag k="a" v="2"/>
<tag k="a" v="6"/>
<tag k="b" v="7"/>
</test>
</question>
I would like to return all values v of test, if k = "a" AND v = "1", like this:
v="3"
v="5"
So far my approach:
for $i in //test
where ($i/tag[#k = 'a' and #v = '1'])
return $i/tag/#v
But this is not correct because thats the return:
v="1"
v="2"
v="3"
v="1"
v="4"
v="5"
Thank you for your help :)
You are probably looking for something like
for $i in //test
where ($i/tag[#k = 'a'][#v="1"])
return $i/tag[#k="b"]/#v
Your criteria for selection was not exactly clear, but this returns what you expected:
for $i in //test
where $i/tag[#k = 'a' and #v = '1']
return $i/tag[not(#k = 'a' or #v = '1')]/#v
You could simplify and do this in a single XPath expression:
//test/tag[#k = 'a' and #v = '1']/tag[not(#k = 'a' or #v = '1')]/#v

How to parse XML with non-pair tags using Nokogiri

All examples seen on the internet are XML files with structure like:
<open_tag>data that I want</close_tag>
but my XML file is different:
<Report xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="_x0034_00_x0020_-_x0020_Nomenklatury" xsi:schemaLocation="_x0034_00_x0020_-_x0020_Nomenklatury http://pcisrs/ReportServer?%2FTARIC%20Reporty%20Ciselnikov%2F400%20-%20Nomenklatury&rs%3AFormat=XML&rc%3ASchema=True" Name="400 - Nomenklatury">
<table1>
<Detail_Collection>
<Detail goods_nomenclature_item_id="0100000000" product_line="80" date_start="31.12.1971" quantity_indents="0" declarable_import="0" declarable_export="0" goods_nomenclature_item_description="ŽIVÉ ZVIERATÁ"/>
<Detail goods_nomenclature_item_id="0101000000" product_line="80" date_start="01.01.1972" quantity_indents="1" statistical_unit="NAR" declarable_import="0" declarable_export="0" goods_nomenclature_item_description="Živé kone, somáre, muly a mulice" parent_goods_nomenclature_item_id="0100000000" parent_product_line="80"/>
.....ETC....
</Detail_Collection>
</table1>
</Report>
If I understand the tutorials, this should work:
subor = Nokogiri::XML(File.open('vendor/financnasprava/nomenklatury/recent.xml'))
dataset = subor.xpath('//Detail')
but didn't.
You can work with this data like in the example below. I removed the source path as I have not this data locally.
If i'm right and you are trying to the access Detail attributes:
require 'nokogiri'
require 'open-uri'
data_xml = <<-EOT
<Report xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="400 - Nomenklatury">
<table1>
<Detail_Collection>
<Detail goods_nomenclature_item_id="0100000000" product_line="80" date_start="31.12.1971" quantity_indents="0" declarable_import="0" declarable_export="0" goods_nomenclature_item_description="ŽIVÉ ZVIERATÁ"/>
<Detail goods_nomenclature_item_id="0101000000" product_line="80" date_start="01.01.1972" quantity_indents="1" statistical_unit="NAR" declarable_import="0" declarable_export="0" goods_nomenclature_item_description="Živé kone, somáre, muly a mulice" parent_goods_nomenclature_item_id="0100000000" parent_product_line="80"/>
</Detail_Collection>
</table1>
</Report>
EOT
subor = Nokogiri::XML(data_xml)
dataset = subor.xpath('//Detail_Collection/*')
details = dataset.map do |row|
{
product_line: row.attributes['product_line'].value,
goods_nomenclature_item_id: row.attributes['goods_nomenclature_item_id'].value
}
end
puts details
#=> {:product_line=>"80", :goods_nomenclature_item_id=>"0100000000"}
#=> {:product_line=>"80", :goods_nomenclature_item_id=>"0101000000"}

unable to parse xml with groovy

I can't read the xml and parse the items because it's always returning an error of
groovy.lang.MissingPropertyException: No such property: method for
class: Script1
def xmlText = new XmlSlurper().parse('myxml.xml')
def skipped = 0
def failed = 0
def total = 0
def passed = 0
xmlText.suite.test.class.test-method.each{
if(it['#is-config'] == "true"){
}
else{
if(it['#status']=="PASS"){
passed = passed + 1
total = total + 1
}
if(it['#status']=="FAIL"){
failed = failed + 1
total = total + 1
}
if(it['#status']=="SKIP"){
skipped = skipped + 1
total = total + 1
}
}
}
the xml file is
<?xml version="1.0" encoding="UTF-8"?>
<testng-results skipped="3" failed="0" total="3" passed="0">
<reporter-output>
</reporter-output>
<suite name="DinamicTestSuite" duration-ms="24" started-at="2018-07-16T13:26:48Z" finished-at="2018-07-16T13:26:48Z">
<groups>
</groups>
<test name="Device:null" duration-ms="24" started-at="2018-07-16T13:26:48Z" finished-at="2018-07-16T13:26:48Z">
<class name="com.automation.venues.stg.VenuesSuite">
<test-method status="PASS" signature="login(org.testng.ITestContext, java.lang.String)[pri:0, instance:com.automation.venues.stg.VenuesSuite#71454b9d]" name="login" is-config="true" duration-ms="11" started-at="2018-07-16T16:26:48Z" finished-at="2018-07-16T16:26:48Z">
</test-method>
<test-method status="PASS" signature="beforeMethod(java.lang.reflect.Method)[pri:0, instance:com.automation.venues.stg.VenuesSuite#71454b9d]" duration-ms="0" started-at="2018-07-16T16:26:48Z" finished-at="2018-07-16T16:26:48Z">
</test-method>
</class> <!-- com.automation.venues.stg.VenuesSuite -->
</test> <!-- Device:null -->
</suite> <!-- DinamicTestSuite -->
</testng-results>
how can I parse the list ?
You need to put quotes round the attribute with a - in it
xmlText.suite.test.class.'test-method'.each{
An alternative to your each approach would be:
def xmlText = new XmlSlurper().parse('myxml.xml')
def totals = xmlText.suite.test.class.'test-method'.countBy { it.#status.text() }
def skipped = totals.SKIP
def failed = totals.FAIL
def passed = totals.PASS
def total = totals.values().sum()

Parsing with Ruby Mechanize

Im trying to parse a website using the Mechanize Gem. So far this is what I have:
page = agent.get("http://www.greatgiftsformen.com/price-range-under-c-131_142.html?page=all")
page.parser.xpath('//tr[(((count(preceding-sibling::*) + 1) = 2) and parent::*)]//*[contains(concat( " ", #class, " " ), concat( " ", "productListing-data", " " ))]')[5]
and I get the elements for this product back:
=> #<Nokogiri::XML::Element:0x81c175ec name="td" attributes=[#<Nokogiri::XML::Attr:0x81c17d58 name="valign" value="top">, #<Nokogiri::XML::Attr:0x81c17eac name="align" value="center">, #<Nokogiri::XML::Attr:0x81c17ec0 name="class" value="productListing-data">] children=[#<Nokogiri::XML::Element:0x805fa174 name="a" attributes=[#<Nokogiri::XML::Attr:0x81c13794 name="href" value="http://www.greatgiftsformen.com/gas-pump-retro-liquor-dispenser-p-249.html?osCsid=05f5dbb816874ece6db883c2c48d7ae1">] children=[#<Nokogiri::XML::Element:0x8068e270 name="img" attributes=[#<Nokogiri::XML::Attr:0x81c115ac name="src" value="product_thumb.php?img=images/prod/liquordisp-gas.jpg&w=160&h=160">, #<Nokogiri::XML::Attr:0x81c115c0 name="width" value="160">, #<Nokogiri::XML::Attr:0x81c115d4 name="height" value="160">, #<Nokogiri::XML::Attr:0x81c11714 name="border" value="0">, #<Nokogiri::XML::Attr:0x81c11728 name="alt" value="Gas Pump Retro Liquor Dispenser">, #<Nokogiri::XML::Attr:0x81c11750 name="title" value="Gas Pump Retro Liquor Dispenser">, #<Nokogiri::XML::Attr:0x81c11764 name="class" value="fotgal">]>]>]>
however when I try to get the href, I get back nil:
url = item.attributes['href']
=> nil
Needed to add the child nodes:
url = item.children[0].attributes['href'].to_s

Resources