When using XmlParser, it automatically strips out unused namespace definitions. It doesn't appear to detect a namespace being used in a value.
Example Code: The value for attribute "type" is "xs:string" which requires the namespace definition, but XmlParser strips it out
import groovy.xml.XmlUtil
def xml = '''<?xml version="1.0" encoding="UTF-8"?>
<value xmlns:xs="http://xs" type="xs:string">http://localhost:8001/MyService</value>
'''
def doc = new XmlParser().parseText(xml)
println(xml)
println(XmlUtil.serialize(doc))
Output:
****ORIGINAL****
<?xml version="1.0" encoding="UTF-8"?>
<value xmlns:xs="http://xs" type="xs:string">http://localhost:8001/MyService</value>
****XML PARSED/SERIALIZED*****
<?xml version="1.0" encoding="UTF-8"?>
<value type="xs:string">http://localhost:8001/MyService</value>
Is there any way to tell XmlParser to keep this namespace definition??
def parser = new XmlParser()
parser.setFeature("http://xml.org/sax/features/namespaces", false)
parser.setFeature("http://xml.org/sax/features/namespace-prefixes", true)
doc = parser.parseText(xml)
println(XmlUtil.serialize(doc))
Related
I am trying to send an xml request to generate token
the code is
import requests
url = "https://api.demo.convergepay.com/VirtualMerchantDemo/processxml.do"
dataXml = """
<?xml version="1.0" encoding="UTF-8"?>
<txn>
<ssl_merchant_id>mercentId</ssl_merchant_id>
<ssl_user_id>userID</ssl_user_id>
<ssl_pin>sslPin</ssl_pin>
<ssl_transaction_type>ccgettoken</ssl_transaction_type>
<ssl_card_number>0000000000000000</ssl_card_number>
<ssl_exp_date>1222</ssl_exp_date>
<ssl_avs_address>7300</ssl_avs_address>
<ssl_avs_zip>12345</ssl_avs_zip>
<ssl_verify>N</ssl_verify>
</txn>
"""
x = requests.post(url, data=dataXml)
print(x.text)
But i am getting below error
<?xml version="1.0" encoding="UTF-8"?>
<txn><errorCode>6042</errorCode><errorName>Invalid Request Format</errorName><errorMessage>XML request is not well-formed or request is incomplete.</errorMessage></txn>
What is the wrong with my request ?
I have zeep pulling soap data from a SOAP endpoint as:
'''<?xml version="1.0" encoding="utf-8"?>
<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>
<GetLogCategoriesResponse xmlns="http://mynamespace.net/client">
<GetLogCategoriesResult>
<IsSuccessful>true</IsSuccessful>
<Messages />
<Categories>
<LogCategory>
<Category>Client Call</Category>
<CategoryId>805</CategoryId>
<CategoryType>UDF</CategoryType>
</LogCategory>
<LogCategory>
<Category>Client Portal</Category>
<CategoryId>808</CategoryId>
<CategoryType>UDF</CategoryType>
</LogCategory>
<LogCategory>
<Category>Complaint Notes</Category>
<CategoryId>1255</CategoryId>
<CategoryType>UDF</CategoryType>
</LogCategory>
</Categories>
</GetLogCategoriesResult>
</GetLogCategoriesResponse>
</soap:Body>
</soap:Envelope>'''
I've tried pulling the data using Elementtree as below without success:
'''from zeep import Client, Transport
import xml.etree.ElementTree as ET
client = Client('http://sandbox.mynamespace.net/Client.asmx?wsdl')
with client.settings(raw_response=True):
soap_result = client.service.GetLogCategories(userName='user', password='pass')
namespaces = {
'soap': 'http://schemas.xmlsoap.org/soap/envelope/',
'a': 'http://mynamespace.net/client',
}
dom = ET.fromstring(soap_result.content)
print(dom)
names = dom.findall(
'./soap:Body'
'./a:GetLogCategoriesResponse'
'./a:GetLogCategoriesResult'
'./a:Categories'
'./a:LogCategory'
'./a:Category',
namespaces,)
print(names)
for name in names:
print('in For')
print(name.text)'''
I do have a partially working but it only pulls back the first instance of the data group, I need to pull back all groups:
'''from zeep import Client, Transport
from bs4 import BeautifulSoup
client = Client('http://sandbox.mynamespace.net/2.18/Client.asmx?wsdl')
with client.settings(raw_response=True):
soap_result = client.service.GetLogCategories(userName='uname', password='pass')
soup = BeautifulSoup(soap_result.text, 'html.parser')
searchTerms = ['Category','CategoryId','CategoryType']
for st in searchTerms:
print(st+'\t',)
print(soup.find(st.lower()).contents[0])'''
I am looking for any pointers or solutions that will work at this point.
Thanks again
Try this.
from simplified_scrapy.simplified_doc import SimplifiedDoc
html = '''<?xml version="1.0" encoding="utf-8"?>
<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>
<GetLogCategoriesResponse xmlns="http://mynamespace.net/client">
<GetLogCategoriesResult>
<IsSuccessful>true</IsSuccessful>
<Messages />
<Categories>
<LogCategory>
<Category>Client Call</Category>
<CategoryId>805</CategoryId>
<CategoryType>UDF</CategoryType>
</LogCategory>
<LogCategory>
<Category>Client Portal</Category>
<CategoryId>808</CategoryId>
<CategoryType>UDF</CategoryType>
</LogCategory>
<LogCategory>
<Category>Complaint Notes</Category>
<CategoryId>1255</CategoryId>
<CategoryType>UDF</CategoryType>
</LogCategory>
</Categories>
</GetLogCategoriesResult>
</GetLogCategoriesResponse>
</soap:Body>
</soap:Envelope>'''
doc = SimplifiedDoc(html)
Categories = doc.getElementsByTag('LogCategory')
print ([(c.Category.text,c.CategoryId.text,c.CategoryType.text) for c in Categories])
Result:
[('Client Call', '805', 'UDF'), ('Client Portal', '808', 'UDF'), ('Complaint Notes', '1255', 'UDF')]
Here are more examples of SimplifiedDoc here
I am so close to getting my code completed. I would like to get only the values in an array. Right now I am getting XML declaration plus the line.
Here's my code:
import groovy.xml.XmlUtil
def serverList = new
XmlSlurper().parse("/app/jenkins/jobs/firstsos_servers.xml")
def output = []
serverList.Server.find { it.#name == SERVER}.CleanUp.GZIP.File.each{
output.add(XmlUtil.serialize(it))
}
return output
Here is my XML File:
<ServerList>
<Server name="testserver1">
<CleanUp>
<GZIP>
<File KeepDays="30">log1</File>
<File KeepDays="30">log1.2</File>
</GZIP>
</CleanUp>
</Server>
<Server name="testserver2">
<CleanUp>
<GZIP>
<File KeepDays="30">log2</File>
</GZIP>
</CleanUp>
</Server>
<Server name="testserver3">
<CleanUp>
<GZIP>
<File KeepDays="30">log3</File>
</GZIP>
</CleanUp>
</Server>
When I select testserver1 my output should be:
['log1','log1.2']
What I am getting is this:
<?xml version="1.0" encoding="UTF-8"?><File KeepDays="30">log1</File>
<?xml version="1.0" encoding="UTF-8"?><File KeepDays="30">log2</File>
You need not require to use XmlUtil.serialize()
Here is what you need and following inline comments.
//Define which server you need
def SERVER = 'testserver1'
//Pass the
def serverList = new
XmlSlurper().parse("/app/jenkins/jobs/firstsos_servers.xml")
//Get the filtered file names
def output = serverList.Server.findAll{it.#name == SERVER}.'**'.findAll{it.name() == 'File'}*.text()
println output
return output
Output:
You can quickly try online Demo
def output = []
def node = serverList.Server.find {
it.'name' = 'testserver1'
}.CleanUp.GZIP.File.each {
output.add(it)
}
return output
also there is a copy & paste error in your .xml. You have to add </ServerList> at the end.
`
I try to select value of node from soap message (with gt and lt symbols) , but cant do that, i can only get body (root.Body) and other nodes are not visible, it is empty result. What i'm making wrong?
Thanks!
import groovy.util.slurpersupport.Node
import groovy.util.slurpersupport.NodeChild
import groovy.xml.XmlUtil
String source=
'''<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>
<ns0:GetListBy_QualificationResponse xmlns:ns0="urn:WS_CTM_People_ICEVA">
<ns0:getListValues>
<ns0:Person_ID>PPL000000301739</ns0:Person_ID>
<ns0:Submitter>soehler</ns0:Submitter>
<ns0:Profile_Status>Enabled</ns0:Profile_Status>
<ns0:Locale2>en_US</ns0:Locale2>
<ns0:VIP>No</ns0:VIP>
<ns0:Client_Sensitivity>Standard</ns0:Client_Sensitivity>
</ns0:getListValues>
</ns0:GetListBy_QualificationResponse>
</soapenv:Body>
</soapenv:Envelope>'''
def root = new XmlSlurper().parseText(source)
def Submitter =root.Body.GetListBy_QualificationResponse.getListValues.'*'.find { node->
node.name() == 'Submitter'
}
It is because the xml is escaped. In order to be able to retrieve the data property, it is required to unescape the xml string and pass it XmlSlurper.
Here is how it can be done:
String source='''<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>
<ns0:GetListBy_QualificationResponse xmlns:ns0="urn:WS_CTM_People_ICEVA">
<ns0:getListValues>
<ns0:Person_ID>PPL000000301739</ns0:Person_ID>
<ns0:Submitter>soehler</ns0:Submitter>
<ns0:Profile_Status>Enabled</ns0:Profile_Status>
<ns0:Locale2>en_US</ns0:Locale2>
<ns0:VIP>No</ns0:VIP>
<ns0:Client_Sensitivity>Standard</ns0:Client_Sensitivity>
</ns0:getListValues>
</ns0:GetListBy_QualificationResponse>
</soapenv:Body>
</soapenv:Envelope>'''
//map the unescape characters
def map = ['<' : '<', '>' : '>', '"' : '"', ''':'\'', '&':'&']
//Replace them in source string
map.collect {k,v -> source = source.replaceAll(k,v)}
//Now parse it
def root = new XmlSlurper().parseText(source)
//Get the submitter
def submitter = root.'**'.find { it.name() == 'Submitter' }
println submitter
You can quickly try online Demo
This is the response I am getting from soapui.
<PageList>
<offset>0</offset>
<totalLength>2</totalLength>
<result>
<Id>9</Id>
<Name>Cake</Name>
<Price>80</Price>
<quantity>1</quantity>
</result>
<result>
<Id>13</Id>
<Name>Tea</Name>
<Price>10</Price>
<quantity>5</quantity>
</result>
<result>
<Id>15</Id>
<Name>Cofee</Name>
<Price>15</Price>
<quantity>10</quantity>
</result>
</PageList>
How to display the name field separately like
Cake,Tea,Cofee
using groovy script
You can get the list of names in the following way:
def xml = '''<PageList>
<offset>0</offset>
<totalLength>2</totalLength>
<result>
<Id>9</Id>
<Name>Cake</Name>
<Price>80</Price>
<quantity>1</quantity>
</result>
<result>
<Id>13</Id>
<Name>Tea</Name>
<Price>10</Price>
<quantity>5</quantity>
</result>
<result>
<Id>15</Id>
<Name>Cofee</Name>
<Price>15</Price>
<quantity>10</quantity>
</result>
</PageList>'''
def slurped = new XmlSlurper().parseText(xml)
def names = slurped.result.Name.collect { it.text() }
println names