escaping xml with CDATA

Hi guys,

I want to call an external logging service to log the response from a target endpoint. Therefore the payload of this logging service includes the xml from the endpoint. However, I'm not able to escape the returned XML with CDATA - it simply disappears from the final message. Am I missing something here?

Thanks.

My AssignMessage policy (note the CDATA):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="true" enabled="true" name="AM-LogMessage">
    <DisplayName>AM-LogMessage</DisplayName>
    <Properties/>
    <AssignTo createNew="true" transport="http" type="request">logoutput</AssignTo>
    <Set>
        <Payload contentType="application/xml">
            <log>
                <messageId>{messageid}</messageId>
                <environmentName>{environment.name}</environmentName>
                <request>
                    <verb>{log.request.verb}</verb>
                    <scheme>{log.client.scheme}</scheme>
                    <host>{log.request.header.host}</host>
                    <uri>{log.request.uri}</uri>
                    <url>{log.client.scheme}://{log.request.header.host}/{log.request.uri}</url>
                    <receivedStartTimestamp>{converted.client.received.start.timestamp}</receivedStartTimestamp>
                    <receivedEndTimestamp>{converted.client.received.end.timestamp}</receivedEndTimestamp>
                    <content><![CDATA[{log.request.content}]]></content>
                </request>
                <response>
                    <content>{log.response.content}</content>
                </response>
                <target>
                    <sentStartTimestamp>{converted.target.sent.start.timestamp}</sentStartTimestamp>
                    <sentEndTimestamp>{converted.target.sent.end.timestamp}</sentEndTimestamp>
                    <receivedStartTimestamp>{converted.target.received.start.timestamp}</receivedStartTimestamp>
                    <receivedEndTimestamp>{converted.target.received.end.timestamp}</receivedEndTimestamp>
                    <requestContent>{log.target.request.content}</requestContent>
                    <responseContent><![CDATA[{log.target.response.content}]]></responseContent>
                </target>
            </log>
        </Payload>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</AssignMessage>

Result of trace (edited for clarity - no CDATA):

<log>
    <messageId>rrt-04f86cf07fc1285a3-b-de-18184-27376007-1</messageId>
	...
        <content>
            <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
            <ns2:IDSReservationRequest>
		...            
	    </ns2:IDSReservationRequest>
        </content>
    </request>
    <response>
        <content>
            <RESPONSE>
		...                
            </RESPONSE>
        </content>
    </response>
	...
</log> 
Solved Solved
1 4 2,085
1 ACCEPTED SOLUTION

The CDATA section is being "consumed" by the assignmessage policy, which itself is XML. So that CDATA will not propagate to the final message.

What's your goal?

What do you want the output message to be?

I see two options. 1: Escape the XML. 2: "hide" the cdata.

Option 1.

Apigee includes an escapeXML11 function. If you use this for your AssignMessage:

<AssignMessage name='AM-Response1'>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <Set>
        <Payload contentType="application/xml">
            <log>
                <messageId>{messageid}</messageId>
                <test>
                    <responseContent>{escapeXML11(fakerequest.content)}</responseContent>
                </test>
            </log>
        </Payload>
    </Set>
    <ReasonPhrase>OK</ReasonPhrase>
    <StatusCode>200</StatusCode>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <AssignTo>response</AssignTo>
</AssignMessage>

You will get something like this on output:

9349-screenshot-20191023-114148.png

Option 2

If you use something like this:

<AssignMessage name='AM-Response2'>
  <AssignVariable>
    <Name>cdata_open</Name>
    <Value>& lt;![CDATA[</Value>
  </AssignVariable>
  <AssignVariable>
    <Name>cdata_close</Name>
    <Value>]]& gt;</Value>
  </AssignVariable>


  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <Set>
        <Payload contentType="application/xml">
            <log>
                <messageId>{messageid}</messageId>
                <test>
                    <responseContent>{cdata_open}{fakerequest.content}{cdata_close}</responseContent>
                </test>
            </log>
        </Payload>
    </Set>
    <ReasonPhrase>OK</ReasonPhrase>
    <StatusCode>200</StatusCode>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <AssignTo>response</AssignTo>
</AssignMessage>

You will get an actual cdata section in the output.

<log>
  <messageId>rrt-8957324297109092480-b-gwo1-8179-38716113-1</messageId>
  <test><responseContent><![CDATA[
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:IDSReservationRequest>
                ...
</ns2:IDSReservationRequest>


]]></responseContent>
  </test>
</log>

View solution in original post

4 REPLIES 4

The CDATA section is being "consumed" by the assignmessage policy, which itself is XML. So that CDATA will not propagate to the final message.

What's your goal?

What do you want the output message to be?

I see two options. 1: Escape the XML. 2: "hide" the cdata.

Option 1.

Apigee includes an escapeXML11 function. If you use this for your AssignMessage:

<AssignMessage name='AM-Response1'>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <Set>
        <Payload contentType="application/xml">
            <log>
                <messageId>{messageid}</messageId>
                <test>
                    <responseContent>{escapeXML11(fakerequest.content)}</responseContent>
                </test>
            </log>
        </Payload>
    </Set>
    <ReasonPhrase>OK</ReasonPhrase>
    <StatusCode>200</StatusCode>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <AssignTo>response</AssignTo>
</AssignMessage>

You will get something like this on output:

9349-screenshot-20191023-114148.png

Option 2

If you use something like this:

<AssignMessage name='AM-Response2'>
  <AssignVariable>
    <Name>cdata_open</Name>
    <Value>& lt;![CDATA[</Value>
  </AssignVariable>
  <AssignVariable>
    <Name>cdata_close</Name>
    <Value>]]& gt;</Value>
  </AssignVariable>


  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <Set>
        <Payload contentType="application/xml">
            <log>
                <messageId>{messageid}</messageId>
                <test>
                    <responseContent>{cdata_open}{fakerequest.content}{cdata_close}</responseContent>
                </test>
            </log>
        </Payload>
    </Set>
    <ReasonPhrase>OK</ReasonPhrase>
    <StatusCode>200</StatusCode>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <AssignTo>response</AssignTo>
</AssignMessage>

You will get an actual cdata section in the output.

<log>
  <messageId>rrt-8957324297109092480-b-gwo1-8179-38716113-1</messageId>
  <test><responseContent><![CDATA[
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:IDSReservationRequest>
                ...
</ns2:IDSReservationRequest>


]]></responseContent>
  </test>
</log>

9355-anotacao-2019-10-24-155016.png

Hi Dino, thanks for the reply.

As I mentioned, I want to call an external logging service with the request/response of the target endpoint. Those are XML, as is the request for the logging service. What I want to do is inject those messages into a bigger payload, as you can see in the original ÂssignMessage, and then use this payload to call the logging service.

However, because those messages have the XML declaration in them, the logging service will return an error. A simple solution therefore would be to escape the request/response in the payload with CDATA, but as you noticed it's "consumed" by the AssignMessage and won't show up in the final payload.

I don't really like solution 1 because it would make the log less legible.

Option 2 seems like it could work for me, but Edge won't let me attribute the value "<[CDATA[" to a variable (nor "<![CDATA[", for that matter) - it says my XML is not valid, as you can see from the screenshot. Have you been able to deploy this?

yes, it works for me.

It looks to me you are missing the semi-colon after the lt.

it needs to be & lt; (but eliminate the space)

I guess if you add the semi-colon, the "Invalid XML" warning will disappear.

Dino, you're right, I was missing the semi-colon. It's working now, thanks.