[PHP] Soap (request), attribute construeren.

Pagina: 1
Acties:
  • 325 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • r0bert
  • Registratie: September 2001
  • Laatst online: 30-07 02:32
Ik ben nu al 2 dagen aan het stoeien om een stom attribuut bij een element in de SOAP request te krijgen vanuit PHP. Ik heb de search gebruikt en google misbruikt, maar geen resultaat.

Mijn request moet er ongeveer zo uit gaan zien (versimpelt):

SOAP request:
XML:
1
2
3
4
5
6
7
<env:Envelope ...>
  <env:Body>
    <ns1:getNodes ...>
       <elem attr="value">content</elem>
    </ns1:getNodes>
  </env:Body>
</env:Envelope>



Het enige wat ik tot nu toe krijg is meer als

PHP:
1
2
3
$return = $client->__soapCall("getNodes", 
    array('_' => 'value', 'attr' => 'attvalue')
   );

SOAP request:
XML:
1
2
3
4
<ns1:getNodes ...>
    <fields xsi:type="xsd:string">value</fields>
    <param1 xsi:type="xsd:string">attvalue</param1>
</ns1:getNodes>



---OF---

zo:
PHP:
1
2
3
   $return = $client->__soapCall("getNodes", 
    array('_' => array('value', 'attr' => 'attvalue'))
   );

SOAP request:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
<ns1:getNodes ...>
    <fields xsi:type="ns2:Map">
        <item>
            <key xsi:type="xsd:int">0</key>
            <value xsi:type="xsd:string">value</value>
        </item>
        <item>
            <key xsi:type="xsd:string">attr</key>
            <value xsi:type="xsd:string">attvalue</value>
        </item>
    </fields>
</ns1:getNodes>



Mijn WSDL hierbij is als volgt:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<types>
      <xsd:schema ...>          
        <complexType name="testType">
            <complexContent>
                <restriction base="xsd:string">
                    <attribute name="attr" type="xsd:string"/>
                </restriction>
            </complexContent>
        </complexType>          
    </xsd:schema>
</types>
    
    
<message name="myRequest">
    <part name="elem" type="types:testType"/>
</message>


Iemand die weet hoe dit wel werkend te krijgen is? De documentatie is zeer beperkt en wat ik heb kunnen vinden over '_' toepassen en SOAPvar en SOAPparam, kreeg ik niet werkend. Een werkende testcase ben ik al meer dan blij mee!

Liefst zou ik ook ns1 namespace vervangen door een eigen ns. Als iemand dat weet hoor ik het ook graag :)

Acties:
  • 0 Henk 'm!

  • r0bert
  • Registratie: September 2001
  • Laatst online: 30-07 02:32
Ik weet niet waardoor, maar ik heb het werkend (ik denk iets met namespaces). Voor refs (lijkt me erg handig omdat de docu héél matig is):

WSDL:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0"?>
<definitions name="MyDefinition"
    targetNamespace="http://www.sovenewmedia.nl"
    xmlns:tns="http://www.sovenewmedia.nl/tns" 
    xmlns:pfwx="http://www.sovenewmedia.nl/pfwx"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns="http://schemas.xmlsoap.org/wsdl/">
    
    <types>
      <xsd:schema targetNamespace="http://www.sovenewmedia.nl" xmlns="http://www.w3.org/2001/XMLSchema/">
            
        <xsd:complexType name="elem">
                <xsd:attribute name="attr" type="xsd:string"/>
        </xsd:complexType>
            
        </xsd:schema>
    </types>
    
    
    <message name="myRequest">
        <part name="elem" type="elem"/>
    </message>
... etc
</...afsluitingen>

Gedeelte van code komt uit een bron van internet die ik zo niet meer weet, tut. ofzo


PHP:
1
2
3
4
5
6
7
8
9
10
11
$cVar = new SoapVar
    (
        Array('elem', 'attr' => 'test'),
        SOAP_ENC_OBJECT, 
        'elem', 
        'http://www.sovenewmedia.nl'
    );

$return = $client->__soapCall("getNodes", 
            Array($cVar)
             );


Resultaat (helaas nog wel ns1)
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope 
    xmlns:env="http://www.w3.org/2003/05/soap-envelope" 
    xmlns:ns1="http://www.sovenewmedia.nl" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:enc="http://www.w3.org/2003/05/soap-encoding">

    <env:Body>
        <ns1:getNodes env:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
            <elem attr="test" xsi:type="ns1:elem"/>
        </ns1:getNodes>
    </env:Body>
</env:Envelope>

Maar goed genoeg

Acties:
  • 0 Henk 'm!

  • r0bert
  • Registratie: September 2001
  • Laatst online: 30-07 02:32
Nu loop ik toch tegen een probleem aan, wanneer ik meerdere 'levels' ga gebruiken:

Dit werkt:
WSDL (xml schema)
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
<types>
    <xsd:schema targetNamespace="http://www.sovenewmedia.nl"
        xmlns="http://www.w3.org/2001/XMLSchema/">

        <xsd:complexType name="elem">
            <xsd:sequence>
                <xsd:element name="test" type="xsd:string" />
            </xsd:sequence>
            <xsd:attribute name="attr" type="xsd:string" use="required" />
        </xsd:complexType>  
    
    </xsd:schema>
</types>


Met de PHP code:
PHP:
1
2
3
4
5
6
7
8
9
10
11
   $cVar = new SoapVar
        (
            Array('_' =>'value', 'attr' => 'test', 'test' => 'testval'),
            SOAP_ENC_OBJECT, 
            'elem', 
            'http://www.sovenewmedia.nl'
        );

    $return = $client->__soapCall("getNodes", 
                Array($cVar)
            );


geeft netjes de SOAP request
XML:
1
2
3
<elem attr="test" xsi:type="ns1:elem">
    <test xsi:type="xsd:string">testval</test>
</elem>

MAAR wil ik dat een stap verder doen, bijvoorbeeld met meer elementen van hetzelfde type e.d. wordt dit gewoon een rotzooitje (identieke indexes :?).

Dat zou iets worden als
PHP:
1
2
3
4
5
6
7
8
9
Array(
    '_'    =>'value', 
    'attr' => 'test', 
    'test' => Array(
        '_'   => 'testvalue', 
        'sub' => 'melp', 
        'sub' => 'blaat'
    )
),

Met aangepast schema
XML:
1
2
3
4
5
6
7
8
9
10
11
12
<xsd:complexType name="elem">
    <xsd:sequence>
        <xsd:element name="test" base="xsd:string">     
            <xsd:complexType>       
                <xsd:sequence>
                    <xsd:element name="sub" base="xsd:string"/>
                </xsd:sequence>
            </xsd:complexType>      
        </xsd:element>
    </xsd:sequence>
    <xsd:attribute name="attr" type="xsd:string" use="required" />
</xsd:complexType>

Voor het eerste sub element werkt dat, maar de tweede niet (of andersom), omdat ze elkaar 'overschrijven'.

Het SOAP request ziet er nu dus zo uit:
XML:
1
2
3
4
5
<elem attr="test" xsi:type="ns1:elem">
    <test xsi:type="ns1:test">
        <sub xsi:type="xsd:string">melp</sub>
    </test>
</elem>

Maar die sub zou dus 2x voor moeten komen 8)7

Ik heb het geprobeert te nesten, maar weet niet hoe ik dit netjes en werkend voor elkaar kan krijgen. Heeft IEMAND hier ervaring mee?

[ Voor 35% gewijzigd door r0bert op 05-09-2007 23:36 ]


  • r0bert
  • Registratie: September 2001
  • Laatst online: 30-07 02:32
Ik heb het ook zo geprobeert:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$cSub = new SoapVar
                        (
                            Array('_' =>'sub'),
                            SOAP_ENC_OBJECT, 
                            'sub'
                        );
                        
$cTest = new SoapVar
                        (
                            Array($cSub),
                            SOAP_ENC_OBJECT, 
                            'test'
                        );
                        
$cVar = new SoapVar
                        (
                            Array($cTest),
                            SOAP_ENC_OBJECT, 
                            'elem', 
                            'http://www.sovenewmedia.nl'
                        );


$return = $client->__soapCall("getNodes", 
                                                    Array($cVar)
                                            );


Maar dat zorgt er alleen maar voor dat Apache crashed (op veel manier trouwens). Iemand??

Acties:
  • 0 Henk 'm!

  • r0bert
  • Registratie: September 2001
  • Laatst online: 30-07 02:32
Iemand een tip waar ik het antwoord zou kunnen vinden behalve googlen op "nested soap request"?

Acties:
  • 0 Henk 'm!

  • r0bert
  • Registratie: September 2001
  • Laatst online: 30-07 02:32
Anders iemand die weet hoe ik een string of kant-en-klaar (plain) SOAP-request bestand kan verzenden voor afhandeling m.b.v. PHP oid?

Acties:
  • 0 Henk 'm!

  • r0bert
  • Registratie: September 2001
  • Laatst online: 30-07 02:32
Nou deze moeite wil ik mensen besparen, wat een bagger werkje is het om dat uit te zoeken.

Ik heb het werkend gekregen en er meteen maar even een (zeer) brakke class bijgemaakt. Hij werkt bij het voorbeeld iig wel en er valt uit af te leiden hoe het wel zou moeten werken. Bij meerdere elementen van het zelfde 'type' wordt er dus een extra level nesting ingebracht.

Deze class heeft een iets andere opzet dan de structuur met arrays, hier is het eerste parameter het type element. De tweede is de waarde ervan en de volgargumenten zijn de childsnodes en attribute (als SOAPArray). Een lap code zegt meer dan duizend woorden:

(att2 slaat nergens op, te lui om het weg te halen)

Class:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
class SOAPArray
{   private     $__text;
    
    protected $__name;
    
    public      $__childs = Array();        
    public      $__exported;
    
    /* Third+ arguments will become child-elements or attributes  */
    public function __construct($sName, $sText) 
    {   $this->__name = $sName;
        $this->__text = $sText;
        
        $this->__exported = false;
        
        /* If third+ argument(s) are passed, they'll be added as childnodes */
        if (
                (func_num_args() > 2)
            )
        {   $iArg = 1;
        
            /* We require SOAPArray Objects */
            while (@get_class($aChild = func_get_arg(++$iArg)) == 'SOAPArray') 
            {   array_push($this->__childs, $aChild);
            }   
        }
    }
    
    
    public function export()
    {   return Array($this->__name => $this->exportArray());
    }
    
    protected function exportArray()
    {   $aReturnArray = Array();
            // Alles van dezelfde type in een array in een array proppen.
            // Alles waar maar 1 per type van is in ene array
        
        foreach ($this->__childs as $oChild)
        {   if (!$oChild->__exported)
                $aReturnArray[$oChild->__name] = $this->getChildSameType($oChild->__name, $oChild);
        }
        
        if (!$this->__childs)
        {   return $this->__text;
        }
        
        return $aReturnArray;
    }
    
    // Call to parent, search in childs
    public function getChildSameType($sType, $oActiveChild)
    {   $aReturnArray = Array();
        
        foreach ($this->__childs as $oChild)
        {
            if (
                    ($sType == $oChild->__name) && 
                    (!$oChild->__exported)          
                )
            { array_push($aReturnArray, $oChild->exportArray());
                $oChild->__exported = true;
            }
        }

        if (count($aReturnArray) > 1)
            return $aReturnArray;
        else
            return $oActiveChild->exportArray();
    }
};


Aanroepen
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$oSOAP =    
    new SOAPArray('elem', null,
    
                        new SOAPArray(
                            'sub1', null,
                            new SOAPArray(
                                'att', 'test1'
                            )
                        ),
                        
                        new SOAPArray(
                            'sub1', null,
                            new SOAPArray(
                                'att', 'test2'
                            ),
                            new SOAPArray(
                                'att2', 'test3'
                            )
                        ),
                        
                        new SOAPArray(
                            'sub2',null,
                            new SOAPArray(
                                'att5', 'test'
                            )
                        )
                        
            );


Output:
print_r($oSOAP->export());
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Array
(
    [elem] => Array
        (
            [sub1] => Array
                (
                    [0] => Array
                        (
                            [att] => test2
                            [att2] => test3
                        )

                )

            [sub2] => Array
                (
                    [att5] => test
                )

        )

)


WSDL:
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<xsd:schema elementFormDefault="qualified" targetNamespace="http://www.sovenewmedia.nl" xmlns="http://www.w3.org/2001/XMLSchema/">


    <xsd:complexType name="customType">
                <xsd:choice minOccurs="0" maxOccurs="unbounded">
            <xsd:element name="sub1" type="tns:customType2" />
            <xsd:element name="sub2" type="tns:customType2" />
          </xsd:choice>
    </xsd:complexType>
    
    <xsd:complexType name="customType2">
        <xsd:attribute name="att" type="xsd:string" use="required" />               
    </xsd:complexType>
    
</xsd:schema>

Met verderop
XML:
1
2
3
<message name="myRequest">
    <part name="elem" type="tns:customType" />
</message>


Met als uiteindelijk resultaat:
SOAP
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope 
    xmlns:env="http://www.w3.org/2003/05/soap-envelope" 
    xmlns:ns1="http://www.sovenewmedia.nl" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
    
    <env:Body>
        <ns1:getNodes 
            env:encodingStyle="http://www.w3.org/2003/05/soap-encoding">        
            <elem xsi:type="ns1:customType">
                <sub1 att="test" xsi:type="ns1:customType2"/>
                <sub1 att="test" xsi:type="ns1:customType2"/>
                <sub2 att="test" xsi:type="ns1:customType2"/>
            </elem>
        </ns1:getNodes>
    </env:Body>
</env:Envelope>

[ Voor 9% gewijzigd door r0bert op 09-09-2007 23:08 ]


Acties:
  • 0 Henk 'm!

  • r0bert
  • Registratie: September 2001
  • Laatst online: 30-07 02:32
Nog even een betere versie:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
ini_set("soap.wsdl_cache_enabled", "0"); 


class SOAPArray
{   private     $__text;
    
    protected $__name;
    
    public      $__childs = Array();        
    public      $__exported;
    
    /* Third+ arguments will become child-elements or attributes  */
    public function __construct($sName, $sText) 
    {   $this->__name = $sName;
        $this->__text = $sText;
        
        $this->__exported = false;
        
        /* If third+ argument(s) are passed, they'll be added as childnodes */
        if (
                (func_num_args() > 2)
            )
        {   $iArg = 1;
        
            /* We require SOAPArray Objects */
            while (@get_class($aChild = func_get_arg(++$iArg)) == 'SOAPArray') 
            {   array_push($this->__childs, $aChild);
            }   
        }
    }
    
    
    public function export()
    {   $aSOAPExport = Array($this->__name => $this->exportArray());
        
        $this->unsetExport();
        
        return $aSOAPExport;
    }
    
    private function unsetExport()
    {   $this->__exported = false;      
        
        foreach ($this->__childs as $oChild)
        {   $oChild->unsetExport();
        }
    }
    
    protected function exportArray()
    {   $aReturnArray = Array();
            // Alles van dezelfde type in een array in een array proppen.
            // Alles waar maar 1 per type van is in ene array
        if ($this->__childs)
        {
            foreach ($this->__childs as $oChild)
            {   if (!$oChild->__exported)
                    $aReturnArray[$oChild->__name] = $this->getChildSameType($oChild->__name, $oChild);
            }
        }
        else
        {   return $this->__text;
        }
        
        return $aReturnArray;
    }
    
    // Call to parent, search in childs
    public function getChildSameType($sType, $oActiveChild)
    {   $aReturnArray = Array();

        foreach ($this->__childs as $oChild)
        {
            if (
                    ($sType == $oChild->__name) && 
                    (!$oChild->__exported)
                )                                                                                                                           //*1   oChild != oActiveChild
            { array_push($aReturnArray, $oChild->exportArray());
                
                $oChild->__exported = true; // Block multiple indexing
            }
        }
        
        if (count($aReturnArray) == 1)                                                                          //*1   > 0
        {   $oActiveChild->unsetExport(); // Free the active child for single indexing
            return $oActiveChild->exportArray();
        }
        else
            return $aReturnArray;
    }
};
    
    

$oSOAP =    
    new SOAPArray('core', null,
    
                        new SOAPArray(
                            'cond', null,
                            
                            new SOAPArray(
                                'cond', 'c == d'
                            ),
                            
                            new SOAPArray(
                                'prop', 'naam'
                            )
                        ),
                        new SOAPArray(
                            'cond', 'a == b'
                        ),
                        
                        new SOAPArray(
                            'act', 'getNodes'
                        ),
                        
                        new SOAPArray(
                            'name','facturen'
                        ),
                        
                        new SOAPArray(
                            'select', null,
                            
                            new SOAPArray(
                                'prop', 'relatieid'
                            ),
                            new SOAPArray(
                                'prop', 'naam'      
                            ),
                            new SOAPArray(
                                'prop', 'plaats'        
                            )
                        ),
                        
                        new SOAPArray(
                            'param', null,
                            
                            new SOAPArray(
                                'name', 'sort'                  
                            )
                        )   
            );

print_r($oSOAP->export());

Ik krijg het alleen niet voor elkaar om een element sort of mixed te maken. Dus dat hij én subelementen krijgt én eigen text. Iemand die me hier nog mee zou kunnen helpen? Wat voor Array moet dat worden?
Pagina: 1