0

我想将 XML 转换为 CSV。没关系,但在某些项目中,我的字段比其他项目多或少。

我的提要的一个例子是:

编辑: XML 的顶部是:

<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
<channel>
<item>

字段较少的项目:

<item>
<title>
<![CDATA[
Resident Evil Revelations 2: Raid Mode: Throwback Map Pack
]]>
</title>
<link>
https://www.nuuvem.com/item/resident-evil-revelations-2-raid-mode-throwback-map-pack
</link>
<description>
<![CDATA[
Novas missões do modo raide! 4 mapas nostálgicos de locais icônicos, como o Queen Zenobia, do Resident Evil Revelations. 3 níveis de dificuldade oferecem um total de 12 novas missões.
]]>
</description>
<g:availability>out of stock</g:availability>
<g:price currency="BRL">9.99</g:price>
<g:image_link>
http://dskhvldhwok3h.cloudfront.net/image/upload/t_boxshot_big/v1/products/5584854f69702d7235000025/boxshots/j6qaxbrhowfkijd5zdg8.jpg
</g:image_link>
<g:product_type>
<![CDATA[ Action ]]>
</g:product_type>
<g:google_product_category>Software > Video Game Software > Computer Games</g:google_product_category>
<g:condition>new</g:condition>
<g:identifier_exists>FALSE</g:identifier_exists>
<g:id>11985</g:id>
</item>

具有最常见字段的项目:

<item>
<title>
<![CDATA[ Tom Clancys Rainbow Six - SIEGE: Gemstone Bundle ]]>
</title>
<link>
https://www.nuuvem.com/bundle/tom-clancy-s-rainbow-six-siege-gemstone-bundle
</link>
<description>
<![CDATA[ ]]>
</description>
<g:availability>in stock</g:availability>
<g:price currency="BRL">38.99</g:price>
<g:image_link>
http://dskhvldhwok3h.cloudfront.net/image/upload/t_boxshot_big/v1/products/573ded74f372803be9006b35/boxshots/l8ypqwhq48jzbxogypeh.jpg
</g:image_link>
<g:product_type>
<![CDATA[ Bundle ]]>
</g:product_type>
<g:google_product_category>Software > Video Game Software > Computer Games</g:google_product_category>
<g:condition>new</g:condition>
<g:identifier_exists>FALSE</g:identifier_exists>
<g:id>12705</g:id>
</item>

具有更多字段的项目:

<item>
<title>
<![CDATA[ Far Cry 4 - Gold Edition ]]>
</title>
<link>https://www.nuuvem.com/item/far-cry-4-gold-edition</link>
<description>
<![CDATA[
You are a gun for hire, trapped in a war-torn African state, stricken with malaria and forced to make deals with corrupt warlords on both sides of the conflict in order to make this country your home. You must identify and exploit your enemies' weaknesses, neutralizing their superior numbers and firepower.
]]>
</description>
<g:availability>in stock</g:availability>
<g:price currency="BRL">129.99</g:price>
<g:sale_price currency="BRL">64.99</g:sale_price>
<g:sale_price_effective_date>
2017-01-26T02:00:00+00:00/2017-01-31T01:59:00+00:00
</g:sale_price_effective_date>
<g:image_link>
http://dskhvldhwok3h.cloudfront.net/image/upload/t_boxshot_big/v1/products/557dbc5369702d0a9c57e600/boxshots/ld6c69odlluoerzmwyga.jpg
</g:image_link>
<g:product_type>
<![CDATA[ Action ]]>
</g:product_type>
<g:google_product_category>Software > Video Game Software > Computer Games</g:google_product_category>
<g:condition>new</g:condition>
<g:identifier_exists>FALSE</g:identifier_exists>
<g:id>2246</g:id>
</item>

我正在使用脚本进行转换,它可以工作,但是当项目的字段比最常见的项目类型更多或更少时,它就会出错。

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

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

   // Writing column headers
   $columns = array('title', 'link', 'description', 'availability', 'price', 'image_link', 'product_type', 'google_product_category', 'condition', 'identifier_exists', 'id');

   $fs = fopen('nuuvem-merchant.csv', 'w');
   fputcsv($fs, $columns);      
   fclose($fs);

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

   foreach ($node as $n) {           

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

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

       // Write to CSV files (appending to column headers)
       $fs = fopen('nuuvem-merchant.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)
   }
}

使用此脚本,我始终可以按顺序排列每个项目的字段。正因为如此,数据多次与列的标题不匹配,并且一些字段较多的项目因此没有标题。

抱歉,我不是 PHP 开发人员,我很难解决这个问题。我试图在这里搜索,但没有找到像我这样的问题。

谢谢

4

1 回答 1

2

只需迭代columns用于 CSV 标题的数组,在该数组中,您将列名传递给XPath表达式,而不是所有项目的子项/*。要选择返回的 XPath 数组的第一项,[0]使用索引并删除空格trim()

此外,您将需要注册命名空间前缀g来访问这些元素(因此命名空间对于始终包含在发布的 XML 片段中很重要):

$filexml = 'GoogleProductFeed.xml';
$xml = simplexml_load_file($filexml);
$xml->registerXPathNamespace('g', 'http://base.google.com/ns/1.0');

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

   // Writing column headers
   $columns = array('title', 'link', 'description', 'g:availability', 'g:price', 'g:image_link', 'g:product_type',
                    'g:google_product_category', 'g:condition', 'g:identifier_exists', 'g:id');

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

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

   foreach ($node as $n) {               
       // Iterate through each child of <item> node
       foreach ($columns as $col) {         
           if (count($xml->xpath('//item['.$i.']/'.$col)) > 0) {
              $values[] = trim($xml->xpath('//item['.$i.']/'.$col)[0]);
           } else {
              $values[] = '';
           }    
       }    
       // Write to CSV files (appending to column headers)
       $fs = fopen('GoogleProductFeed.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)
   }
}

请注意,列标题将具有g:这些适用列的前缀。也许使用两个几乎相同的数组,一个用于标头,另一个用于 XPath 调用。

于 2017-01-31T03:39:34.933 回答