Re: XML Parsing
| From: | Tyler Lane | Date: | Thu, 17 Jul 2003 17:59:27 +0000 |
| Subject: | Re: XML Parsing | ||
| References: | 1 | Groups: | php.general |
| Request: | Send a blank email to php-general+get-155662@lists.php.net to get a copy of this message | ||
On Thu, 2003-07-17 at 10:03, Doug La Farge wrote:
> Hello,
>
> I'm new to PHP but have been coding in Perl for over six years. I've
> had a steep learning curve in the last few days. My task has been to
> use fsockopen to pull in an XML stream, parse that XML stream, and
> package up that data into a complex, but usable data structure. We've
> been able to accomplish this in Perl but now I'm attempting to port the
> Perl code to PHP. The Perl code was written by Randal Schwartz (for me)
> but he's not interested in helping me solve the PHP problems I'm
> running into. I'm hoping to find someone on this list savvy in Perl
> and PHP, and understands complex data structures (in perl the hash
> refs/pointers go about four levels deep). I've included below the PHP
> code with three functions in question. Below each function is the Perl
> code I'm attempting to port.
>
> Here are some URL's that might help:
>
> http://shop.sprocketdata.com/test.php - url for the code below
> (which
> works if you copy paste)
> ignore the feof error- i left out the fsockopen because I know that's
> not where the problem is nor does this error effect the output.
>
> http://stage.holdit.com/cgi-bin/is/shipping.cgi - url for
> equivalent
> code in perl (ignore the drop-down)
>
> http://stage.holdit.com/cgi-bin/is/fetch.cgi - the data
> structure I'm
> trying to achieve in PHP
>
> http://stage.holdit.com/cgi-bin/is/is.cgi - the raw XML data
> structure
> - almost useless until parsed and probably useless to look at :-).
>
> You'll also notice at the bottom of the code I've included how the PHP
> XML parsed the data. It's very similar to the fetch.cgi - maybe it's
> different and thus causing the problem but I don't see it.
>
> <?php
>
> $state = array();
> global $state;
>
> // these two associatative arrays will hold the data structure (I hope
> :-)
> $quote = array();
> global $quote;
> $quotes = array();
> global $quotes;
>
> //XML start element
> function startElement(&$Parser, &$Elem, &$Attr) {
> global $state; //this works
> array_push ($state, $Elem); //this works
> $states = join (' ',$state); //can't interpolate the list so must
> join - works
> if ($states = "SHIPMENT PACKAGE") { //we make it this far
if( $states == "SHIPMENT PACKAGE" ) {
^^
> echo "$states\n"; //for testing should on print once!
> // $package_id = $Attr->{id}; // how to write this in PHP?
> }
> //This conditional is never met - QUOTE gets popped off before it
> returns
> elseif ($states = "SHIPMENT PACKAGE QUOTE") { //why does perl see
> QUOTE?
elseif( $states == "SHIPMENT PACKAGE QUOTE" ){
^^
> echo "$states\n"; // testing
> // %quote = ( package_id => $package_id, id => $attr->{id} ); //Perl
> // $quote = array ( package_id => $package_id, id => $attr->{id} );
> //PHP version of above line?
> }
> }
>
> /*Perl
> start_h => [ sub {
> my ($tagname, $attr) = @_;
> push @state, $tagname;
> if ("@state" eq "shipment package") {
> print "@state<br>";#testing
> $package_id = $attr->{id};
> }
> elsif ("@state" eq "shipment package quote") {
> %quote = ( package_id => $package_id, id => $attr->{id} );
> print "@state<br>";#testing
> }
> }, "tagname, attr"],
> */
>
> // XML data
> //This function might work but I don't know yet as QUOTE never stays in
> the $state stack
> function characterData(&$Parser, &$Line) {
> global $state;
> $states = join (' ',$state);
> if ($states = "SHIPPMENT ERROR") {
if( $states == "SHIPMENT ERROR" ) {
^^
> $error = $Line;
> }
> elseif ($states = "SHIPMENT PACKAGE QUOTE BOXID") {
elseif( $states == "SHIPMENT PACKAGE QUOTE BOXID" ) {
^^
> $boxID = $Line;
> }
> elseif ($states = "SHIPMENT PACKAGE QUOTE CARRIER NAME") {
elseif( $states == "SHIPMENT PACKAGE QUOTE CARRIER NAME"
) {
^^
> $quote{carrier_name} = $Line; // Doubting this will work - need to
> fix this too
> }
> elseif ($states = "SHIPMENT PACKAGE QUOTE CARRIER CODE") {
elseif( $states == "SHIPMENT PACKAGE QUOTE CARRIER CODE"
) {
^^
> $quote{carrier_code} = $Line;
> }
> elseif ($states = "SHIPMENT PACKAGE QUOTE CLASS NAME") {
elseif( $states == "SHIPMENT PACKAGE QUOTE CLASS NAME" )
{
^^
> $quote{class_name} = $Line;
> }
> elseif ($states = "SHIPMENT PACKAGE QUOTE CLASS CODE") {
elseif( $states == "SHIPMENT PACKAGE QUOTE CLASS CODE" )
{
^^
> $quote{class_code} = $Line;
> }
> elseif ($states = "SHIPMENT PACKAGE QUOTE SERVICE NAME") {
elseif( $states == "SHIPMENT PACKAGE QUOTE SERVICE NAME"
) {
^^
> $quote{service_name} = $Line;
> }
> elseif ($states = "SHIPMENT PACKAGE QUOTE SERVICE CODE") {
elseif( $states == "SHIPMENT PACKAGE QUOTE SERVICE CODE"
) {
^^
> $quote{service_code} = $Line;
> }
> elseif ($states = "SHIPMENT PACKAGE QUOTE RATE AMOUNT") {
elseif( $states == "SHIPMENT PACKAGE QUOTE RATE AMOUNT"
) {
^^
> $quote{amount} = $Line;
> }
> }
>
> /* Perl
> text_h => [ sub {
> my ($text) = @_;
> if ("@state" eq "shipment error") {
> $error = $text;
> }
> elsif ("@state" eq "shipment package boxID") {
> $boxID = $text;
> }
> elsif ("@state" eq "shipment package quote carrier name") {
> $quote{carrier_name} = $text;
> }
> elsif ("@state" eq "shipment package quote carrier code") {
> $quote{carrier_code} = $text;
> }
> elsif ("@state" eq "shipment package quote class name") {
> $quote{class_name} = $text;
> }
> elsif ("@state" eq "shipment package quote class code") {
> $quote{class_code} = $text;
> }
> elsif ("@state" eq "shipment package quote service name") {
> $quote{service_name} = $text;
> }
> elsif ("@state" eq "shipment package quote service code") {
> $quote{service_code} = $text;
> }
> elsif ("@state" eq "shipment package quote rate amount") {
> $quote{amount} = $text;
> }
> }, "dtext"],
> */
>
>
> function endElement(&$Parser, &$Elem) {
> global $state;
> $states = join (' ',$state);
> if ($states = "SHIPMENT PACKAGE QUOTE") {
if( $states == "SHIPMENT PACKAGE QUOTE" ) {
^^
> //echo "got QUOTE here $states\n";
>
> /*
> The following three lines need porting to PHP
> there is much perl magic here - I can explain if it doesn't
> make sense. The short of this is it's a rather complex structure
> Perhaps this is where things are breaking?
> */
> //$key = "@quote{qw(carrier_code service_code)}";
> //delete @quote{qw(id package_id)}; # artificial
> //$quotes{$boxID}{$key} = {%quote};
> }
> // obviously the part that pulls QUOTE off the $state stack
> // perhaps a conditional?
> array_pop($state);
> }
>
> /*Perl
> end_h => [ sub {
> my ($tagname) = @_;
> if ("@state" eq "shipment package quote") {
> my $key = "@quote{qw(carrier_code service_code)}";
> delete @quote{qw(id package_id)}; # artificial
> $quotes{$boxID}{$key} = {%quote};
> }
> pop @state;
> }, "tagname"],
> */
>
>
>
> //This code should work just fine
> echo '<html><body><pre><form>';
> $xml_parser = xml_parser_create();
> xml_set_element_handler($xml_parser, "startElement", "endElement");
> xml_set_character_data_handler($xml_parser, "characterData");
>
> //The XML data as returned from the server in it's raw form
> $data = '<?xml version="1.0"?><shipment
>
> xsi:schemaLocation="http://www.intershipper.com/Interface/Intershipper/
> XML/v2.0/schemas response.xsd"
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-
> instance"><version>2.0.0.0</version><shipmentID>1234</
> shipmentID><queryID>23456</queryID><deliveryType>COM</
> deliveryType><shipMethod>DRP</shipMethod><origination><name>John
> Smith</name><address1>465 Tyende
> Ovi</address1><address2></address2><address3></
>
> address3>address3><city>Flagstaff</city><state>AZ</state><postal>86001</
>
> postal>postal><country>US</country></origination><destination><name>Jane
> Doe</name><address1>466 Tyende
> Ovi</address1><address2></address2><address3></
>
> address3>address3><city>Flagstaff</city><state>AZ</state><postal>86001</
> postal><country>US</country></destination><package
> id="1"><boxID>1</boxID><weight
> unit="LB">10.0</weight><dimensions
>
> unit="IN"><length>10.0</length><width>10.0</width><height>10.0</
>
> height></dimensions><packaging>BOX</packaging><contents>OTR</
> contents><cod>18500</cod><insurance>15000</
> insurance><options><specialHandling
> id="1"><code>SDD</code><name>Saturday
> Delivery</name></specialHandling></options><quote
> id="1"><carrier><code>UPS</code><name>United Parcel
>
> Service</name><account>123456789</account><invoiced>1</invoiced></
> carrier><class><code>1DY</code><name>1st
> Day</name></class><service><code>NDA</code><name>Next Day
>
> Air</name></service><rate><amount>4201</amount><currency>USD</
>
> currency></rate></quote><quote
> id="2"><carrier><code>UPS</code><name>United Parcel
>
> Service</name><account>123456789</account><invoiced>1</invoiced></
> carrier><class><code>1DY</code><name>1st
> Day</name></class><service><code>NDS</code><name>Next Day
> Air
>
> Saver</name></service><rate><amount>3898</amount><currency>USD</
>
> currency></rate></quote><quote
> id="3"><carrier><code>UPS</code><name>United Parcel
>
> Service</name><account>123456789</account><invoiced>1</invoiced></
> carrier><class><code>1DY</code><name>1st
> Day</name></class><service><code>NDM</code><name>Next Day
> Air
>
> AM</name></service><rate><amount>7087</amount><currency>USD</
>
> currency></rate></quote></package></shipment>';
>
> if (!xml_parse($xml_parser, $data, feof($fp))) {
> die(sprintf("XML error: %s at line %d",
> xml_error_string(xml_get_error_code($xml_parser)),
> xml_get_current_line_number($xml_parser)));
> }
> xml_parser_free($xml_parser);
> echo '</select></form>';
>
>
> /*
> Here is an example of the data returned from the XML parser
>
> SHIPMENT:
> VERSION: 2.0.0.0
> SHIPMENTID: 1234
> QUERYID: 23456
> DELIVERYTYPE: COM
> SHIPMETHOD: DRP
> ORIGINATION:
> NAME: John Smith
> ADDRESS1: 465 Tyende Ovi
> ADDRESS2:
> ADDRESS3:
> CITY: Flagstaff
> STATE: AZ
> POSTAL: 86001
> COUNTRY: US
> DESTINATION:
> NAME: Jane Doe
> ADDRESS1: 466 Tyende Ovi
> ADDRESS2:
> ADDRESS3:
> CITY: Flagstaff
> STATE: AZ
> POSTAL: 86001
> COUNTRY: US
> PACKAGE:
> BOXID: 1
> WEIGHT: 10.0
> DIMENSIONS:
> LENGTH: 10.0
> WIDTH: 10.0
> HEIGHT: 10.0
> PACKAGING: BOX
> CONTENTS: OTR
> COD: 18500
> INSURANCE: 15000
> OPTIONS:
> SPECIALHANDLING:
> CODE: SDD
> NAME: Saturday Delivery
> QUOTE:
> CARRIER:
> CODE: UPS
> NAME: United Parcel Service
> ACCOUNT: 123456789
> INVOICED: 1
> CLASS:
> CODE: 1DY
> NAME: 1st Day
> SERVICE:
> CODE: NDA
> NAME: Next Day Air
> RATE:
> AMOUNT: 4201
> CURRENCY: USD
> QUOTE:
> CARRIER:
> CODE: UPS
> NAME: United Parcel Service
> ACCOUNT: 123456789
> INVOICED: 1
> CLASS:
> CODE: 1DY
> NAME: 1st Day
> SERVICE:
> CODE: NDS
> NAME: Next Day Air Saver
> RATE:
> AMOUNT: 3898
> CURRENCY: USD
> QUOTE:
> CARRIER:
> CODE: UPS
> NAME: United Parcel Service
> ACCOUNT: 123456789
> INVOICED: 1
> CLASS:
> CODE: 1DY
> NAME: 1st Day
> SERVICE:
> CODE: NDM
> NAME: Next Day Air AM
> RATE:
> AMOUNT: 7087
> CURRENCY: USD
> */
> ?>
>
>
> I do apologize for the length of this email. I did my best to make it
> short.
--
Tyler Lane <tlane@lyrical.net>
Attachment: [application/pgp-signature] This is a digitally signed message part signature.asc
Attachment: [application/pgp-signature] This is a digitally signed message part signature.asc