ExtractVariables XPath null when passing value as CDATA

Not applicable

We have an ExtractVariables Policy using XPath. It looks like this:

<ExtractVariables async="false" continueOnError="false" enabled="true" name="GetRequestBodyVariables">
  <DisplayName>GetRequestBodyVariables</DisplayName>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> 
  <Source clearPayload="false">request</Source>
  <XMLPayload stopPayloadProcessing="false">
    <Namespaces>
      <Namespace prefix="soap">http://schemas.xmlsoap.org/soap/envelope/</Namespace>
    <Namespace prefix="atp">http://api.abc.com/AtpInquiryService_AWS/AtpInquiry</Namespace>
    </Namespaces>
    <Variable name="ashley.request.ExternalID" type="string">
      <XPath>//soap:Envelope/soap:Body/atp:ATPRequest/atp:KeyOne</XPath>
    </Variable>
    <Variable name="private.request.KeyCode" type="string">
      <XPath>//soap:Envelope/soap:Body/atp:ATPRequest/atp:KeyTwo</XPath>
    </Variable>
  </XMLPayload>
</ExtractVariables>

When passing a value with CDATA it evaluates as null, but if we don't wrap it with CDATA it works as expected. As far as I know CDATA is fully supported in XPath. We have many other programs outside of Apigee that handle this without any problem. Is this a known issue? Is there a workaround?

Solved Solved
2 3 1,059
1 ACCEPTED SOLUTION

Hi, I just investigated this on my own organization, and it works for me. I used your ExtractVariables policy (just changed the name of one of the extracted variables), and a contrived XML payload, like this:

<soap:Envelope
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:atp="http://api.abc.com/AtpInquiryService_AWS/AtpInquiry"
    >
  <soap:Body>
    <atp:ATPRequest>
      <atp:KeyOne>Sawtooth</atp:KeyOne>
      <atp:KeyTwo><![CDATA[-Mountain-]]></atp:KeyTwo>
    </atp:ATPRequest>
  </soap:Body>
</soap:Envelope>

As you can see, one of the elements is wrapped in a CDATA and one is not.

The proxy uses this AssignMessage policy to put the extracted value into a response message:

<AssignMessage name='AM-GoodResponse'>
  <DisplayName>AM-GoodResponse</DisplayName>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <Set>
    <Payload contentType='application/xml'><![CDATA[
<message>
  <externalId>{ashley.request.ExternalID:none}</externalId>
  <keyCode>{ashley.request.KeyCode:none}</keyCode>
</message>
]]></Payload>
    <StatusCode>200</StatusCode>
    <ReasonPhrase>OK</ReasonPhrase>
  </Set>
</AssignMessage>

When I pass in the SOAP body, I get this response:

<message>
  <externalId>Sawtooth</externalId>
  <keyCode>-Mountain-</keyCode>
</message>

My conclusion is that ExtractVariables works correctly when CDATA is used to wrap a text node.

One thing that catches people, sometimes: ExtractVariables will not extract anything from an XML Payload if the content-type header is not set appropriately. For example, assuming the file "soap-input-2.xml" contains the SOAP payload shown above, if I send this request:

$ curl -i -H content-type:text/xml  https://ORG-ENV.apigee.net/ev-cdata/f1 -d @ghunt-SOAP-input-2.xml 

...works as desired. If I omit the header, like this:

$ curl -i  https://ORG-ENV.apigee.net/ev-cdata/f1 -d @ghunt-SOAP-input-2.xml 

...then the ExtractVariables doesn't extract. This is as documented and as expected. If you have an XMLPayload element in the ExtractVariables policy, it applies if and only if the payload is an XML type, like text/xml or application/xml .

View solution in original post

3 REPLIES 3

Let me investigate; I'll get back to you shortly.

Hi, I just investigated this on my own organization, and it works for me. I used your ExtractVariables policy (just changed the name of one of the extracted variables), and a contrived XML payload, like this:

<soap:Envelope
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:atp="http://api.abc.com/AtpInquiryService_AWS/AtpInquiry"
    >
  <soap:Body>
    <atp:ATPRequest>
      <atp:KeyOne>Sawtooth</atp:KeyOne>
      <atp:KeyTwo><![CDATA[-Mountain-]]></atp:KeyTwo>
    </atp:ATPRequest>
  </soap:Body>
</soap:Envelope>

As you can see, one of the elements is wrapped in a CDATA and one is not.

The proxy uses this AssignMessage policy to put the extracted value into a response message:

<AssignMessage name='AM-GoodResponse'>
  <DisplayName>AM-GoodResponse</DisplayName>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <Set>
    <Payload contentType='application/xml'><![CDATA[
<message>
  <externalId>{ashley.request.ExternalID:none}</externalId>
  <keyCode>{ashley.request.KeyCode:none}</keyCode>
</message>
]]></Payload>
    <StatusCode>200</StatusCode>
    <ReasonPhrase>OK</ReasonPhrase>
  </Set>
</AssignMessage>

When I pass in the SOAP body, I get this response:

<message>
  <externalId>Sawtooth</externalId>
  <keyCode>-Mountain-</keyCode>
</message>

My conclusion is that ExtractVariables works correctly when CDATA is used to wrap a text node.

One thing that catches people, sometimes: ExtractVariables will not extract anything from an XML Payload if the content-type header is not set appropriately. For example, assuming the file "soap-input-2.xml" contains the SOAP payload shown above, if I send this request:

$ curl -i -H content-type:text/xml  https://ORG-ENV.apigee.net/ev-cdata/f1 -d @ghunt-SOAP-input-2.xml 

...works as desired. If I omit the header, like this:

$ curl -i  https://ORG-ENV.apigee.net/ev-cdata/f1 -d @ghunt-SOAP-input-2.xml 

...then the ExtractVariables doesn't extract. This is as documented and as expected. If you have an XMLPayload element in the ExtractVariables policy, it applies if and only if the payload is an XML type, like text/xml or application/xml .

Thank you for confirming the header requirement and the test case!