I have to parse the data from XML file to CSV using PHP. I have written the code in PHP, it gets only few details and it does not extract the node's details if it has children. I am testing with smaller part of XML, the original file has very large amount of data around 20,000 person nodes. Below is my XML data --> list.xml.
<persons>
<person>
<id>326324</id>
<lastName>ABC</lastName>
<firstName>XYZ</firstName>
<middleName>PQR</middleName>
<preferredfirstName></preferredfirstName>
<details>
<JobTitle>Engineer</JobTitle>
<Dept>Healthcare</Dept>
<emp_position_no>PT0970</emp_position_no>
<emp_class_code>AJ</emp_class_code>
<emp_class_desc>Developer</emp_class_desc>
<emp_rank></emp_rank>
<CA_AddrStreet></CA_AddrStreet>
<CA_AddrCity></CA_AddrCity>
<CA_AddrState></CA_AddrState>
<CA_AddrZip></CA_AddrZip>
<CA_Phone></CA_Phone>
<EmployeeEmail>ABC@ABDA.COM</EmployeeEmail>
</details>
<Projects>
<subj_crse>MKTG 311</subj_crse>
<subj_crse>MKTG 428</subj_crse>
</Projects>
</person>
<person>
<id>956197</id>
<lastName>YTRG</lastName>
<firstName>WDES</firstName>
<middleName>BVCX</middleName>
<preferredfirstName></preferredfirstName>
<details>
<JobTitle>TECHNICIAN</JobTitle>
<Dept>Education</Dept>
<emp_position_no>PT1010</emp_position_no>
<emp_class_code>AJ</emp_class_code>
<emp_class_desc>Technician</emp_class_desc>
<emp_rank></emp_rank>
<CA_AddrStreet></CA_AddrStreet>
<CA_AddrCity></CA_AddrCity>
<CA_AddrState></CA_AddrState>
<CA_AddrZip></CA_AddrZip>
<CA_Phone></CA_Phone>
<EmployeeEmail>TRED@HDSEYY.COM</EmployeeEmail>
</details>
<Projects>
<subj_crse>TCHCS 321</subj_crse>
</Projects>
</person>
</persons>
I am able to retrieve the data till the node preferredfirstName and after that since details node has further children I am unable to extract the data. Below is my PHP code:
$xml = simplexml_load_file('list.xml');
$i = 1;
$values = [];
$columns = array('id', 'lastName', 'firstName',
'middleName', 'preferredfirstName', 'details', 'Projects');
$fs = fopen('ODU.csv', 'w');
fputcsv($fs, $columns);
fclose($fs);
$node = $xml->xpath('//person');
foreach ($node as $n) {
$child = $xml->xpath('//person['.$i.']/*');
foreach ($child as $value) {
$values[] = $value;
}
$fs = fopen('test.csv', 'a');
fputcsv($fs, $values);
fclose($fs);
$values = [];
$i++;
}
I need the output in CSV file with each node details under separate colums like below:
I never use simplexml
but I would guess you could easily accomplish the same thing using that rather than DOMDocument as below - I don't see, in this case, any real need for the XPath query - it's all quite straightforward XML. Hopefully you'll be able to make use of the following somehow.
$strxml='<persons>
<person>
<id>326324</id>
<lastName>ABC</lastName>
<firstName>XYZ</firstName>
<middleName>PQR</middleName>
<preferredfirstName></preferredfirstName>
<details>
<JobTitle>Engineer</JobTitle>
<Dept>Healthcare</Dept>
<emp_position_no>PT0970</emp_position_no>
<emp_class_code>AJ</emp_class_code>
<emp_class_desc>Developer</emp_class_desc>
<emp_rank></emp_rank>
<CA_AddrStreet></CA_AddrStreet>
<CA_AddrCity></CA_AddrCity>
<CA_AddrState></CA_AddrState>
<CA_AddrZip></CA_AddrZip>
<CA_Phone></CA_Phone>
<EmployeeEmail>ABC@ABDA.COM</EmployeeEmail>
</details>
<Projects>
<subj_crse>MKTG 311</subj_crse>
<subj_crse>MKTG 428</subj_crse>
</Projects>
</person>
<person>
<id>956197</id>
<lastName>YTRG</lastName>
<firstName>WDES</firstName>
<middleName>BVCX</middleName>
<preferredfirstName></preferredfirstName>
<details>
<JobTitle>TECHNICIAN</JobTitle>
<Dept>Education</Dept>
<emp_position_no>PT1010</emp_position_no>
<emp_class_code>AJ</emp_class_code>
<emp_class_desc>Technician</emp_class_desc>
<emp_rank></emp_rank>
<CA_AddrStreet></CA_AddrStreet>
<CA_AddrCity></CA_AddrCity>
<CA_AddrState></CA_AddrState>
<CA_AddrZip></CA_AddrZip>
<CA_Phone></CA_Phone>
<EmployeeEmail>TRED@HDSEYY.COM</EmployeeEmail>
</details>
<Projects>
<subj_crse>TCHCS 321</subj_crse>
</Projects>
</person>
</persons>';
$dom=new DOMDocument;
$dom->loadXML( $strxml );
/*
to load a file rather than a string of xml
------------------------------------------
$dom->load( realpath( 'list.xml' ) );
*/
/* file handles */
$output=__DIR__.'\odu.csv';
$tmp=tempnam( sys_get_temp_dir(), 'csv' );
$handle=fopen( $tmp, 'r+' );
$col=$dom->getElementsByTagName('person');
if( $col ){
foreach( $col as $person ){
if( $person->nodeType==XML_ELEMENT_NODE && $person->hasChildNodes() ){
/* arrays to hold data */
$row=array();
$cols=array();
foreach( $person->childNodes as $node ) {
if( $node->nodeType==XML_ELEMENT_NODE ){
if( $node->hasChildNodes() && $node->childNodes->length > 1 ) {
foreach( $node->childNodes as $detail ){
if( $detail->nodeType==XML_ELEMENT_NODE ) {
/* add values from details */
$row[ $detail->tagName ]=$detail->nodeValue;
/* add column headers / tagnames for nodes within details */
$cols[]=$detail->tagName;
}
}
} else {
$cols[]=$node->tagName;
$row[ $node->tagName ]=$node->nodeValue;
}
}
}
fputcsv( $handle, $row );
}
}
}
/* change handle to the final output file & truncate before writing */
$handle=fopen( $output, 'w+' );
/* add column headers */
fputcsv( $handle, $cols );
/* close file handle */
@fclose( $handle );
/* copy contents of temp file to output */
file_put_contents( $output, file_get_contents( $tmp ), FILE_APPEND );
/* delete temp file */
@unlink( $tmp );
$dom=$col=$person=$node=$handle=null;