need to take SOAP headers out of a simplexml object

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
benward
Forum Newbie
Posts: 6
Joined: Wed Mar 24, 2010 11:30 am

need to take SOAP headers out of a simplexml object

Post by benward »

Hi Guys,

I have been arguing with my computer all day. It just doesn't want to do as it's told!

essentially I have been able to build an xml file in the format that I want using simplexml and stick it in a soap header, send it to a server in a post array and get a response. This is a huge victory for me :) It is basically sending info of a motor insurance risk and getting a response of quote ref, premium, terms etc.

Code: Select all

$xmlToSend = '<?xml version="1.0" encoding="UTF-8" ?>' . "\n" .
			 '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SOAP-ENV:Body>' . "\n" .
			 substr($xml2->asXML(),22) . //XML body
			 '</SOAP-ENV:Body>' . "\n" .
			 '</SOAP-ENV:Envelope>';
I know this looks strange but I needed a soap envelope on the request so I took the <?xml version="1.0" encoding="UTF-8" ?> off of the results of the simplexml so that I could stick a soap header in between that and the xml data.

I'm then using CURL to bring the xml response into a variable:

Code: Select all

$ch = curl_init(SOURCE_URL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlToSend);
$xmlReceived = curl_exec($ch);
curl_close($ch);
Then I'm loading the results into a simpleXMLElement and attempting to display the quoted premium:

Code: Select all

$QResponse = new SimpleXMLElement($xmlReceived);

echo "<pre>Premium Returned:" . (string) $QResponse->GrossPremium . "\n";
This doesn't seem to work. It just returns blank. If I look at the $QResponse->asXML; I can see that the GrossPremium element is populated so I can only assume that the issue is to do with the SOAP header that is being returned. Is there any way of removing the SOAP header without searching the curled string for <root element> and </root element> and substringing everything in between?

I tried using PHP SOAP earlier but the WS im trying to connect to doesn't like the way the xml is formatted by the soapClient object.

Thanks for reading,
Ben
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: need to take SOAP headers out of a simplexml object

Post by requinix »

You don't need to trim it off. Just work around it.

What's the XML?
benward
Forum Newbie
Posts: 6
Joined: Wed Mar 24, 2010 11:30 am

Re: need to take SOAP headers out of a simplexml object

Post by benward »

Request XML is:

Code: Select all

<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><SOAP-ENV:Body>
<QRequest><EffectiveDate>2010-3-30</EffectiveDate><AgentCode>38004W</AgentCode><PolicyType>S</PolicyType><CoverType>01</CoverType><TransactionType>1</TransactionType><ClassOfUse>A</ClassOfUse><DriverCode>1</DriverCode><ProtectedNCDFlag>Y</ProtectedNCDFlag><NCDYears>5</NCDYears><VoluntaryExcess>150</VoluntaryExcess><DiscretionaryLoading>0</DiscretionaryLoading><InstalmentsFlag>N</InstalmentsFlag><VehicleType>P</VehicleType><VehiclePostCode>GL2 8DJ</VehiclePostCode><VehicleABICode>52055502  </VehicleABICode><VehicleOwner>1</VehicleOwner><VehicleValue>4000</VehicleValue><VehicleYearOfMake>2005</VehicleYearOfMake><PurchasedDate>2008-07-20</PurchasedDate><AnnualMilage>5000</AnnualMilage><GarageCode>4</GarageCode><Modified>N</Modified><FortisReference>0000001A</FortisReference><DriverDetails><DriverNumber>1</DriverNumber><Proposer>Y</Proposer><Sex>M</Sex><DateOfBirth>1987-03-04</DateOfBirth><MaritalStatus>S</MaritalStatus><CommutesInVehicle>Y</CommutesInVehicle><AdjustedAge>0</AdjustedAge><LicenceType>F</LicenceType><LicenceDate>2004-11-03</LicenceDate><MainDriver>M</MainDriver><OwnsVehicle>Y</OwnsVehicle><KeepsVehicle>Y</KeepsVehicle><RelationToProposer>P</RelationToProposer><YearsResident>23</YearsResident><OccupationDetails><OccupationNumber>1</OccupationNumber><FullTime>Y</FullTime><OccupationABICode>084</OccupationABICode><EmployersABICode>077</EmployersABICode><EmploymentType>E</EmploymentType></OccupationDetails><DisabilityRecord><DisabilityNumber>1</DisabilityNumber><DisabilityCode/><DVLAAdvised>N</DVLAAdvised><Duration>0</Duration><Status/><Treatment/><Registered/><RestrictedLicence/></DisabilityRecord></DriverDetails></QRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Response XML is:

Code: Select all

<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><SOAP-ENV:Header/><SOAP-ENV:Body><QResponse><DateGenerated>2010-03-30</DateGenerated><TimeGenerated>09.20.30</TimeGenerated><CompanyName>Fortis Insurance Ltd</CompanyName><QuoteReference>2010-03-30-09.20.28.574990      </QuoteReference><GrossPremium>1813.37</GrossPremium><NetPremium>1727.02</NetPremium><Endorsements/><Exclusions/><Sections><SectionCode>A</SectionCode><SectionDescription>Damage to the car.</SectionDescription><SectionCode>B</SectionCode><SectionDescription>Broken windscreen and window glass</SectionDescription><SectionCode>C</SectionCode><SectionDescription>Fire and theft</SectionDescription><SectionCode>D</SectionCode><SectionDescription>Personal accident</SectionDescription><SectionCode>E</SectionCode><SectionDescription>Medical expenses</SectionDescription><SectionCode>F</SectionCode><SectionDescription>Personal belongings</SectionDescription><SectionCode>G</SectionCode><SectionDescription>Liabilities to third parties</SectionDescription><SectionCode>H</SectionCode><SectionDescription>Using your car abroad</SectionDescription><SectionCode>I</SectionCode><SectionDescription>Spanish bail bond</SectionDescription><SectionCode>J</SectionCode><SectionDescription>No claim discount</SectionDescription><SectionCode>K</SectionCode><SectionDescription>No claim discount protection</SectionDescription><SectionCode>L</SectionCode><SectionDescription>Replacement locks</SectionDescription></Sections><Limitations/></QResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
Thanks.
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: need to take SOAP headers out of a simplexml object

Post by requinix »

If you load the response into a SimpleXMLElement named $root then

Code: Select all

$root
	->children("http://schemas.xmlsoap.org/soap/envelope/")->Body
	->children("")->QResponse
will give you the <QResponse>. From there, navigate as normal.
benward
Forum Newbie
Posts: 6
Joined: Wed Mar 24, 2010 11:30 am

Re: need to take SOAP headers out of a simplexml object

Post by benward »

Magic! It works :) Thanks!

Can you please explain why it works? Don't fully understand..

I'm guessing it looks for SOAP-ENV: values for the name of the element but I dont understand the ->children("")-> part?

Thanks
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: need to take SOAP headers out of a simplexml object

Post by requinix »

The issue is namespaces: that's what the SOAP-ENV part in each tag deals with. I don't think I've made a good post about namespaces on this forum. Assuming you have a good understanding of how to use SimpleXML:

Every time you see a <foo:bar> tag you need to use namespaces. Unfortunately SimpleXML doesn't let you do

Code: Select all

$node->{"foo:bar"}
to get to the node. Instead to need a URI and the children and attributes methods.

The URI is given in an "xmlns:..." attribute somewhere. For example,

Code: Select all

<root xmlns="urn:com.example.namespaces" xmlns:foo="urn:com.example.namespaces.foo">
This defines two namespaces: the default (xmlns) and foo (xmlns:foo). Starting at <root> and applying to all child nodes (unless overridden with another xmlns or xmlns:foo),

Code: Select all

$root->children("urn:com.example.namespaces")
$root->children("urn:com.example.namespaces.foo")
Those two give the list of children in the default and foo namespaces respectively.

So if you have

Code: Select all

<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope
	xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
	xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	<SOAP-ENV:Body>
		<QRequest>
			<EffectiveDate>2010-3-30</EffectiveDate>
			<AgentCode>38004W</AgentCode>
			<PolicyType>S</PolicyType>
			<!-- ... -->
		</QRequest>
	</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
loaded into the $root variable (like with simplexml_load_string,

Code: Select all

/* the <SOAP-ENV:Envelope> */
$root // already have it

/* the <SOAP-ENV:Body> */
$root
	->children("http://schemas.xmlsoap.org/soap/envelope/") // switch to SOAP-ENV
	->Body // the name is what comes after the colon

/* the <QRequest> */
$root
	->children("http://schemas.xmlsoap.org/soap/envelope/") // switch to SOAP-ENV
	->Body // the name is what comes after the colon
	->children("") // switch to the default namespace
	->QRequest
(Note that the default URI for the default namespace is an empty string.)
Keep in mind that a namespace applies to the node itself, so if

Code: Select all

<QRequest xmlns="foo">
then

Code: Select all

/* the <QRequest> */
$root
	->children("http://schemas.xmlsoap.org/soap/envelope/") // switch to SOAP-ENV
	->Body // the name is what comes after the colon
	->children("") // switch to the default namespace
	->QRequest
Post Reply