Type conversion error while using Linq to XML - c#-4.0

I have created a sample XML. And trying to Read by using LINQ
here is the code:
XElement root = XElement.Load("C:\\............\\TestData.xml");
IEnumerable<Xelement> address = from tt in root.Elements("Test")
select tt;
I am getting compile time error at select statement :
Cannot implicitly convert type
'System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>'
to 'System.Collections.Generic.IEnumerable<EvalTest.Xelement>'.
An explicit conversion exists (are you missing a cast?)
XML:
<?xml version="1.0" encoding="utf-8" ?>
<TestData>
<Test Method="1">
<ID>1</ID>
<Submitter> Ritvij</Submitter>
<Date>11/5/2013 2:51:57 PM </Date>
</Test>
<Test Method="2">
<ID>1</ID>
<Submitter> Ritvij</Submitter>
<Date>11/5/2013 2:51:57 PM </Date>
</Test>
</TestData>

root.Elements returns an IEnumerable<XElement> (with a capital "E"), but you're trying to assign it to IEnumerable<Xelement> (lower case "e").
Either modify your code to use XElement or use var:
IEnumerable<XElement> address = from tt in root.Elements("Test") select tt;
var address = from tt in root.Elements("Test") select tt;

Related

Python lxml.etree: how to add 'xml:lang="en-US"' as a namespace

I am trying to create a xml whose first element is:
<speak version="1.0"
xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en-US">
</speak>
I am able to add the first attributes with...
from lxml.etree import Element, SubElement, QName, tostring
root = Element('speak', version="1.0",
xmlns="http://www.w3.org/2001/10/synthesis")
...but not the namespace xml:lang="en-US". Based on several tuto/question like this and this I tried many solutions but none worked.
For example, I tried this :
class XMLNamespaces:
xml = 'http://www.w3.org/2001/10/synthesis'
root.attrib[QName(XMLNamespaces.xml, 'lang')] = "en-US"
But the ouput is
<speak xmlns:ns0="http://www.w3.org/2001/10/synthesis" version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" ns0:lang="en-US">
How can I create the xml:lang="en-US" of my first xml element?
The special xml: prefix is associated with the http://www.w3.org/XML/1998/namespace URI.
The following code adds xml:lang="en-US" to the root element:
root.attrib[QName("http://www.w3.org/XML/1998/namespace", "lang")] = "en-US"

Would like to output xml file as in body from python using lxml

Would like to output the following at the head of xml
I can find lots on parsing and validating, but not so much on creation/output
I can find some documentation on QName but how do I output
`
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://service-spi.web.cern.ch/service-spi/app /releases/GDML/schema/gdml.xsd">`
Use QName to create the attribute (noNamespaceSchemaLocation) that is bound to the http://www.w3.org/2001/XMLSchema-instance namespace.
from lxml.etree import QName, Element, tostring
qname = QName("http://www.w3.org/2001/XMLSchema-instance", "noNamespaceSchemaLocation")
attr_dict = {qname: "http://service-spi.web.cern.ch/service-spi/app /releases/GDML/schema/gdml.xsd"}
gdml = Element("gdml", attr_dict)
print(tostring(gdml, encoding="UTF-8", standalone=False).decode())
Output:
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<gdml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://service-spi.web.cern.ch/service-spi/app /releases/GDML/schema/gdml.xsd"/>
The namespace declaration (xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance") is created automatically.
Thanks - I already did it another way
NS = 'http://www.w3.org/2001/XMLSchema-instance'
location_attribute = '{%s}noNameSpaceSchemaLocation' % NS
gdml = ET.Element('gdml',attrib={location_attribute: 'http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd'})
print(gdml.tag)

Simple XSLT transformation into ABAP Object

I'm again stuck with a transformation from XML into ABAP. This time, I want to put the XML data directly into an ABAP Object.
My XML looks like this:
<qualityStatus>
<address>0</address>
<bounceRisk>0</bounceRisk>
<checked>1</checked>
<domain>1</domain>
<domainScores>
<domainScore>
<domain>gmx.de</domain>
<score>0.8333333134651184</score>
</domainScore>
<domainScore>
<domain>ggs.de</domain>
<score>0.6666666269302368</score>
</domainScore>
<domainScore>
<domain>xyz.de</domain>
<score>0.6666666269302368</score>
</domainScore>
</domainScores>
<extSyntax>1</extSyntax>
<mailserver>1</mailserver>
<mailserverDiagnosis>1</mailserverDiagnosis>
<probability>1</probability>
<syntax>1</syntax>
</qualityStatus>
Edit: I changed back to a XSLT transformation, shortened to one attribute it looks like this:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sap="http://www.sap.com/sapxsl" version="1.0">
<xsl:output encoding="iso-8859-1" indent="yes" method="xml" version="1.0"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/qualityStatus">
<asx:abap version="1.0" xmlns:asx="http://www.sap.com/abapxml">
<asx:values>
<ROOT href="#o26"/>
</asx:values>
<asx:heap xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:abap="http://www.sap.com/abapxml/types/built-in"
xmlns:cls="http://www.sap.com/abapxml/classes/global"
xmlns:dic="http://www.sap.com/abapxml/types/dictionary">
<cls:ZCL_ADDRESS_QUALITY id="o26" >
<local.ZCL_ADDRESS_QUALITY>
<W_ADDRESS>
<xsl:value-of select="address"/>
</W_ADDRESS>
<!--More attributes here-->
</local.ZCL_ADDRESS_QUALITY>
</cls:ZCL_ADDRESS_QUALITY>
</asx:heap>
</asx:abap>
</xsl:template>
My object attributes are all public right now, because I thought this could be the problem. However, setter and getter do exist. Yes, my class does implement the interface if_serializable_object.
DATA:
w_address TYPE char1,
w_bouncerisk TYPE char1,
w_checked TYPE char1,
w_decoded TYPE stringval,
w_domain TYPE char1,
w_domainscores TYPE z_domainscore_t, "Table type for name + score
w_extsyntax TYPE char1,
w_mailserver TYPE char1,
w_mailserverdiagnosis TYPE char1,
w_probability TYPE char1,
w_syntax TYPE char1,
w_syntaxwarnings TYPE z_syntaxwarnings_t. "Table of syntaxwarnings
Finally, I call my transformation with an instance of my class:
CALL TRANSFORMATION zst_addressquality
SOURCE XML lw_xml
RESULT result = lo_addressquality.
Now, when debugging through the transformation code, it successfully notices all fields of the given lw_xml and appears to write them into the object lo_addressquality. But the object attributes stay empty afterwards.
When testing the serialization, I can access result which contains my object, but result-w_address (and all others) are empty.
While testing, I created a structure with completely identical names and types. With it, it worked as intended.
What am I missing? Is there anything else I have to watch out for when working with transformation into ABAP Objects?
_Edit: After changing to the XSLT, I can get until W_ADDRESS before my code throws an CX_XSLT_ABAP_CALL_ERROR. So, I'm still not able to access the object'S attributes properly. :|_
Objects can be serialized/deserialized only with an XSL transformation. It's not possible to do it with a simple transformation, dixit ABAP documentation:
ST programs are restricted to the transformation of elementary and structured ABAP data, along with internal tables. The transformation of reference variables and referenced objects is not currently supported.
The XSL transformation must convert the XML into ASXML, which in short corresponds to a structure like this:
<?xml ...?>
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
...
</asx:values>
<asx:heap>
...
</asx:heap>
</asx:abap>
The easiest way to understand what the ASXML should look like is to serialize your object reference using the identity transformation (it's an XSL transformation), and then adapt your transformation to produce the same kind of asXML:
CALL TRANSFORMATION id SOURCE anyRootName = yourObjectReference RESULT XML asXMLutf8xstring.
Example:
REPORT.
CLASS serialization_demo DEFINITION.
PUBLIC SECTION.
INTERFACES if_serializable_object.
DATA attribute TYPE i.
ENDCLASS.
START-OF-SELECTION.
DATA obj_ref TYPE REF TO serialization_demo.
DATA xstring TYPE xstring.
CREATE OBJECT obj_ref.
obj_ref->attribute = 5.
CALL TRANSFORMATION id " serialize
SOURCE root = obj_ref
RESULT XML xstring.
CLEAR obj_ref.
CALL TRANSFORMATION id " deserialize
SOURCE XML xstring
RESULT root = obj_ref.
ASXML (in the xstring variable):
<?xml version="1.0" encoding="utf-8"?>
<asx:abap version="1.0" xmlns:asx="http://www.sap.com/abapxml">
<asx:values>
<ROOT href="#o3"/>
</asx:values>
<asx:heap xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:abap="http://www.sap.com/abapxml/types/built-in" xmlns:cls="http://www.sap.com/abapxml/classes/global" xmlns:dic="http://www.sap.com/abapxml/types/dictionary">
<prg:SERIALIZATION_DEMO id="o3" xmlns:prg="http://www.sap.com/abapxml/classes/program/ZZSRO_TEST16I">
<local.SERIALIZATION_DEMO>
<ATTRIBUTE>5</ATTRIBUTE>
</local.SERIALIZATION_DEMO>
</prg:SERIALIZATION_DEMO>
</asx:heap>
</asx:abap>

SOAPUI Property Transfer xpath

I am trying to transfer the response from one test case to another in SOAPUI. So that i can search by country and retrieve the currency code to use then search by currency code. However i am not sure i am getting my xpath correct.
SOAP WSDL used: http://www.webservicex.net/CurrencyConvertor.asmx?WSDL
This is a practice for a service which is shortly due to be delivered.
Initial test case post
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:web="http://www.webserviceX.NET">
<soap:Header/>
<soap:Body>
<web:GetCurrencyByCountry>
<!--Optional:-->
<web:CountryName>Belgium</web:CountryName>
</web:GetCurrencyByCountry>
</soap:Body>
</soap:Envelope>
Response
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetCurrencyByCountryResponse xmlns="http://www.webserviceX.NET">
<GetCurrencyByCountryResult><![CDATA[<NewDataSet>
<Table>
<Name>Belgium</Name>
<CountryCode>be</CountryCode>
<Currency>Franc</Currency>
<CurrencyCode>BEF</CurrencyCode>
</Table>
<Table>
<Name>Belgium</Name>
<CountryCode>be</CountryCode>
<Currency>Franc</Currency>
<CurrencyCode>BEF</CurrencyCode>
</Table>
</NewDataSet>]]></GetCurrencyByCountryResult>
</GetCurrencyByCountryResponse>
</soap:Body>
</soap:Envelope>
I am then using the property transfer test step, Firstly setting the drop downs as follows:
Source: Get Currency by Country; Property: Response Path Language: xpath
Then declared the xpath as follows:
declare namespace sam= 'http://www.webserviceX.NET';//GetCurrencyByCountryResult/table[2]/CurrencyCode
Each time i run the test i get a Null response. I have attempted using a wild card however i still cannot pick up the value.
Here is the groovy script which does exactly what you are looking for:
Added comments appropriately before each statement for better understanding.
Currently using the fixed xml response. But you may replace it to make it dynamic.
Since your xml has cdata and cdata has xml again. So, this needs to be done in two phases, first time cdata and then xpath to get the actual value that is needed.
import com.eviware.soapui.support.XmlHolder
def xml = '''<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body>
<GetCurrencyByCountryResponse xmlns="http://www.webserviceX.NET">
<GetCurrencyByCountryResult><![CDATA[<NewDataSet>
<Table>
<Name>Belgium</Name>
<CountryCode>be</CountryCode>
<Currency>Franc</Currency>
<CurrencyCode>BEF</CurrencyCode>
</Table>
<Table>
<Name>Belgium</Name>
<CountryCode>be</CountryCode>
<Currency>Franc</Currency>
<CurrencyCode>BEF</CurrencyCode>
</Table>
</NewDataSet>]]></GetCurrencyByCountryResult>
</GetCurrencyByCountryResponse>
</soap:Body>
</soap:Envelope>'''
//If you want this script to handle dynamic response
// remove above xml and uncomment below line and replace your previous step name in
// place of STEP_NAME
//def xml = context.expand( '${STEP_NAME#Response}' )
//Please replace the actual response in place of xml
def holder = new XmlHolder(xml)
//Get the CDATA part
def countryCodeResult = holder.getNodeValue('//*:GetCurrencyByCountryResult')
//log the content of CDATA
log.info countryCodeResult
//Again convert cdata string as xml holder
def cdataHolder = new XmlHolder(countryCodeResult)
//Get the actual xpath
def currencyCode = cdataHolder.getNodeValue("//Table[2]/CurrencyCode")
log.info currencyCode
//now you may store this currency code as suite level propery so that
//you can use it in next test case as ${#TestSuite#CURRENCY_CODE}
context.testCase.testSuite.setPropertyValue('CURRENCY_CODE', currencyCode)
As you see in the above comment, the script is storing currency code into a test suite level property. That allows you to use the currency code in different test case or step using property expansion, say ${#TestSuite#CURRENCY_CODE}
You need to store the CDATA Content in to a property and then use that property value in groovy script and access CDATA internal xml, I am referring in the below example <![CDATA[<isle>test</isle>]]> .
eg:
<test>
<elementa>
<![CDATA[<isle>test</isle>]]>
</elementa>
</test>
In your current scenario Soapui only understand XPATH up to "//GetCurrencyByCountryResult" , after that whatever path have provided goes under CDATA .
SOAPUI working with CDATA is separate mechanism.
Please look into this; it has lot of information on CDATA with SOAPUI and its definitely solve your issue
https://www.soapui.org/functional-testing/working-with-cdata.html

Filtering xml file on attributes on similarly named elements using linq to xml

I suppose the solution is simple, but I haven't found an answer despite searching the internet extensively. Please help! The problem is : my xml query is not returning the required result if the required attribute is not inside the first element of similarly named elements. For example, this code is not returning anything:
XElement xelement = XElement.Load("~/Employees.xml"));
var homePhone = from phoneno in xelement.Elements("Employee")
where (string)phoneno.Element("Phone").Attribute("Type") == "Work"
select phoneno;
foreach (XElement xEle in homePhone)
TextBox1.Text= xEle + "/n";
However, if I substitute "Work" with "Home", I get the required result. In fact, I should get exactly the same result with "Work". Can someone please explain how to do this?
The xml template is:
<?xml version="1.0" encoding="utf-8" ?>
<Employees>
<Employee>
<EmpId>1</EmpId>
<Name>Sam</Name>
<Sex>Male</Sex>
<Phone Type="Home">423-555-0124</Phone>
<Phone Type="Work">424-555-0545</Phone>
<Address>
<Street>7A Cox Street</Street>
<City>Acampo</City>
<State>CA</State>
<Zip>95220</Zip>
<Country>USA</Country>
</Address>
</Employee>
<Employee>
<EmpId>2</EmpId>
<Name>Lucy</Name>
<Sex>Female</Sex>
<Phone Type="Other">143-555-0763</Phone>
<Phone Type="Work">434-555-0567</Phone>
<Address>
<Street>Jess Bay</Street>
<City>Alta</City>
<State>CA</State>
<Zip>95701</Zip>
<Country>USA</Country>
</Address>
</Employee>
<Employee>
<EmpId>3</EmpId>
<Name>Kate</Name>
<Sex>Female</Sex>
<Phone Type="Home">166-555-0231</Phone>
<Phone Type="Other">233-555-0442</Phone>
<Address>
<Street>23 Boxen Street</Street>
<City>Milford</City>
<State>CA</State>
<Zip>96121</Zip>
<Country>USA</Country>
</Address>
</Employee>
<Employee>
<EmpId>4</EmpId>
<Name>Chris</Name>
<Sex>Male</Sex>
<Phone Type="Work">564-555-0122</Phone>
<Phone Type="Other">442-555-0154</Phone>
<Address>
<Street>124 Kutbay</Street>
<City>Montara</City>
<State>CA</State>
<Zip>94037</Zip>
<Country>USA</Country>
</Address>
</Employee>
</Employees>
XElement.Element("name") will return the FIRST element of the given name when there is more than one. You really want this:
var employeesWithHomePhone = from e in xdocument.Root.Elements("Employee")
where e.Elements("Phone").Any( p => (string)p.Attribute("Type") == "Home")
select e;
And just change "Home" to "Work" to get the ones with a Work number
This line:
where (string)phoneno.Element("Phone")
is indeed using only the first Phone element since you requested only one. You need to use the Elements method, but you can iterate all phones instead of employees:
from phone in xelement.Descendants("Phone")
where (string)phone.Attribute("Type") == "Work"
select phone;
If you want to make sure this phone belongs to an employee add this condition in the where:
phone.Parent.Name == "Employee"

Resources