1
votes

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&amp;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&amp;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&amp;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&amp;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?

2

2 Answers

1
votes

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>
0
votes

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