【问题标题】:Not getting all the nodes data when parsing XML to CSV using PHP使用 PHP 将 XML 解析为 CSV 时未获取所有节点数据
【发布时间】:2016-05-04 17:42:03
【问题描述】:

我必须使用 PHP 将 XML 文件中的数据解析为 CSV。我用 PHP 编写了代码,它只得到很少的细节,如果它有子节点,它不会提取节点的细节。我正在使用 XML 的一小部分进行测试,原始文件包含大量数据,大约 20,000 个人节点。下面是我的 XML 数据 --> 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>

我能够检索到节点 preferredfirstName 之前的数据,之后由于 details 节点有更多的子节点,我无法提取数据。以下是我的 PHP 代码:

   $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++;            
   }

我需要 CSV 文件中的输出,每个节点详细信息位于单独的列下,如下所示:

【问题讨论】:

    标签: php xml csv


    【解决方案1】:

    我从不使用simplexml,但我猜你可以使用它而不是下面的 DOMDocument 轻松完成相同的事情 - 在这种情况下,我看不到对 XPath 查询的任何真正需要 - 这一切都非常简单XML。希望您能够以某种方式使用以下内容。

    $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;
    

    【讨论】:

    • 我所考虑的数据是非常大数据的一部分。所以我必须将其视为一个单独的文件。
    • 没问题,您可以轻松加载 xml 文件 - 请参阅上面的更改
    • 如果xml中的数据是动态变化的,那么这样就不行了,因为每次我们都不能手动加载xml文件。
    • DOMDocument 允许您像使用 simple_xml 一样加载 xml 文件,因此在这方面应该没有区别。我提供以上内容只是为了展示使用DOMDocument 可以轻松完成它 - 毫无疑问,熟悉simple_xml 的其他人可能会指出您的原始文件无法返回子节点的问题
    • 谢谢!我需要将数据保存在 csv 文件中。那怎么办?
    猜你喜欢
    • 1970-01-01
    • 2012-12-30
    • 2019-04-19
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    相关资源
    最近更新 更多