【问题标题】:Convert xml to csv in Nth level using php使用php将xml转换为第N级的csv
【发布时间】:2017-05-10 06:54:17
【问题描述】:

您好,我正在处理需要将 xml 转换为 csv 文件的操作

下面是我的xml文件格式。

<CatalogLine>
            <Item>
               <ItemID agencyRole="MasterProductNumber">
                  <ID>11802</ID>
               </ItemID>
               <ItemID agencyRole="Prefix_Number">
                  <ID>FOL</ID>
               </ItemID>
               <ItemID agencyRole="Stock_Number">
                  <ID>00374EA</ID>
               </ItemID>
            </Item>
            <UOMCode>EA</UOMCode>
            <ItemPrice>
               <UnitPrice>
                  <Amount currencyID="USD">0</Amount>
                  <PerQuantity unitCode="EA">1</PerQuantity>
                  <Code>Catalog_List_Amount</Code>
               </UnitPrice>
            </ItemPrice>
            <Note type="Page_Number">5</Note>
</CatalogLine>

500 多次相同。

所以我需要csv 中的所有数据,比如

MasterProductNumber Prefix_Number   Stock_Number    UOMCode Amount  PerQuantity Code                    Page_Number 
11802               FOL             00374EA         EA      0       1           Catalog_List_Amount     5

下面的代码我试过了:

<?php

$filexml='ddsource.xml';
if (file_exists($filexml))  {

   $xml = simplexml_load_file($filexml);
   $i = 1;           // Position counter
   $values = [];     // PHP array

   // Writing column headers
   $columns = array('MasterProductNumber','Prefix_Number','Stock_Number','UOMCode','Amount','PerQuantity','Code','Page_Number');

   $fs = fopen('ddsource1.csv', 'w');
   fputcsv($fs, $columns);      
   fclose($fs);

   // Iterate through each <item> node
   $node = $xml->xpath('//CatalogLine');

   foreach ($node as $n) {           

       // Iterate through each child of <item> node
       $child = $xml->xpath('//CatalogLine['.$i.']/*');      

       foreach ($child as $value) {
          $values[] = $value;         
       }

       // Write to CSV files (appending to column headers)
       $fs = fopen('ddsource1.csv', 'a');
       fputcsv($fs, $values);      
       fclose($fs);  

       $values = [];    // Clean out array for next <item> (i.e., row)
       $i++;            // Move to next <item> (i.e., node position)
   }
}
?>

但它只给主节点值: UOMCode - EA 注意 - 5

我需要所有的价值观。

请帮助我在哪里犯了错误。

【问题讨论】:

  • 你有这个XML 还是一个例子?
  • 是有它的实际xml
  • 希望我的解决方案能帮到你..
  • @SahilGulati 如果我需要从 xml 文件加载内容怎么办?
  • 我已经更新了我的帖子,你可以检查 cmets.. 你可以像这样加载字符串 $string= file_get_contents("/path/to/file.txt");

标签: php xml csv


【解决方案1】:
$xml='<?xml version="1.0" encoding="UTF-8"?>
        <root>
            <CatalogLine>
                <Item>
                   <ItemID agencyRole="MasterProductNumber">
                      <ID>11802</ID>
                   </ItemID>
                   <ItemID agencyRole="Prefix_Number">
                      <ID>FOL</ID>
                   </ItemID>
                   <ItemID agencyRole="Stock_Number">
                      <ID>00374EA</ID>
                   </ItemID>
                </Item>
                <UOMCode>EA</UOMCode>
                <ItemPrice>
                   <UnitPrice>
                      <Amount currencyID="USD">0</Amount>
                      <PerQuantity unitCode="EA">1</PerQuantity>
                      <Code>Catalog_List_Amount</Code>
                   </UnitPrice>
                </ItemPrice>
                <Note type="Page_Number">5</Note>
            </CatalogLine>
            <CatalogLine>
                <Item>
                   <ItemID agencyRole="MasterProductNumber">
                      <ID>12803</ID>
                   </ItemID>
                   <ItemID agencyRole="Prefix_Number">
                      <ID>FOL</ID>
                   </ItemID>
                   <ItemID agencyRole="Stock_Number">
                      <ID>00374FA</ID>
                   </ItemID>
                </Item>
                <UOMCode>EP</UOMCode>
                <ItemPrice>
                   <UnitPrice>
                      <Amount currencyID="USD">34</Amount>
                      <PerQuantity unitCode="EA">1</PerQuantity>
                      <Code>Catalog_List_Amount</Code>
                   </UnitPrice>
                </ItemPrice>
                <Note type="Page_Number">5</Note>
            </CatalogLine>
            <CatalogLine>
                <Item>
                   <ItemID agencyRole="MasterProductNumber">
                      <ID>15603</ID>
                   </ItemID>
                   <ItemID agencyRole="Prefix_Number">
                      <ID>WKI</ID>
                   </ItemID>
                   <ItemID agencyRole="Stock_Number">
                      <ID>45374FA</ID>
                   </ItemID>
                </Item>
                <UOMCode>XY</UOMCode>
                <ItemPrice>
                   <UnitPrice>
                      <Amount currencyID="UKP">69</Amount>
                      <PerQuantity unitCode="EA">36</PerQuantity>
                      <Code>Catalog_List_Amount</Code>
                   </UnitPrice>
                </ItemPrice>
                <Note type="Page_Number">42</Note>
            </CatalogLine>
        </root>';


    libxml_use_internal_errors( true );
    $dom=new DOMDocument;
    $dom->validateOnParse=false;
    $dom->standalone=true;
    $dom->strictErrorChecking=false;
    $dom->recover=true;
    $dom->formatOutput=false;

    $dom->loadXML( $xml );
    $errors=serialize( libxml_get_last_error() );
    libxml_clear_errors();

    $cats=$dom->getElementsByTagName('CatalogLine');




    if( !empty( $cats ) && $cats->length > 0 ){
        /* column headers for use in csv */
        $columns = array(
            'MasterProductNumber',
            'Prefix_Number',
            'Stock_Number',
            'UOMCode',
            'Amount',
            'PerQuantity',
            'Code',
            'Page_Number'
        );
        /* output file location */
        $file=__DIR__ . '/so_csv.csv';

        /* placeholder array to store results for later writing to csv */
        $data=array();

        foreach( $cats as $cat ){

            $item=$cat->childNodes->item(1);
            $ip=$cat->childNodes->item(5);
            $note=trim( $cat->childNodes->item(7)->nodeValue );
            $up=$ip->childNodes->item(1);

            $uom=trim( $cat->childNodes->item(3)->nodeValue );
            $amount=trim( $up->childNodes->item(1)->nodeValue );
            $qty=trim( $up->childNodes->item(3)->nodeValue );
            $code=trim( $up->childNodes->item(5)->nodeValue );

            /* get a list of ItemIDs*/
            $colitems=$item->getElementsByTagName('ItemID');
            foreach( $colitems as $itemid ){
                if( $itemid->hasAttribute( 'agencyRole' ) ){
                    /*
                        Assign each as a variable variable - these then match
                        the column values [0-2]
                    */
                    ${$itemid->getAttribute( 'agencyRole' )}=trim( $itemid->nodeValue );
                }
            }

            /*
                Generate an array with the values found from querying the XML
            */
            $data[]=array(
                $columns[0] =>  ${$columns[0]},
                $columns[1] =>  ${$columns[1]},
                $columns[2] =>  ${$columns[2]},
                $columns[3] =>  $uom,
                $columns[4] =>  $amount,
                $columns[5] =>  $qty,
                $columns[6] =>  $code,
                $columns[7] =>  $note
            );
        }
        /*
            Write the headers and csv data to file
        */
        if( !empty( $data ) ){
            $f = fopen( $file, 'w' );
            fputcsv( $f, $columns );
            foreach($data as $arr)fputcsv($f,$arr);
            fclose($f);

            echo count( $data ) . ' lines added to ' . $file;
        }
    }
    $dom=null;

【讨论】:

  • 但我需要从 xml 文件中获取内容!!使用您的代码我无法从 xml 文件中获取内容。如果我粘贴你的整个代码,那么它可以工作,但无法从 xml 文件中获取
  • 谢谢!!!主要是你的回答对我有帮助,我仍然需要一些捷径操作。
【解决方案2】:

我没有测试它,因为我写得很快。看看这个例子,它可能有用。

$xml_content_payload = '
    <CatalogLine>
        <Item>
            <ItemID agencyRole="MasterProductNumber">
                <ID>11802</ID>
            </ItemID>
            <ItemID agencyRole="Prefix_Number">
                <ID>FOL</ID>
            </ItemID>
            <ItemID agencyRole="Stock_Number">
                <ID>00374EA</ID>
            </ItemID>
        </Item>
        <UOMCode>EA</UOMCode>
        <ItemPrice>
            <UnitPrice>
                <Amount currencyID="USD">0</Amount>
                <PerQuantity unitCode="EA">1</PerQuantity>
                <Code>Catalog_List_Amount</Code>
            </UnitPrice>
        </ItemPrice>
        <Note type="Page_Number">5</Note>
    </CatalogLine>';

$xml_reader = new \XMLReader();
$xml_reader->xml($xml_content_payload); // use the $xml_reader->open('file.xml'); to open a file

//this loop reads node by node from xml file/payload
while ($xml_reader->read()) {
    if ($xml_reader->nodeType === \XMLReader::ELEMENT && $xml_reader->name === 'CatalogLine') { //put your name of node what you want to catch
        $element = simplexml_load_string($xml_reader->readOuterXml());
        // ..process your element
        // as $element you have \SimpleXMLElement::class object with all CatalogLine's childrens
        $xml_reader->next();
    }
}

这是清除读取非常大的 xml 文件并逐个节点处理它们的最佳方法

我希望我有所帮助。祝你好运!

【讨论】:

    【解决方案3】:

    此解决方案适用于 OP 提供的特定字符串。

    Try this code snippet here

    <?php
    
    ini_set('display_errors', 1);
    $string='<CatalogLine>
                <Item>
                   <ItemID agencyRole="MasterProductNumber">
                      <ID>11802</ID>
                   </ItemID>
                   <ItemID agencyRole="Prefix_Number">
                      <ID>FOL</ID>
                   </ItemID>
                   <ItemID agencyRole="Stock_Number">
                      <ID>00374EA</ID>
                   </ItemID>
                </Item>
                <UOMCode>EA</UOMCode>
                <ItemPrice>
                   <UnitPrice>
                      <Amount currencyID="USD">0</Amount>
                      <PerQuantity unitCode="EA">1</PerQuantity>
                      <Code>Catalog_List_Amount</Code>
                   </UnitPrice>
                </ItemPrice>
                <Note type="Page_Number">5</Note>
    </CatalogLine>';
    //optionally you can load string like this
    //$string=  file_get_contents("/path/to/file.txt");
    $object= simplexml_load_string($string);
    $headers=array();
    $values=array();
    foreach($object->Item->ItemID as $key => $items)
    {
        $headers[]=(string)$items["agencyRole"];
    }
    foreach($object->Item->ItemID as $key => $items)
    {
        $values[]=(string)$items->ID;
    }
    foreach((array)$object->ItemPrice->UnitPrice as $key => $value)
    {
        $headers[]=$key;
        $values[]=$value;
    }
    
    $headers[]=(string)$object->Note["type"];
    $values[]=(string)$object->Note;
    
    print_r(array($headers,$values));
    

    输出:

    Array
    (
        [0] => Array
            (
                [0] => MasterProductNumber
                [1] => Prefix_Number
                [2] => Stock_Number
                [3] => Amount
                [4] => PerQuantity
                [5] => Code
                [6] => Page_Number
            )
    
        [1] => Array
            (
                [0] => 11802
                [1] => FOL
                [2] => 00374EA
                [3] => 0
                [4] => 1
                [5] => Catalog_List_Amount
                [6] => 5
            )
    
    )
    

    【讨论】:

    • 谢谢!!!主要是你的回答对我有帮助,我仍然需要一些短途操作。
    猜你喜欢
    • 2017-12-14
    • 2013-06-10
    • 1970-01-01
    • 1970-01-01
    • 2022-06-13
    • 2019-02-02
    • 2017-05-23
    相关资源
    最近更新 更多