{ Community }
  • Academy
  • Docs
  • Developers
  • Resources
    • Community Articles
    • Apigee on GitHub
    • Code Samples
    • Videos & eBooks
    • Accelerator Methodology
  • Support
  • Ask a Question
  • Spaces
    • Product Announcements
    • General
    • Edge/API Management
    • Developer Portal (Drupal-based)
    • Developer Portal (Integrated)
    • API Design
    • APIM on Istio
    • Extensions
    • Business of APIs
    • Academy/Certification
    • Adapter for Envoy
    • Analytics
    • Events
    • Hybrid
    • Integration (AWS, PCF, Etc.)
    • Microgateway
    • Monetization
    • Private Cloud Deployment
    • 日本語コミュニティ
    • Insights
    • IoT Apigee Link
    • BaaS/Usergrid
    • BaaS Transition/Migration
    • Apigee-127
    • New Customers
    • Topics
    • Questions
    • Articles
    • Ideas
    • Leaderboard
    • Badges
  • Log in
  • Sign up

Get answers, ideas, and support from the Apigee Community

  • Home /
  • Edge/API Management /
avatar image
1
Question by Adauto Martins · Jul 14, 2016 at 08:48 PM · 2.9k Views soap to restxsltxsl transformxsl

Is there a way to pass a XSLT resource as a parameter of a XSLT on XSLT Policy Transformation?

Hello,

Is there a way to pass a XSLT resource as a parameter on XSLT Policy Transformation?

My need is to apply a dynamic template to remove some undesired elements from an response.

Public Webservice got as an example: http://wsf.cdyne.com/WeatherWS/Weather.asmx?wsdl

Follow my assets for someone that may want to help me, the goal is to take control of which element is an array of elements.

By default applying only a transformation XML -> JSON policy i got:

"GetWeatherInformationResponse": {
  "GetWeatherInformationResult": {
   "WeatherDescription": [
        {
          "WeatherID": 1,
          "Description": "Thunder Storms",
          "PictureURL": "http://wsf.cdyne.com/WeatherWS/Images/thunderstorms.gif"
        }, ...

But i expected this:

"WeatherDescription": [
  {
    "WeatherID": 1,
    "Description": "Thunder Storms",
    "PictureURL": "http://wsf.cdyne.com/WeatherWS/Images/thunderstorms.gif"
  }, ...

This is a simple scenario, but i have other more complex scenarios where we can have 3 or more lists of elements.

PS: We already made this with an API Gateway that makes use of Saxon XSLT processor, so i know that this is possible, but i'm in doubt on how to pass a reference to an XSLT Resource as a parameter.

XSLT policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<XSL async="false" continueOnError="false" enabled="true" name="SoapResponseRewrite">
    <DisplayName>SoapResponseRewrite</DisplayName>
    <Properties/>
    <Source>response</Source>
    <ResourceURL>xsl://SoapResponseRewrite.xsl</ResourceURL>
    <Parameters ignoreUnresolvedVariables="false">
        <Parameter name="soap.response.template" value="apiproxy/resources/xsl/ListWeathersResponse.xsl"/>
    </Parameters>
</XSL

Main XSLT SoapResponseRewrite.xsl (Rewrite the entire SOAP Response according to an template passed as parameter)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" version="1.0">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
  <xsl:param name="soap.response.template"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="*">
    <xsl:param name="source"/>
    <xsl:variable name="current-lookup-elem" select="current()"/>
    <xsl:for-each select="$source/*[local-name() = local-name($current-lookup-elem)]">
      <xsl:choose>
        <xsl:when test="$current-lookup-elem[processing-instruction('xml-multiple')]">
          <xsl:if test="./*">
            <xsl:processing-instruction name="xml-multiple">
              <xsl:value-of select="local-name(./*)"/>
            </xsl:processing-instruction>
          </xsl:if>
          <xsl:apply-templates select="$current-lookup-elem/*">
            <xsl:with-param name="source" select="current()"/>
          </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise>
          <xsl:element name="{local-name($current-lookup-elem)}">
            <xsl:apply-templates select="$current-lookup-elem/*">
              <xsl:with-param name="source" select="current()"/>
            </xsl:apply-templates>
            <xsl:copy-of select="text()"/>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="/*">
    <xsl:apply-templates select="document($soap.response.template)/*/soap:Envelope/soap:Body/*/node()">
      <xsl:with-param name="source" select="/*/soap:Body/*"/>
    </xsl:apply-templates>
  </xsl:template>
  <xsl:template match="/">
    <xsl:element name="response">
      <xsl:apply-templates select="node()"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

XSLT Template ListWeathersResponse.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" version="1.0">
  <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>
      <GetWeatherInformationResponse xmlns="http://ws.cdyne.com/WeatherWS/">
        <GetWeatherInformationResult>
          <?xml-multiple?>
          <WeatherDescription>
            <WeatherID/>
            <Description/>
            <PictureURL/>
          </WeatherDescription>
        </GetWeatherInformationResult>
      </GetWeatherInformationResponse>
    </soap:Body>
  </soap:Envelope>
</xsl:stylesheet>
Comment
Add comment
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Close

2 Answers

  • Sort: 
avatar image
0

Answer by Dino   · Jul 15, 2016 at 05:00 AM

Hi,

I'm not sure I understand all of what you are asking. Especially the part about "specifying a resource as a parameter".... I'm not following that.

But, specific to your scenario of converting from XML to JSON. I think your situaiton is that the input XML looks like this:

  <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>
      <GetWeatherInformationResponse xmlns="http://ws.cdyne.com/WeatherWS/">
        <GetWeatherInformationResult>
          <WeatherDescription>
            <WeatherID>...</WeatherID>
            <Description>...</Description>
            <PictureURL>...</PictureURL>
          </WeatherDescription>
        </GetWeatherInformationResult>
      </GetWeatherInformationResponse>
    </soap:Body>
  </soap:Envelope>

...and you want to convert it to

"WeatherDescription": [
  {
    "WeatherID": 1,
    "Description": "Thunder Storms",
    "PictureURL": "http://wsf.cdyne.com/WeatherWS/Images/thunderstorms.gif"
  }, ...

In today's XMLToJSON policy, we cannot do that. Instead you get JSON versions of all the SOAP and Response elements. In the near future, you will be able to use a new option in the XMLToJSON policy, like so:

<XMLToJSON ... > 
  ... 
  <Options> 
    ... 
    <!-- this is new --> 
  <StripLevels>3</StripLevels>
  </Options> 
</XMLToJSON> 

... in order to get what you seek. This option tells the converter to strip levels of the XML document, and simply discard them, when converting to JSON. In the case of a SOAP message, StripLevels=3 would strip the Envelope, the Body, and the Response elements. If you also wanted to strip the Result element, you would need StripLevels=4.

Levels in the hierarchy are stripped only if they have a single child element.

There is also a related new option, TreatAsArray. It looks like this:

<XMLToJSON ...>
   ...
  <Options>
    <TreatAsArray>
      <Path>Envelope/Body/GetWeatherInformationResponse/GetWeatherInformationResult/WeatherDescription</Path>
    </TreatAsArray>
  </Options>
</XMLToJSON>


This will tell the XMLToJSON to treat the element identified by the path, as an array. By default, XMLToJSON infers the presence of an array by the number of elements present. IF there are two or more child elements named WeatherDescription, then XMLToJSON infers an array. But in some cases, the document has just one element, but you would still like it to be converted to an array. This option allows you to stipulate that.

The associated tickets for these new features are APIRT-578 and APIRT-1144, respectively.

I'll get back to you on when you will be able to use these new features.

Comment
Add comment Show 2 · Link
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Adauto Martins · Jul 15, 2016 at 07:21 PM 0
Link

Hi Dino,

thanks for your response, it's good to hear that in near future we'll get more control with XMLToJSON and i guess that this could help me on some scenarios.

Going back to my question what i expect is to rewrite the SOAP Response according to a template and to to that i just need to realize how to pass a reference to another XSLT as a parameter on a XSLT.

This diagram shows my need:

+--------+           +--------+      +--------+
|        |           |        |      |        |
|  SOAP  +---------> |REWRITE +----> | OUTPUT |
|RESPONSE|           |  XSLT  |      |  XML   |
|        |           |        |      |        |
+--------+           +---+----+      +--------+
                         ^
                         |Passed as a parameter
                         |
                     +---+----+
                     |        |
                     |TEMPLATE|
                     |  XSLT  |
                     |        |
                     +--------+

I've done it with Vordel Api Gateway, there i've Saxon as a XSLT processor and we just refers the XSLT location as a parameter and it works as expected.

Do you know how to refer a XSLT Resource? I've tried these ways:

ListWeathersResponse.xsl

XSL://ListWeathersResponse.xsl

apiproxy/resources/xsl/ListWeathersResponse.xsl

Best regards

avatar image Dino ♦♦ Adauto Martins   · Jul 15, 2016 at 07:41 PM 0
Link

yes, you need a full URL in that location. Example:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- this is a parameter set in the XSL Policy config -->
  <xsl:param name="loc1" select="''"/>

  <!-- the following retrieves the remote document into a variable
       available to the stylesheet -->
  <xsl:variable name="xdoc1" select="document($loc1)"/>

  <!-- now, do what you want with the template document... -->

</xsl:stylesheet>

The policy configuration would look like this:

<XSL name='XSL-1'>
  <Source>myDocument</Source>
  <OutputVariable>response.content</OutputVariable>
  <ResourceURL>xsl://my-transform.xsl</ResourceURL>
  <Parameters ignoreUnresolvedVariables='false'>
    <Parameter name='loc1'>https://example.org/my-template.xsl</Parameter>
  </Parameters>
</XSL>

You can host that XSL locally in Edge... in a nodejs server, or otherwise.

avatar image
0

Answer by Satya Srinivas Dubba · Mar 30, 2017 at 03:14 AM

Hi Dino,

I tried the above solution to reference an xml file using parameter but no luck. Here are is code(Apigee version 4.16.01.02):

Here i am trying to work with parameter and not with Source value as an example

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<XSL async="false" continueOnError="false" enabled="true" name="XSL-Transform-1">
    <DisplayName>XSL Transform-1</DisplayName>
    <Properties/>
    <Source>calloutResponse</Source>
    <OutputVariable>response.content</OutputVariable>
    <Parameters ignoreUnresolvedVariables="false">
        
        <Parameter name="one">https://api.com/v1/proxyone</Parameter>
        <Parameter name="two">https://api.com/v1/proxytwo</Parameter>
    </Parameters>
    <ResourceURL>xsl://books.xslt</ResourceURL>
</XSL>


books.xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html"/>
    <xsl:param name="one" select="''"/>
    <!-- <xsl:param name="two" select="''"/> -->
    <xsl:template match="/">
        <html>
            <MyFiles>
                <xsl:apply-templates select="document('$one')/node()"></xsl:apply-templates>
            </MyFiles>
        </html>
    </xsl:template>
</xsl:stylesheet>

proxyone output:

<entry-list>
  <entry>
    <day>mon</day>
    <amount>34</amount>
  </entry>
</entry-list>


output :
<html>
   <MyFiles></MyFiles>
</html>

expected :
<html>
	<MyFiles>mon34</MyFiles>
</html>


Please advice.
Comment
Add comment · Link
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Follow this Question

Answers Answers and Comments

40 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Trying out XSL. OutputVariable not being populated after execution of the policy 1 Answer

Including SOAP Headers into SOAP Envelope using XSL Script 1 Answer

How can i transform XML document with XSL Transform policy? -1 Answers

Error with XSL Transform - XSLT-Transform.xsl failed with reason: "Process instruction target name cannot be xml at line 2(possibly around char 18)" 1 Answer

SOAP to REST API - XML to jSON transformation issue 2 Answers

  • Products
    • Edge - APIs
    • Insights - Big Data
    • Plans
  • Developers
    • Overview
    • Documentation
  • Resources
    • Overview
    • Blog
    • Apigee Institute
    • Academy
    • Documentation
  • Company
    • Overview
    • Press
    • Customers
    • Partners
    • Team
    • Events
    • Careers
    • Contact Us
  • Support
    • Support Overview
    • Documentation
    • Status
    • Edge Support Portal
    • Privacy Policy
    • Terms & Conditions
© 2021 Apigee Corp. All rights reserved. - Apigee Community Terms of Use - Powered by AnswerHub
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Create an article
  • Post an idea
  • Spaces
  • Product Announcements
  • General
  • Edge/API Management
  • Developer Portal (Drupal-based)
  • Developer Portal (Integrated)
  • API Design
  • APIM on Istio
  • Extensions
  • Business of APIs
  • Academy/Certification
  • Adapter for Envoy
  • Analytics
  • Events
  • Hybrid
  • Integration (AWS, PCF, Etc.)
  • Microgateway
  • Monetization
  • Private Cloud Deployment
  • 日本語コミュニティ
  • Insights
  • IoT Apigee Link
  • BaaS/Usergrid
  • BaaS Transition/Migration
  • Apigee-127
  • New Customers
  • Explore
  • Topics
  • Questions
  • Articles
  • Ideas
  • Badges