2014-09-27 1 views
0

일부 요소가 있지만 정보가 다른 xml 파일이 있습니다.SimpleXML을 사용하여 여러 XML 파일을 하나의 CSV로 변환

먼저 파일 test.xml의

<?xml version="1.0" encoding="UTF-8"?> 
<phones> 
    <phone> 
     <title>"Apple iPhone 5S"</title> 
     <price> 
      <regularprice>500</regularprice> 
      <saleprice>480</saleprice> 
     </price> 
     <color>black</color> 
    </phone> 
</phones> 

두 번째 파일 test1.xml

<?xml version="1.0" encoding="UTF-8"?> 
<phones> 
    <phone> 
     <title>Nokia Lumia 830</title> 
     <price> 
      <regularprice>400</regularprice> 
      <saleprice>370</saleprice> 
     </price> 
     <color>black</color> 
    </phone> 
</phones> 
내가 1 개 test.csv 파일에이 XML 파일에서 일부 값을 변환 할 필요가

그래서이 PHP 코드를 사용하고 있습니다

,
<?php 

$filexml1='test.xml'; 
$filexml2='test1.xml'; 

    //File 1 
    if (file_exists($filexml1)) { 
     $xml = simplexml_load_file($filexml1); 
     $f = fopen('test.csv', 'w'); 

    $headers = array('title', 'color'); 
    $converted_array = array_map("strtoupper", $headers); 


    fputcsv($f, $converted_array, ',', '"'); 


    foreach ($xml->phone as $phone) { 

     //$phone->title = trim($phone->title, " "); 
     // Array of just the components you need... 
     $values = array(
      "title" => (string)$phone->title = trim(str_replace ("\"", "&quot;", $phone->title), " "), 
      "color" => (string)$phone->color 
     ); 
     fputcsv($f, $values,',','"'); 

    } 
    fclose($f); 

    echo "<p>File 1 coverted to .csv sucessfully</p>"; 
} else { 
    exit('Failed to open test.xml.'); 
} 

    //File 2 
    if (file_exists($filexml2)) { 
     $xml = simplexml_load_file($filexml2); 
     $f = fopen('test.csv', 'a'); 


    //the same code for second file like for the first file 

    echo "<p>File 2 coverted to .csv sucessfully</p>"; 
} else { 
    exit('Failed to open test1.xml.'); 
} 

?> 

test.csv의 출력이 방법

TITLE    COLOR 
Apple iPhone 5S black 
Nokia Lumia 830 black 

당신은 내가 유일한 변수에 각 파일을로드 관리 및 각 파일에 대해 내가 문은 스크립트를 만드는 경우 작성해야 볼 수있는 것처럼 보이는 너무 커서 xml 요소가 동일하고 하나의 .csv 파일로 출력되기 때문에 하나의 코드 블록으로 모든 파일을 배열로로드 할 수 있는지 궁금합니다. 기본적으로 적은 PHP 코드로만 동일한 test.csv 출력이 필요합니다.

미리 감사드립니다.

+2

네 당신이 그렇게 배열 내부의 파일 이름을 넣을 수는 루프 그들 각각, 마지막으로 결국 다음 배열 내에서 모든 정보를 보유하고하는 용기를 넣어 fputcsv 그들 모두 – Ghost

답변

1

배열을 사용하는 다음으로 PHP를 사용하면 훨씬 더 간단해질 수 있습니다. 배열이 파일 목록을 나타낼 수있는 것처럼 PHP의 다른 구조도 그렇게 할 수 있습니다.

$inputFiles = new GlobIterator(__DIR__ . '/*.xml'); 

당신은 할 수 : 당신은 가능성이 가장 가지고있는 XML 파일로 예를 들어

자신의 이름과 몇 가지 패턴에 따라 특정 디렉토리 안에있는 그는 쉽게 GlobIterator로 표현 될 수 그 다음에 다른 예제로 잠시 후에 보여줄 foreach입니다.

이러한 목록을 사용하면 처리 과정을 간소화 할 수 있습니다. 입력, 프로세스, 출력과 같은 많은 프로그램을위한 일종의 일반적인 공식이 있기 때문에 이것은 중요합니다. IPO 또는 IPO + S 모델이라고도합니다. S는 저장을 의미합니다. 입력 데이터를 처리하는 중에도 출력 (처리 완료 후) 인 새 파일 CSV 파일에 저장합니다.

이러한 일반 모델을 따르는 경우 코드 구조가 더 쉽고 구조가 좋으면 코드의 수가 적습니다. 그렇지 않은 경우에도 코드의 각 부분은 자급 자족하고 작아서 가장 자주 찾는 부분입니다. XML-파일의 상기 목록에

다음으로는 XML 데이터를 처리하는 데 도움이 될 수 있습니다 다른 반복자가있는 GlobIterator과 대답의 시작 부분에 보여 주었다.

예를 들어, 0-n <phone> 요소를 포함하는 1-n XML 파일이 있습니다.이 <phone> 요소를 처리하기를 원한다면 이미 정확히 (해당 데이터에서 일부 데이터 추출)을 알고 있습니다. 그렇다면 먼저 모든 XML 파일에 모든 <phone> 요소 목록을 포함시키는 것이 좋지 않을까요?

이것은 발전기의 도움으로 PHP로 쉽게 수행 할 수 있습니다. 그것은 여전히 ​​"실행 중"여러 번 값을 반환 할 수있는 함수입니다. 이는 단순화 된 것으로,이를 설명하는 코드를 더 잘 보여줍니다. 우리가 XML 파일의 목록을 입력으로 가지고 있다고 가정하고 모든 <phone> 요소를 빼내고 싶다고합시다. 확실히, 모든 <phone> 요소의 배열을 만들어 나중에 배열을 처리 할 수 ​​있습니다. 그러나, 발전기 직접 foreach 루프 내에서 사용되는 모든 <phone> 요소를 제공 할 수 있습니다 :, 본 실시 발전기 기능에서 볼 수 있듯이

function extract_phones(Traversable $files) { 
    foreach ($files as $file) { 
     $xml = simplexml_load_file($file); 
     if ($xml === false) { 
      continue; 
     } 
     foreach ($xml->phone as $phone) { 
      yield $phone; 
     } 
    } 
} 

그것을 모든 $files 넘어로로드하려고 a SimpleXMLElement이고 성공한 경우 모든 <phone> 요소를 반복하고 을 산출합니다. 귀하의 질문에 출력으로 CSV 파일을 만드는 방법에 대해 물어 그래서 지금

foreach(extract_phones($inputFiles) as $phone) { 
    # $phone is a SimpleXMLElement here 
} 

: 함수 extract_phonesforeach 내에서 호출되는 경우

즉, 그 루프는 SimpleXMLElement으로 모든 <phone> 요소가됩니다. 출력을 전달하고 처리하는 동안 액세스하려면 SplFileObject을 만들면됩니다. 기본적으로 파일 핸들을 전달하는 것과 같은 방식으로 작동합니다. 예를 들어 이지만은 나중에 더 쉽게 코드를 변경할 수 있습니다 (동일한 동작을하는 다른 객체로 바꿀 수 있음).

또한 코드에서 약간의 세부 사항을 먼저 보았습니다. 몇 가지 논의가 먼저 필요합니다. 따옴표를 HTML 엔터티로 인코딩합니다.

trim(str_replace("\"", "&quot;", $phone->title), " ") 

HTML 엔터티를 CSV 파일에 넣으려고 할 가능성이 높습니다. 그러나 CSV 파일에는 이러한 파일이 필요하지 않습니다. CSV 파일에있는 데이터를 가능한 한 일반적인 것으로하고 싶을 수도 있습니다. CSV 파일을 나중에 스프레드 시트 응용 프로그램이나 HTML 컨텍스트에서 사용할지 여부는 파일 형식을 변환 할 때 걱정할 필요가 없습니다. 내 제안은 그것을 버리고 다른 곳에서 처리하는 것입니다. 이 장소가 더 많이 속하고 나중에는 예를 들어 일부 HTML을 만드는 CSV의 데이터를 사용하는 경우

변환 및 데이터를 깨끗하게 유지하고 코드를 더 복잡하게 할뿐만 아니라 프로그램에 결함을 도입하는 장소 인 처리의 세부 장소를 제거합니다.

나 자신을 위해 내 예제에서 제거됩니다.모든 XML 파일에서 모든 전화를 확인하고 출력 CSV 파일로 관심 분야 저장 :

그럼 모두 함께이를 만들어 보자없이 (

$files = new GlobIterator(__DIR__ . '/*.xml'); 
$phones = extract_phones($files); 

$output = new SplFileObject('file.csv', 'w'); 
$output->fputcsv($header = ["title", "color"]); 

foreach ($phones as $phone) { 
    $output->fputcsv(
     [ 
      $phone->title, 
      $phone->color, 
     ] 
    ); 
} 

이것은 당신이 찾고있는 출력 파일을 만듭니다 HTML 엔터티) :

title,color 
"""Apple iPhone 5S""",black 
"Nokia Lumia 830",black 

이 모든 요구 사항은 이미 위에서 설명한 발전기 기능이기 때문에 직접 작성된 코드도 있습니다. 다른 모든 것들은 이미 PHP와 함께 제공됩니다. 여기에 전체의 예제 코드 :

<?php 
/** 
* @link http://stackoverflow.com/questions/26074850/convert-multiple-xml-files-to-csv-with-simplexml 
*/ 

function extract_phones(Traversable $files) 
{ 
    foreach ($files as $file) { 
     $xml = simplexml_load_file($file); 
     if ($xml === false) { 
      continue; 
     } 
     foreach ($xml->phone as $phone) { 
      yield $phone; 
     } 
    } 
} 

$files = new GlobIterator(__DIR__ . '/*.xml'); 
$phones = extract_phones($files); 

$output = new SplFileObject('file.csv', 'w'); 
$output->fputcsv($header = ["title", "color"]); 

foreach ($phones as $phone) { 
    $output->fputcsv(
     [ 
      $phone->title, 
      $phone->color, 
     ] 
    ); 
} 

echo file_get_contents($output->getFilename()); 
+0

답장과 모든 것을 지우는 데 감사 드리는 @hakre. 그것은 매우 유용합니다. –

+0

이것에 대해 설명해 주셔서 감사합니다.하지만 정말로 필요한 모든 작업은 파일 이름에 대한 또 다른 반복입니다. – DanMan

+0

@DanMan : 실제로 코드로 복잡성을 줄이는 것을 목표로 삼았습니다. 그것은 일반적으로 오버 엔지니어링의 반대입니다 .... – hakre

0

고맙습니다. 올바른 방향으로 안내해 주셔서 감사합니다. 그래서 여기에 내 해결책이있다.

<?php 

$filexml = array ('test.xml', 'test1.xml'); 


//Headers 
$fp = fopen('file.csv', 'w'); 

$headers = array('title', 'color'); 
$converted_array = array_map("strtoupper", $headers); 


fputcsv($fp, $converted_array, ',', '"'); 


//XML 
foreach ($filexml as $file) { 
    if (file_exists($file)) { 
     $xml = simplexml_load_file($file); 

     foreach ($xml->phone as $phone) { 
     $values = array(
       "title" => (string)$phone->title = trim(str_replace ("\"", "&quot;", $phone->title), " "), 
       "color" => (string)$phone->color 
      ); 
      fputcsv($fp, $values, ',', '"'); 
     } 
     echo $file . ' converted to .csv sucessfully' . '<br>'; 
    } else { 
     echo $file . ' was not found' . '<br>'; 
    } 


} 

fclose($fp); 

?>