2017-01-30 8 views
0

XML을 CSV로 변환하려고합니다. 괜찮습니다. 그러나 일부 itens에서는 다른 필드보다 필드가 적거나 필드 수가 적습니다.XML로 CSV를 PHP로 변환하고 일부 필드에 다른 필드가있는 경우

내 피드의 예는 다음과 같습니다

편집 : 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 개발자가 아니며 이것을 해결하기가 어렵습니다. 나는 여기서 찾으려고했지만, 내 것과 같은 문제는 찾지 못했습니다.

감사

+0

귀하의 XML 형식이 올바르지 않습니다 (즉, 유효하지 않습니다). [XML 1.0의 W3C 네임 스페이스] (https://www.w3.org/TR/REC-xml-names/#ns-using)에 따르면 : xml이나 xmlns가 아닌 네임 스페이스 접두사는 반드시 있어야합니다. 네임 스페이스 선언 특성 *에서 선언되었습니다. 그래서'g' 접두사는 조상이나 현재 태그에서 선언되어야합니다. – Parfait

+0

이것은 파일 시작 부분에 있습니다.

+0

매우 중요한 라인입니다! XML 질문에서 루트를 버리지 마십시오. XPath의 경우 네임 스페이스를 등록해야합니다. 그렇다면''는 뿌리의 자식입니까? 댓글이 아닌 실제 XML에 대한 소식을 업데이트하십시오. – Parfait

답변

1

당신이 /*으로 XPath 식으로 모든 항목의 아이들을 열 이름을 전달 곳 간단하게 당신이 CSV 헤더에 사용하는 columns 배열을 반복. 반환 된 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 호출 용으로 사용할 수 있습니다.

+0

많은 감사합니다 @ Parfait, 매력처럼 작동합니다. 유일한 문제는 이제 내 서버 (브라질의 Hostinger의 파트너)가 시간 초과를 제공하지만 ... 귀하의 스크립트와 관련이 없습니다. –

+0

안녕하세요 @Parfait, 지금 리눅스에서 실행 중이며 오류가 표시 될 수 있습니다 : 'PHP 알림 :/home/ec2-user/cron3에 정의되지 않은 오프셋 : 0.php on line 25' 마지막 줄부터 생각해 봅니다 :'$ values ​​[] = trim ($ xml-> xpath ('. $ i.'] /'.$ col) [0]);'. 이 문제를 해결하는 데 도움을 줄 수 있습니까? –

+0

특정 xpath와 같은 사운드는 특정 노드에서 비어 있습니다. 배열에 추가하기 전에'if'로 검사해야 할 수도 있습니다. 업데이트를 참조하십시오. – Parfait