extract variable issue

Not applicable

Used assign message policy and assigned text/xml payload say like below.<a><b>hi</b></a> .then used extract variable with xml load xpath expression and assigned to variable x.eg: /a/b.But while testing it gave error saying unable to extract x.Please advice.Does Extract variable extracts only from from real target response or why it does not work for xml payload assigned from Assign messgae policy.

Solved Solved
0 8 1,066
1 ACCEPTED SOLUTION

The problem is with the lack of appropriate namespaces in your xpath.

In your comment you wrote "cannot paste whole as comment length excceds, but it is definitely well formed xml". But the part you omitted is the key part. We cannot diagnose for certain without that part.

But, I have a good guess. It looks like a WSDL file that you are embedding into the AssignMessage policy. And the root element in a WSDL file is the "definitions" element in the xml namespace of "http://schemas.xmlsoap.org/wsdl/". Example:

<definitions 
  targetNamespace="something-something"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
>
  much more stuff here

Therefore your XMLPayload element in the ExtractVariables policy must specify the WSDL namespace and use the appropriate prefix in the xpath. Like this:

  <XMLPayload>
    <Namespaces>
      <Namespace prefix='wsdl'>http://schemas.xmlsoap.org/wsdl/</Namespace>
      <Namespace prefix='soap'>http://schemas.xmlsoap.org/wsdl/soap/</Namespace>    </Namespaces>
    <Variable name='name' type='string'>
      <XPath>/wsdl:definitions/wsdl:service/wsdl:port/soap:address/@location</XPath>
    </Variable>

Do you understand why? Try and see, I bet it will work.

Here's a quick summary of XML Namespaces. Namespaces qualify elements. Therefore this XML document:

<a>
  <b>Hi</b>
</a>

...is not equivalent to this XML document.

<a xmlns="dino-was-here">
  <b>Hi</b>
</a>

The latter has specified that the a element and all of its children are scoped in the XML Namespace called "dino-was-here". (BTW, this is a TERRIBLE XML Namespace name. In fact, it should be a URN, so for example: http://mycompany.com/schema/messages is a good URN, or you could also use urn:my-company:schema:201703 . but I digress!)

The point is that the element a's are different in document 1 and document 2. An Xpath of

/a/b/text()

...will resolve to "Hi" when applied to the first document, whereas it will resolve to the empty set when applied to the second document. To get "Hi" from the second document, you need an xpath like this:

 /ns1:a/ns1:b/text()

...where "ns1" can be any simple string. In the parlance of XML Namespaces, it is known as a prefix. The actual prefix is not important, but what it gets mapped to is important. The prefix has to be mapped to the string "dino-was-here".

The ns1 in this example is like the prefix "wsdl" in the solution I gave above, and the string "dino-was-here", which again, denotes an XML Namespace, corresponds to "http://schemas.xmlsoap.org/wsdl/". One thing to be careful of: the namespace string is compared EXACTLY. Therefore "http://schemas.xmlsoap.org/wsdl/" (with the trailing slash) is not the same as "http://schemas.xmlsoap.org/wsdl" (without). They are not equivalent.

I hope this clarifies.

Some people say "ok, great, I understand XML namespaces, but I just don't want to deal with that. Can I specify an XPath that works regardless of the XML Namespace?" and the answer to that is "No, You can't." Sorry. there's no way to tell an XPath resolver "just ignore the namespaces on the elements." It would make life simpler in many cases, but it's not possible.

View solution in original post

8 REPLIES 8

Kindly paste your assign message and extract variable code in comment.

Not applicable

Assign message xml :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <AssignMessage async="false" continueOnError="false" enabled="true" name="Assign-Message-1"> <DisplayName>Assign Message-1</DisplayName> <Properties/> <Set> <Payload content="text/xml"> <definitions xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ...............<cannot paste whole as comment length excceds,but it is definitely well formed xml>encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input> <output><soap:body use="encoded" namespace="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output> </operation> </binding> <service name="ndfdXML"> <port name="ndfdXMLPort" binding="tns:ndfdXMLBinding"> <soap:address location="https:/abcd.bet/xml/SOAP_server/ndfdXMLserver.php"/> </port> </service> </definitions></Payload> <StatusCode>200</StatusCode> <ReasonPhrase>success</ReasonPhrase> </Set> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> <AssignTo createNew="false" transport="http" type="request"/> </AssignMessage>

extarct xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-Variables-2"> <DisplayName>Extract Variables-2</DisplayName> <Properties/> <Source>response</Source> <VariablePrefix>apigee</VariablePrefix> <XMLPayload stopPayloadProcessing="false"> <Namespaces/> <Variable name="name" type="string"> <XPath>/definitions/service/port/soap:address/@location</XPath> </Variable> </XMLPayload> </ExtractVariables>

Hi Praveenkumar,

just a reminder - you can EDIT your original question and post the full AssignMessage. If it's too large, you can edit the message and add an attachment. The attachment must have the file extension of ".txt". (cannot use .wsdl) .

Also: if you click the "code" button in the editor here, you can format code in your comments and questions. It makes it much easier for readers.

Thanks.

The problem is with the lack of appropriate namespaces in your xpath.

In your comment you wrote "cannot paste whole as comment length excceds, but it is definitely well formed xml". But the part you omitted is the key part. We cannot diagnose for certain without that part.

But, I have a good guess. It looks like a WSDL file that you are embedding into the AssignMessage policy. And the root element in a WSDL file is the "definitions" element in the xml namespace of "http://schemas.xmlsoap.org/wsdl/". Example:

<definitions 
  targetNamespace="something-something"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
>
  much more stuff here

Therefore your XMLPayload element in the ExtractVariables policy must specify the WSDL namespace and use the appropriate prefix in the xpath. Like this:

  <XMLPayload>
    <Namespaces>
      <Namespace prefix='wsdl'>http://schemas.xmlsoap.org/wsdl/</Namespace>
      <Namespace prefix='soap'>http://schemas.xmlsoap.org/wsdl/soap/</Namespace>    </Namespaces>
    <Variable name='name' type='string'>
      <XPath>/wsdl:definitions/wsdl:service/wsdl:port/soap:address/@location</XPath>
    </Variable>

Do you understand why? Try and see, I bet it will work.

Here's a quick summary of XML Namespaces. Namespaces qualify elements. Therefore this XML document:

<a>
  <b>Hi</b>
</a>

...is not equivalent to this XML document.

<a xmlns="dino-was-here">
  <b>Hi</b>
</a>

The latter has specified that the a element and all of its children are scoped in the XML Namespace called "dino-was-here". (BTW, this is a TERRIBLE XML Namespace name. In fact, it should be a URN, so for example: http://mycompany.com/schema/messages is a good URN, or you could also use urn:my-company:schema:201703 . but I digress!)

The point is that the element a's are different in document 1 and document 2. An Xpath of

/a/b/text()

...will resolve to "Hi" when applied to the first document, whereas it will resolve to the empty set when applied to the second document. To get "Hi" from the second document, you need an xpath like this:

 /ns1:a/ns1:b/text()

...where "ns1" can be any simple string. In the parlance of XML Namespaces, it is known as a prefix. The actual prefix is not important, but what it gets mapped to is important. The prefix has to be mapped to the string "dino-was-here".

The ns1 in this example is like the prefix "wsdl" in the solution I gave above, and the string "dino-was-here", which again, denotes an XML Namespace, corresponds to "http://schemas.xmlsoap.org/wsdl/". One thing to be careful of: the namespace string is compared EXACTLY. Therefore "http://schemas.xmlsoap.org/wsdl/" (with the trailing slash) is not the same as "http://schemas.xmlsoap.org/wsdl" (without). They are not equivalent.

I hope this clarifies.

Some people say "ok, great, I understand XML namespaces, but I just don't want to deal with that. Can I specify an XPath that works regardless of the XML Namespace?" and the answer to that is "No, You can't." Sorry. there's no way to tell an XPath resolver "just ignore the namespaces on the elements." It would make life simpler in many cases, but it's not possible.

assignmessage.txt

extarctvariable.txt

wsdl.txt

javascript:

print(context.getVariable("extractedsoapaddress"));

Thanks a lot for detailed explanation, but still i am unable to get it. Attached xmls and also java script so that I can see value in DEBUG.

You've got a couple problems there.

  1. First, the XML payload content is escaped in your AssignMessage. That's not right. Also, it needs to omit the XML declaration.
  2. the Payload element must have the attribute contentType. You have the attribute as content.
  3. The AssignMessage should assign to the response, not the request. Your ExtractVariables applies to the response, therefore I assume you want to assign to response.
  4. In ExtractVariables, the Xpath should not use a namespace prefix on the location attribute.

Fixing all those, it works just fine.

$ curl -i https://ORG-ENV.apigee.net/praveenkumar-1/t1a
HTTP/1.1 200 success
Date: Mon, 06 Mar 2017 20:22:53 GMT
Content-Type: text/xml
Content-Length: 84
Connection: keep-alive
Server: Apigee Router

<root>
  <address>https:/superhost/xml/SOAP_server/ndfdXMLserver.php</address>
</root>

Attached please find the relevant policies.

Oh, and also - It's not necessary to declare a prefix for every namespace that is used in the source XML. You need to declare prefixes for the namespaces that you will refer to, in the XPath. Declaring extra xmlns prefixes won't prevent the ExtractVariables from working properly, but it is extraneous and might lead to confusion for people reading the XPath later. Since your xpath refers only to the wsdl and soap prefixes, those are the only prefixes you need to declare.

assign-message-1axml.txt

extract-variables-2axml.txt

am-responsexml.txt

Thanks a lot Dino. You made me understand and it worked finally:)

I beg to differ from some points on XML.

XML inside XML needs to be escaped so that any parser or program reading xml does not get confused.

somehow apigee does not allow for xml declaration,even after escaping, it gets converted back to original form, and so a document cannot have 2 declarations by standards.

@dino I am trying to view the policies you have attached assign-message-1axml.txt but I am getting the message Access to the specified resource () has been forbidden.

Is there any problem with account