Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Not New to XML Generation but New to Parsing....help 1

Status
Not open for further replies.

nine72

Technical User
Oct 21, 2008
6
0
0
US
Ok, I am not sure where to start with this or even if this is the right forum topic (could be in the PHP section also..), I can generally figure out my issues after a few days…but not this time…haha.

Overview:
Receive an incoming XML string, parse, store to session or other method and present results on a web page (PHP).

Currently, I am generating an xml sting from a set of 15 forms and sending to a middleware app that validates business rules and commits to a central DB. I have not been required to accept a response other than the following…

Code:
<Response>
	<RecordId>Id_Here</RecordId>
	<Status>Insert Complete or Failed</Status>
<Response>

The RecordId I generate and send and it is just returned to me, The Status I would see if it were Complete or Failed and direct the user to the correct page.

Now I am being required to take the incoming string and return all values to a completed page if the insert is successful.

As stated above the string I send is generated from 15 form pages. However, 3 pages can be “recycled” as many times in a session as the user requires. This is say a Contact page, they can give me 1 contact or a 1K contacts. For each contact that is returned it would look something like this…

Code:
<Contact>
   <contact_id>971</contact_id>
   <contact_type>ACCOUNTING</contact_type>
   <first_name>JANE</first_name>
   <last_name>DOE</last_name>
   <middle_i>M</middle_i>
   <address1>147 OCEAN DR</address1>
   <address2>null</address2>
   <state_cd>MA</state_cd>
   <city>RIVERMOOR</city>
   <zip>01556</zip>
   <cntry_cd>840</cntry_cd>
   <telephone>3213213211</telephone>
   <mobile>null</mobile>
   <email_id>NOEMAIL@MYJOB.COM</email_id>
   <department>null</department>
   <title>null</title>
   <fax>5555555555</fax>
   <url>null</url>
   <country>UNITED STATES OF AMERICA</country>
   <state>MASSACHUSETTS</state>
   <customer_care_phone>3213213211</customer_care_phone>
</Contact>

So if they enter 100 Contacts then how in the world do I take a tag like <state> that occurs 100 times, parese it and make it unique and then return all the unique tags to some variable that I can then call on a completion page and present the information in a usable format…

I am currently trying to use this class….

Code:
<? 
/** 
* XMLToArray Generator Class 
* Purpose : Creating Hierarchical Array from XML Data 
*/ 

class XmlToArray 
{ 
    
    var $xml=''; 
    
    /** 
    * Default Constructor 
    * @param $xml = xml data 
    * @return none 
    */ 
    
    function XmlToArray($xml) 
    { 
       $this->xml = $xml;    
    } 
    
    /** 
    * _struct_to_array($values, &$i) 
    * 
    * This is adds the contents of the return xml into the array for processing. 
    * Recursive, Static 
    * 
    * @access    private 
    * @param    array  $values this is the xml data in an array 
    * @param    int    $i  this is the current location in the array 
    * @return    Array 
    */ 
    
    function _struct_to_array($values, &$i) 
    { 
        $child = array(); 
        if (isset($values[$i]['value'])) array_push($child, $values[$i]['value']); 
        
        while ($i++ < count($values)) { 
            switch ($values[$i]['type']) { 
                case 'cdata': 
                array_push($child, $values[$i]['value']); 
                break; 
                
                case 'complete': 
                    $name = $values[$i]['tag']; 
                    if(!empty($name)){ 
                    $child[$name]= ($values[$i]['value'])?($values[$i]['value']):''; 
                    if(isset($values[$i]['attributes'])) {                    
                        $child[$name] = $values[$i]['attributes']; 
                    } 
                }    
              break; 
                
                case 'open': 
                    $name = $values[$i]['tag']; 
                    $size = isset($child[$name]) ? sizeof($child[$name]) : 0; 
                    $child[$name][$size] = $this->_struct_to_array($values, $i); 
                break; 
                
                case 'close': 
                return $child; 
                break; 
            } 
        } 
        return $child; 
    }//_struct_to_array 
    
    /** 
    * createArray($data) 
    * 
    * This is adds the contents of the return xml into the array for easier processing. 
    * 
    * @access    public 
    * @param    string    $data this is the string of the xml data 
    * @return    Array 
    */ 
    function createArray() 
    { 
        $xml    = $this->xml; 
        $values = array(); 
        $index  = array(); 
        $array  = array(); 
        $parser = xml_parser_create(); 
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); 
        xml_parse_into_struct($parser, $xml, $values, $index); 
        xml_parser_free($parser); 
        $i = 0; 
        $name = $values[$i]['tag']; 
        $array[$name] = isset($values[$i]['attributes']) ? $values[$i]['attributes'] : ''; 
        $array[$name] = $this->_struct_to_array($values, $i); 
        return $array; 
		
    }//createArray 
    
    
}
?>

And it works well enough; it gives me huge nested arrays of the xml data….but I feel that there has to be a better way to do it…


Thanks….
 
>So if they enter 100 Contacts then how in the world do I take a tag like <state> that occurs 100 times, parese it and make it unique and then return all the unique tags to some variable that I can then call on a completion page and present the information in a usable format...

This is how you can get a unique return of possible "state".

[1] Add a function, say uniqueState() to the class, like this.
[tt]
function uniqueState() {
$xml=$this->xml;
$xml = simplexml_load_string($xml);
$result = $xml->xpath("//state[not(.=../preceding-sibling::Contact/state)]");
$a=array();
foreach ($result as $k=>$v) {
array_push($a,(string)$v);
}
return $a;
}
[/tt]
[2] Then suppose to create an instance of the class supplying certain string ($sxml) say, the result of uniqueState will then be displayed like this for simple inspection.
[tt]
[green]//$sxml given somewhere above[/green]

$x-new XmlToArray([green]$sxml[/green]);
print_r ($x->uniqueState());
[/tt]
 
Thanks for the reply and the sample code tsuji…

Just so that I am clear on this, for each tag that have multiple returns I will need to make a separate function for each. That is, using contacts again as the example, I would need 21 functions. If so I would have nearly 500 possible tags that are recycled through the return string ergo apx 500 functions to handle them?

On a follow-up 2nd question…

Using this method would I be able to set the array return values to a $_SESSION state, ($_SESSION[‘xmlReturn’][‘$key’] = ($val); ,where I can then pull, mix and match the way I would present the information to the completed page…

Thanks for your time and assistance...


 
[2'] First I get this out of the way. There is a typo.
[tt] $x[red]=[/red]new XmlToArray($sxml);[/tt]

[3] >Just so that I am clear on this, for each tag that have multiple returns I will need to make a separate function for each.
Of course not. Just construct the method taking in the node name. [1] uniqueState() is just to show you the big picture how. Such as this.
[tt]
function uniqueContactInfo($sname) {
$xml=$this->xml;
$xml = simplexml_load_string($xml);
$result = $xml->xpath("//".$sname."[not(.=../preceding-sibling::*/".$sname.")]");
$a=array();
foreach ($result as $k=>$v) {
array_push($a,(string)$v);
}
return $a;
}
[/tt]
[4] The return would be shown like this for you to see.
[tt]
$x=new XmlToArray($sxml);
print_r ($x->uniqueState());
print_r ($x->uniqueContactInfo("state"));
print_r ($x->uniqueContactInfo("first_name"));
[/tt]
 
hurmm,

Thanks for the clarification, I will get to work and see if I can pull this off…
 
Ok,
The rules of engagement have changed.

The person that handles the middleware that I get my response from is changing the way they reply still xml, however, no more nested groups/tags like <Contact>

It will be
<Response>
All the individual tags here
Incremented if they are repeating tags…

Exp.

<state_1></state_1>
<state-2></state_2>
Etc…

</Response>

This will allow me to put them all in to one single associative array…

So, this now brings up how the heck do I get this associative array in to a named session array…

$_SESSION[‘xmlResponse’][$key] = $val;

Using the same method of parsing above…


I am doing this to get it to print it to the page…

<?PHP
session_start();

require_once "class.xmltoarray.php";

//XML Data
$xml_data = " xml_string_loads_in_here ";

//Creating Instance of the Class
$xmlObj = new XmlToArray($xml_data);
//Creating Array
$arrayData = $xmlObj->createArray();

?>

Thanks!
 
>Incremented if they are repeating tags...
... that would be the most abominable design one can think of. Don't quote me and don't come back to ask why.
 
understand why.
But not my call as to what or how they want to do things the way they do. Such as building a massive db, this middleware app (for 2 years) and then ask the question of "Humm, now how do we get the info from the user..." not to mention that there were no business rules created, no user input as to what was actually needed. But then again isn't that how software is to be developed?

At any rate, Thanks for the help you have given tsuji.
I will plug along from here.

9
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top