Php: Soap: How to add attribute to SoapVar

From FVue
Jump to: navigation, search

Problem

The WSDL of a webservice requires me to provide an XML-attribute "version" when making a SOAP-call. See this WSDL snippet:

<complexType name="MessageHeader">
  <sequence>
    <element name="From"/>
    <element name="To"/>
  </sequence>
  <attribute form="qualified" name="version" type="xsd:string" use="required"/>;
</complexType>

But there is no way to specify attributes when I create a SoapVar like this(?):

$var = new StdClass;
$var->From = 'foo';
$var->To   = 'bar';
$MessageHeader = new SoapVar($var, SOAP_ENC_OBJECT);

The generated XML is not valid, because the `MessageHeader' element is missing the `version' attribute:

<ns2:MessageHeader>
  <From>foo</From>
  <To>bar</To>
</ns2:MessageHeader>

Environment

  • php-5.3.10

Solution 1: Element and attribute in same namespace

The solution is to map the WSDL object to a PHP class, and to specify the XML attribute as an object property. Now PHP will automatically create the XML attribute.

1. Map the WSDL object to a PHP class via the `classmap' option:

$client = new SoapClient(wsdl, array(
    'trace'        => 1,                                        
    'encoding'     => 'UTF-8',
    'soap_version' => SOAP_1_1,
    'classmap'     => array('MessageHeader' => 'MessageHeaderSoapStruct')
));

2. Create the PHP class:

class MessageHeaderSoapStruct {
    public $From;
    public $To;
    public $version;
}

3. Create the SoapVar using the PHP class:

$var = new MessageHeaderSoapStruct;
$var->From    = 'foo';
$var->To      = 'bar';
$var->version = 1;
$namespace = 'http://xxx'; # Namespace of MessageHeader WSDL element
$MessageHeader = new SoapVar($var, SOAP_ENC_OBJECT, 'MessageHeader', $namespace);

4. The generated XML now looks like this :)

<ns2:MessageHeader ns2:version="1">
  <ns2:From>foo</ns2:From>
  <ns2:To>bar</ns2:To>
</ns2:MessageHeader>

Solution 2: Element and attribute in different namespaces

In case the WSDL specifies the attribute in a different namespace:

<element name="element1" type="ns2:type1"/>
...
<xsd:complexType name="type1">
  <xsd:simpleContent>
    <xsd:extension base="xsd:string">
      <xsd:attribute form="qualified" name="attribute1" type="xsd:string" use="required"/>
    </xsd:extension>
  </xsd:simpleContent>
</xsd:complexType>

and the generated XML should look like this:

<ns1:element1 ns2:attribute1="myattribute1">myvalue1</ns1:element1>

Here's how to generate the XML:

1. Map the WSDL object containing the attribute (type1) to a PHP class via the `classmap' option:

$client = new SoapClient(wsdl, array(
    'trace'        => 1,                                        
    'encoding'     => 'UTF-8',
    'soap_version' => SOAP_1_1,
    'classmap'     => array(
        'type1'   => 'Type1SoapStruct'
    )
));

2. Create the PHP class:

class Type1SoapStruct {
    public $attribute1;
}

3. Create the SoapVar using the PHP class. Specify different namespaces for attribute1 and element1:

$nmB = 'http://mynamespace2';
$nsB = 'myns2';
$element1 = new Type1SoapStruct;
$element1->attribute1 = new SoapVar('myattribute1', XSD_STRING, 'type1', null, $nmB, $nsB);
$element1->_ = 'myvalue1';
 
$nmA = 'http://mynamespace1';
$nsA = 'myns1';
$element1_soapvar = new SoapVar($element1, SOAP_ENC_OBJECT, null, null, $nmA, $nsA);
 
$params = new StdClass();
$params->element1 = $element1_soapvar;
$this->__soapCall('mycall', array(new SoapVar(array($params), SOAP_ENC_OBJECT)));

4. The generated XML now looks like this :)

<ns1:element1 ns2:attribute1="myattribute1" xsi:type="ns2:type1">myvalue1</ns1:element>

Journal

20150917

[SOLVED] php Soap Client - Node Attributes
Forum thread with the classmap solution
Creating a SOAP request with PHP - how do I add attributes to the XML tags? - Stack Overflow:
Forum thread with a workaround using the XSD_ANYXML encoding.

Comments

blog comments powered by Disqus