Map from XML using rest-assured - java

I'm trying to set up an integration test using rest-assured. In one of my test cases I have to validate some properties of an XML file with rest-assured's XmlPath which seems to use Groovy's GPath.
I have an XML document with the following structure (the ids are unique):
<rootelement>
<someelement id="1234" type="a">
<property key="hello" value="world" />
<property key="name" value="a name" />
<property key="status" value="new" />
<child target="645823" type="a" />
<child target="7482" type="b" />
<child target="8942" type="c">
<property key="pro" value="yes" />
</child>
</someelement>
<someelement>
...
</someelement>
<rootelement>
Ideally, given a someelement id, I want to get a map of it's properties, i.e. assuming the given someelement id is 1234 I'd like to get a map that looks like the following:
{"hello": "world", "name": "a name", "status": "new"}. How would I do this? I know that there's a getMap method in XmlPath, but I couldn't figure out which expression I'd have to use.
If it's not possible to get the properties as a map, I would be content with getting a list of the keys and a list for the values. Again, I don't know which expression I have to use. I tried something like that:
xmlPath.getList("**.find {it.#id = '1234'}.property.#key", String.class)
However, it doesn't find anything.

You can do this with Groovy (assuming xml is a String containing your xml)
def map = new XmlParser().parseText( xml )
.someelement
.find { it.#id == '1234' }
.property
.collectEntries { [ it.#key, it.#value ] }
assert map == [ hello:'world', name:'a name', status:'new' ]
Never used rest-assured, so I can't be much help in that direction though :-(

Related

is there a way to get self-or-descendant in an xpath expression without using the [not(self::sub-element)] proprety

I'm trying to deal with xml files to get the NodeList in a special xpath expression but also the Nodes in its sub-elements(all childrens) in all levels. we can have several depths in all provided xml files.
I used an xpath like :
.//level1/*[preceding-sibling::TITLE[text()='INFORMATION']]/descendant-or-self::*
issue with that is I also get redundancy at the end with just the Node of some sub-elements(descendants).
I tried to use the [not(self::sub-element)] property like :
.//level1/*[preceding-sibling::TITLE[text()='INFORMATION']]/descendant-or-self::*[[not(self::sub-element2 or self::sub-element2)]
but the issue is that i dont have the list of all this redundancy sub-element to include them in the property, so I'm looking for another way to delete this in the returned NodeList.
Taking for exemple the following element :
<level1>
<TITLE>INFORMATION</TITLE>
<level11>
<level12 NAME="A" TYPE="Z">A01</level12>: contains <VEAM>NORD and SUD</VEAM> Vendor (V) <SBR>21</SBR> for terms.</level11>
<level11>
<level12 NAME="A" TYPE="Z">A02</level12>: No provided.</level11>
<Empty></Empty>
</level1>
I got the following NodeList :
<level11> <level12 NAME="A" TYPE="Z">A01</level12>: contains <VEAM>NORD and SUD</VEAM> Vendor (V) <SBR>21</SBR> for terms.</level11>
<level12 NAME="A" TYPE="Z">A01</level12>
<VEAM>NORD and SUD</VEAM>
<SBR>21</SBR>
<level11> <level12 NAME="A" TYPE="Z">A02</level12>: No provided.</level11>
<level12 NAME="A" TYPE="Z">A02</level12>
<Empty/>
But i need to got only nodes with all the nodes children and its text without getting cildren nodes alones. there is also other exemples with greater depth.
<level11> <level12 NAME="A" TYPE="Z">A01</level12>: contains <VEAM>NORD and SUD</VEAM> Vendor (V)<SBR>21</SBR>for terms.</level11>
<level11> <level12 NAME="A" TYPE="Z">A02</level12>: No provided.</level11>
<Empty/>
MINDER : without using the [not(self::sub-element)] property
This XPath gets nodes as requested and per the provided sample
//level1[./TITLE[text()='INFORMATION']]/*[not(name()='TITLE')]
Result:
<level11>
<level12 NAME="A" TYPE="Z">A01</level12>: contains <VEAM>NORD and SUD</VEAM> Vendor (V) <SBR>21</SBR> for terms.</level11>
<level11>
<level12 NAME="A" TYPE="Z">A02</level12>: No provided.</level11>
<Empty/>

How can I use a WSO2 ESB XSLT mediator to add an <?xml-multiple?> element into a specific place of a DSS output?

I have the following problem with WSO2 ESB\DSS: the problem is well explained in this beautifoul post on YENLO: https://www.yenlo.com/blog/from-xml-to-json-how-to-handle-an-array-of-one
In my specific case it is related to the fact that when I perform a query using DSS inside an ESB flow, and then convert the obtained XML document into a JSON document this JSON will be formatted differently, depending on the number of entities returned. When multiple entries are returned, for example I perform a query via DSS and I obtain this result:
<VaccinationDetails xmlns="http://ws.wso2.org/dataservice">
<VaccinationDetails>
<vaccination_id>1</vaccination_id>
<vaccination_name_en>Antrax</vaccination_name_en>
<vaccination_name>Antrax</vaccination_name>
<description xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<vaccination_goal xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<vaccination_coverage xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<image_link>https://firebasestorage.googleapis.com/v0/b/myproject.appspot.com/o/img%2Ficons%2Flivestock%2Fvacccination.png?alt=media&token=19b15f9a-4706-4037-a928-c8151c823077</image_link>
<DiseaseCoveredByAVaccinationInfo>
<DiseaseCoveredByAVaccinationInfoList>
<disease_id>6</disease_id>
<disease_name_en>Antrax</disease_name_en>
<disease_name>Antrax</disease_name>
<description>Anthrax is an infection caused by the bacterium Bacillus anthracis. It can occur in four forms: skin, lungs, intestinal, and injection. Symptoms begin between one day and two months after the infection is contracted. The skin form presents with a small blister with surrounding swelling that often turns into a painless ulcer with a black center. The inhalation form presents with fever, chest pain, and shortness of breath. The intestinal form presents with diarrhea which may contain blood, abdominal pains, and nausea and vomiting. The injection form presents with fever and an abscess at the site of drug injection.</description>
<image_link>https://firebasestorage.googleapis.com/v0/b/myproject/o/assets%2FLivestock%2FDisease%2Fanthrax.png?alt=media&token=3a7245ca-f003-4823-b39f-cfaef539e98c</image_link>
</DiseaseCoveredByAVaccinationInfoList>
</DiseaseCoveredByAVaccinationInfo>
<DiseaseCoveredByAVaccinationInfo>
<DiseaseCoveredByAVaccinationInfoList>
<livestock_species_id>1</livestock_species_id>
<parent_livestock_species_id xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<livestock_species_name_en>Cow</livestock_species_name_en>
<livestock_species_name>Cow</livestock_species_name>
<description>Cattle, cows are the most common type of large domesticated ungulates. They are a prominent modern member of the subfamily Bovinae, are the most widespread species of the genus Bos, and are most commonly classified collectively as Bos taurus. Cattle are commonly raised as livestock for meat (beef and veal), as dairy animals for milk and other dairy products, and as draft animals (oxen or bullocks that pull carts, plows and other implements). Other products include leather and dung for manure or fuel. In some regions, such as parts of India, cattle have significant religious meaning.</description>
<image_link>https://firebasestorage.googleapis.com/v0/b/myproject/o/img%2Ficons%2Flivestock%2Fcow.png?alt=media&token=c21866df-448a-4a72-9da2-d55d87f8b31c</image_link>
<ls_vaccination_id>1</ls_vaccination_id>
</DiseaseCoveredByAVaccinationInfoList>
</DiseaseCoveredByAVaccinationInfo>
<DiseaseCoveredByAVaccinationInfo>
<DiseaseCoveredByAVaccinationInfoList>
<livestock_species_id>1</livestock_species_id>
<parent_livestock_species_id xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<livestock_species_name_en>Cow</livestock_species_name_en>
<livestock_species_name>Cow</livestock_species_name>
<description>Cattle, cows are the most common type of large domesticated ungulates. They are a prominent modern member of the subfamily Bovinae, are the most widespread species of the genus Bos, and are most commonly classified collectively as Bos taurus. Cattle are commonly raised as livestock for meat (beef and veal), as dairy animals for milk and other dairy products, and as draft animals (oxen or bullocks that pull carts, plows and other implements). Other products include leather and dung for manure or fuel. In some regions, such as parts of India, cattle have significant religious meaning.</description>
<image_link>https://firebasestorage.googleapis.com/v0/b/myproject/o/img%2Ficons%2Flivestock%2Fcow.png?alt=media&token=c21866df-448a-4a72-9da2-d55d87f8b31c</image_link>
<ls_vaccination_id>1</ls_vaccination_id>
</DiseaseCoveredByAVaccinationInfoList>
</DiseaseCoveredByAVaccinationInfo>
<LivestockVaccinationTimeFrameInfo/>
</VaccinationDetails>
</VaccinationDetails>
Now the DiseaseCoveredByAVaccinationInfoList element in this case is a single element but it can be multiple (it depends by the query output).
The problem is that when in my ESB flow I convert this XML document into a JSON document by:
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<property expression="json-eval($.)" name="JSONPayload" scope="default" type="STRING"/>
the result will be different if in the XML document
<DiseaseCoveredByAVaccinationInfoList>...</DiseaseCoveredByAVaccinationInfoList>
is a single or multiple element.
If it is a single element I will obtain something like this:
"DiseaseCoveredByAVaccinationInfoList": {
"disease_id": 6,
"disease_name_en": "Antrax",
"disease_name": "Antrax",
"description": "Anthrax is an infection caused by the bacterium Bacillus anthracis. It can occur in four forms: skin, lungs, intestinal, and injection. Symptoms begin between one day and two months after the infection is contracted. The skin form presents with a small blister with surrounding swelling that often turns into a painless ulcer with a black center. The inhalation form presents with fever, chest pain, and shortness of breath. The intestinal form presents with diarrhea which may contain blood, abdominal pains, and nausea and vomiting. The injection form presents with fever and an abscess at the site of drug injection.",
"image_link": "https://firebasestorage.googleapis.com/v0/b/my-project.appspot.com/o/assets%2FLivestock%2FDisease%2Fanthrax.png?alt=media&token=3a7245ca-f003-4823-b39f-cfaef539e98c"
}
If in the XML document I have multiple
<DiseaseCoveredByAVaccinationInfoList>...</DiseaseCoveredByAVaccinationInfoList>
elements the JSON converstion will creatre a JSON array, something like:
"DiseaseCoveredByAVaccinationInfoList":
[
{
"disease_id": 6,
"disease_name_en": "YYY",
"disease_name": "YYY",
"description": "DESCRIPTION",
"image_link": "ULR"
},
{
"disease_id": 7,
"disease_name_en": "XXX",
"disease_name": "XXX",
"description": "DESCRIPTION",
"image_link": "ULR"
},
]
Reading the previous YENLO post it seems that I have to add this XML attribute:
<?xml-multiple?>
I think that I need to have something like this:
<?xml-multiple?><DiseaseCoveredByAVaccinationInfoList></DiseaseCoveredByAVaccinationInfoList>
So when it is converted into JSON this element will be always put into a JSON array and not as a single element.
I also found this other post: http://www.hkmconsultingllc.com/blog/xml/json-array-control-with-staxon/
reffering to the previous YENLO one that says to use XSLT to take a SOAP response (the DSS output) and add the xml-multiple processing instructions. But I really don't know what exactly I have to do to implement this behavior and use XSLT into my ESB flow to add this attribute.
In my ESB flow I have defined this API:
<resource methods="GET" protocol="http" uri-template="/country/{country_id}/vaccination/{vaccination_id}?lang={lang_id}">
<inSequence>
<log level="full"/>
<property expression="get-property('uri.var.country_id')" name="country_id" scope="default" type="STRING"/>
<property expression="get-property('uri.var.vaccination_id')" name="vaccination_id" scope="default" type="STRING"/>
<property expression="get-property('uri.var.lang_id')" name="lang_id" scope="default" type="STRING"/>
<log level="custom">
<property expression="$ctx:country_id" name="country_id"/>
<property expression="$ctx:vaccination_id" name="vaccination_id"/>
<property expression="$ctx:lang_id" name="lang_id"/>
</log>
<property name="messageType" scope="axis2" type="STRING" value="application/xml"/>
<payloadFactory media-type="xml">
<format>
<ds:GetVaccinationDetails xmlns:ds="http://ws.wso2.org/dataservice">
<ds:vaccination_id>$1</ds:vaccination_id>
<ds:language_id>$2</ds:language_id>
<ds:country_id>$3</ds:country_id>
</ds:GetVaccinationDetails>
</format>
<args>
<arg evaluator="xml" expression="$ctx:vaccination_id"/>
<arg evaluator="xml" expression="$ctx:country_id"/>
<arg evaluator="xml" expression="$ctx:lang_id"/>
</args>
</payloadFactory>
<header name="Action" scope="default" value="urn:GetVaccinationDetails"/>
<call>
<endpoint key="livestock_Endpoint"/>
</call>
<log level="full"/>
<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<property expression="json-eval($.)" name="JSONPayload" scope="default" type="STRING"/>
<property name="RESPONSE" scope="default" type="STRING" value="true"/>
<header action="remove" name="To" scope="default"/>
<send/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
I think that I have to add an XSLT mediator after the DSS call but reading the documentation and example I can't understand how exactly works and how to add this xml-multiple element to my original XML before transforming it into a JSON document.
What am I missing? How can I implement this behavior?
It's a common issue where if it's a single element then the array will not be added while converting from XML to JSON.
It's always better to use an XSLT mediator to do the conversion rather than allowing ESB to convert the payload.
Below i have provided the Sample XSLT,Try and provide your feedback.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0" xmlns:as="http://schema.ttmw.com/Axon" xmlns:env="http://schema.concierge.com/Envelope" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="text" indent="yes" media-type="application/json" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">{
"VaccinationDetails":{
"DiseaseCoveredByAVaccinationInfo":[
<xsl:for-each select="//DiseaseCoveredByAVaccinationInfoList">
{
"DiseaseCoveredByAVaccinationInfoList":{
"disease_id":"<xsl:value-of select="//disease_id"/>"
}
}
<xsl:if test="position()!=last()">,</xsl:if>
</xsl:for-each>
]
}
}
</xsl:template>
</xsl:stylesheet>
I have solved this issue on following link. Here I have used XSLT and used "processing-instruction" for this. Also need to enabled synapse.json.to.xml.processing.instruction.enabled=true property as well. link

Building different XML files with same JAXB objects

Let's say I want to use JAXB to generate two XML files -- one containing a list of items, the other containing detailed definitions of those items. For instance, something like this:
Garage.xml:
<garage>
<car ref="1" />
<car ref="2" />
</garage>
Cars.xml:
<cars>
<car id="1" color="blue" model="Impreza" />
<car id="2" color="plaid" model="Taurus" />
</cars>
Is there anything clever I can do to define a single JAXB Car.java object that will allow me to use the same object for both files? If not, is there an accepted best practice anyone would recommend beyond the obvious solution of creating two separate Car classes? (One with the ref attribute, the other with the id, color, and model attributes.)

Fetch value of a node's attribute in XML

I have an XML document, a snippet of which is below:
<item name="entryDataItem" type="dataView" caption="__entry_data_item" id="208" formItem="selectbox">
<properties>
<property name="caption" value="Task Type"/>
<property name="name" value="task_type"/>
</properties>
</item>
<item name="entryDataItem" type="dataView" caption="__entry_data_item" id="211" formItem="text">
<properties>
<property name="caption" value="Time Spent (Min)"/>
<property name="name" value="time_spent_min"/>
</properties>
</item>
etc.
There are other "properties" as well. The value of "task_type" as well as all other properties are stored in database. When I iterate through the document, all the properties are fetched and a document is prepared with "caption" and "value" from the XML. The problem is , all the "properties" are printed. But I want contents of the document to be based on the "task_type"; say when the task_type value is TESTING", then only task_type "ESTIMATION" would be printed and nothing else.
I understand I have to put a check just before where the document is being prepared.
My question is: How do I put the condition when I only have "task_type" in the XML and not a value(eg."TESTING") directly within the XML document?
My code is a simple JAVA code.
Any help as to how this can be achived is much appreciated.
In my opinion, XPath is the bee's knees when it comes to going after specific items in a XML document. This article might be of some use if it's something you want to persue.

Java replace in XML-file

I have created my own XML-file on my Android phone, which looks similar to this
<?xml version="1.0" encoding="utf-8" ?>
<backlogs>
<issue id="1">
<backlog id="0" name="Linux" swid="100" />
<backlog id="0" name="Project Management" swid="101" />
</issue>
<issue id="2">
<backlog id="0" name="Tests" swid="110" />
<backlog id="0" name="Online test" swid="111" />
<backlog id="0" name="Test build" swid="112" />
<backlog id="0" name="Update" swid="113" />
</issue>
</backlogs>
I have then converted it into a String to replace inside the string using Regular Expression, but I have a problem with the Regular Expression. The Regular Expression I just created looks like this
([\n\r]*)<(.*)issue(.*)1(.*)([\n\r]*)(.*)([\n\r]*)(.*)([\n\r]*)(.*)<(.*)/(.*)issue(.*)
I need to replace the specific issue-tag (located with the specific ID) with another issue-tag in another String
The Regular Expression works fine for the tag with ID 1, but not with ID 2 as there is another amount of tags, but is there any way to get around the use of amount?
I hope you understand my question
I finally found a solution for my question, which is
([\n\r]*)<(.*)issue(.*)1[\S\s]*?<(.*)/(.*)issue(.*)
Do not use regex. Please. Use XML parser.
Do you know what is the highest voted SO answer
Use a SAX (or StAX) parser and writer at the same time.
As you read one event, detect whether to write the same event type to the writer without modification, or to do some modifications in the state you are currently in - like swapping an element name or attribute value. This will handle an unlimited amount of elements at the expense of CPU usage; in general it will be pretty light-weight.

Categories

Resources