我如何使用 WSO2 ESB XSLT 调解器将 <?xml-multiple?> 元素添加到 DSS 输出的特定位置?

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

我在使用 WSO2 ESB\DSS 时遇到以下问题:这个问题在 YENLO 上的这个漂亮的 post 中得到了很好的解释:https://www.yenlo.com/blog/from-xml-to-json-how-to-handle-an-array-of-one

在我的具体情况下,这与以下事实有关:当我在 ESB 流中使用 DSS 执行查询,然后将得到的XML文档转换成JSON文档,这个JSON的格式会有所不同,具体取决于返回的实体数。当返回多个条目时,例如我通过 DSS 执行查询并获得此结果:

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

现在 DiseaseCoveredByAVaccinationInfoList 元素在这种情况下是单个元素,但它可以是多个(取决于查询输出)。

问题是,在我的 ESB 流程中,我通过以下方式将此 XML 文档转换为 JSON 文档:

<property name="messageType" scope="axis2" type="STRING" value="application/json"/>
<property expression="json-eval($.)" name="JSONPayload" scope="default" type="STRING"/> 

如果在XML文档

中,结果会不同
<DiseaseCoveredByAVaccinationInfoList>...</DiseaseCoveredByAVaccinationInfoList>

是单个或多个元素。

如果是单个元素我会得到这样的东西:

"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"
}

如果在 XML 文档中我有多个

<DiseaseCoveredByAVaccinationInfoList>...</DiseaseCoveredByAVaccinationInfoList>

元素 JSON 转换将创建一个 JSON 数组,类似于:

"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"
},
]

看了前面的YENLO post看来要加这个XML属性:

<?xml-multiple?>

我想我需要这样的东西:

<?xml-multiple?><DiseaseCoveredByAVaccinationInfoList></DiseaseCoveredByAVaccinationInfoList>

所以当它被转换为 JSON 时,这个元素将始终被放入一个 JSON 数组中,而不是作为单个元素。

我还找到了另一个 post:http://www.hkmconsultingllc.com/blog/xml/json-array-control-with-staxon/

参考之前的 YENLO 那个说使用 XSLT 获取 SOAP 响应(DSS 输出)并添加 xml-多个 处理指令。但我真的不知道我到底需要做什么才能实现这种行为,并在我的 ESB 流程中使用 XSLT 来添加这个属性。

在我的 ESB 流程中,我定义了这个 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></ds:vaccination_id>
                    <ds:language_id></ds:language_id>
                    <ds:country_id></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>

我认为我必须在 DSS 调用之后添加一个 XSLT 调解器,但是阅读文档和示例我不明白它究竟是如何工作的以及如何添加它 xml-multiple 元素到我的原始 XML,然后将其转换为 JSON 文档。

我错过了什么?我该如何实现这种行为?

这是一个常见问题,如果它是单个元素,则在从 XML 转换为 JSON 时不会添加数组。

使用 XSLT 中介进行转换总是比让 ESB 转换有效负载更好。

下面我提供了示例 XSLT,尝试并提供您的反馈。

<?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>

我已经在关注 link 后解决了这个问题。在这里,我使用了 XSLT 并为此使用了 "processing-instruction"。还需要启用 synapse.json.to.xml.processing.instruction.enabled=true 属性。 link