Link to home
Start Free TrialLog in
Avatar of Phonebuff
PhonebuffFlag for United States of America

asked on

Need help with parsing XML file into CSV format using a PHP script -

I am trying to build a PHP script to parse a rather complex XML document and output CSV data for certain names spaces within the document - But my simple code just to get the basic construct decoded is not working.  This is my first effort in this space hope someone here might see the error of my ways and help a little -- 


My Code looks like this right now -- Generating 

L1 config L2 category L3 set L4 collection L5 set L5  


<?php
$filexml='contacts_20211226.xml';     if (file_exists($filexml))            {     echo "File name: ", $filexml ;     echo "\n" ;        $xml = simplexml_load_file($filexml);        if ($xml === false) {         echo "Failed loading XML: ";          foreach(libxml_get_errors() as $error) {          echo $error->message;          echo "\n" ;          }        }        $f = fopen('test.csv', 'w');        createCsv($xml, $f);        fclose($f);     } else {     echo "No File name: ", $filexml ;     echo "\n" ;     }     function createCsv($xml,$f)
    {         $l1Name = $xml->getName() ;         echo 'L1 ' . $l1Name ;         echo "\n" ;         foreach ($xml->children() as $second_gen) {         $l2Name = $second_gen->getName() ;             echo 'L1 ' . $l1Name ;                  ' L2 ' . $l2Name ;             echo "\n" ;             foreach ($second_gen->children() as $third_gen) {                 $l3Name = $third_gen->getName() ;                 echo 'L1 ' . $l1Name ;                      ' L2 ' . $l2Name ;                      ' L3 ' . $l3Name ;                 echo "\n" ;                 foreach ($third_gen->children() as $fourth_gen) {                 $l4Name = $fourth_gen->getName() ;                     echo 'L1 ' . $l1Name .                          ' L2 ' . $l2Name .                          ' L3 ' . $l3Name .                          ' L4 ' . $$l4name ;                     echo "\n" ;                         foreach ($fourth_gen->children() as $fifth_gen) {                         $l5Name = $fifth_gen->getName() ;                             echo 'L1 ' . $l1Name .                                  ' L2 ' . $l2Name .                                  ' L3 ' . $l3Name .                                  ' L4 ' . $l4Name .                                  ' L5 ' . $l5Name .                                  ' L5 ' . $fifth_gen ;                             echo "\n" ;                         }                 }             }          }     } ?>

Open in new window

  But this will not output the that I expect --- For example -- 


I get this as output But never see the values in name=" " or the actual data elements.

L1 config L2 category L3 set L4  where as I would like to see 

L1 config L2 catergory "PCRContacts" L3 set "PCRContacts" alias "Talk-around"  L4 field .......... L5 collection ....  


<?xml version="1.0" encoding="utf-8" standalone="yes"?>
L1 = <config>
L2 =   <category name="PCRContacts">

L3 =     <set name="PCRContacts" alias="Talk-around">
L4 =      <field name="ContactName">Talk-around</field>

L5 =       <collection name="MDCCalls" />
L5 =       <collection name="QuikCallIICalls" />
L5 =      <collection name="DigitalCalls">
L6 =        <set name="DigitalCalls" index="0" key="GRPCALL">:q!
 L7 =           <field name="DU_CALLALIAS">Talk-around</field>
          <field name="DU_CALLLSTID">10000</field>
          <field name="DU_ROUTETYPE" Name="Regular">REGULAR</field>
          <field name="DU_CALLPRCDTNEN">False</field>
          <field name="DU_RINGTYPE" Name="No Style">NOSTYLE</field>
          <field name="DU_TXTMSGALTTNTP" Name="Repetitive">REPETITIVE</field>
          <field name="DU_CALLTYPE" Name="Group Call">GRPCALL</field>
          <field name="DU_OVCMCALL">False</field>
          <field name="DU_CALLTYPEPART2">0</field>
          <field name="DU_UKPOTCFLG">False</field>
          <field name="DU_RVRTPERS_Zone" Name="None">NONE</field>
          <field name="DU_RVRTPERS" Name="Selected">SELECTED</field>
          <field name="CallType">Digital Calls-Group Call</field>
          <field name="PeudoCallId">10000</field>
 L6 =       </set>
 L5 =     </collection>
      <collection name="CapacityPlusCalls" />
      <collection name="PhoneCalls" />
      <field name="Comments"></field>


Avatar of David Johnson, CD
David Johnson, CD
Flag of Canada image

Avatar of Phonebuff

ASKER

David,  am I missing something -- I thought I did start by pulling the file into the array $xml.

  -- $xml = simplexml_load_file($filexml);
 
The problem I seem to have is processing each element of the array with the Children(), getName() and some function I don't seem to be aware of to get the various parts of the line. Maybe I should forget it's XML and just use an awk script to take it apart.  Also, it might be more HTML than XML the more I look at it.
   
ASKER CERTIFIED SOLUTION
Avatar of Chris Stanyon
Chris Stanyon
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

Chris,

    THANK YOU --  That all makes sense. One question in my mind before I go try and take this object apart again, is there any way through the functions available to know that I am working Level 3 verses Level 6 in the tree ??  

    As to where I am trying to get to, buried n levels into this document is some data that I am trying to extract to reconcile against an LDAP for the organization.  It's been done by hand previously but it is time to try and automate it and by doing so reconcile more often !  


No worries :)

Firstly, not really. The concept of Levels doesn't usually apply to XML - that's just something that you've called it. I guess technically, you could keep track of it, as you drop further down the tree. You could also call the xpath method with parent to work out where you're at.

The more standardised your XML document is, the easier it will be to code. If you KNOW for certain that the data you need will ALWAYS be in a given Node, then you can generally access it directly, eiter through object properties, or with xpath expressions.

For example:

// Object Properties
// Loop through the children of the <set name="PCRContacts"> node
foreach ($xml->category[0]->set->children() as $element) {
  echo $element->getName() . '|' . $element['name'] . PHP_EOL;
}

// XPath
// Loop through all the <field> elements that are children of the <set name="DigitalCalls"> node
$fields = $xml->xpath("//config/category/set/collection/set[@name='DigitalCalls']/field");
foreach ($fields as $field) {
  echo $field['name'] . '|' . $field . PHP_EOL;
}

Open in new window


Thank you --  Will look at this over the Holiday Weekend..  

Happy, Safe and Healthy New year !

Chris,

    I am almost there -- But how do I test for the presence of a value --

"To read the value, you just output the variable"  works fine if there is a value such as -
  <field name="ContactName" alias="SomethingElse">Talk-around</field>  

But if there is no value, I get garbage in the echo. I thought that either isset() or is_string() would be the answer but neither seem to help in determining when there is a value verses no value in the XML statement such as -
  <collection name="MDCCalls" />

Thanks..