0

I have a text file generated by a device which provides me the data in this form:

Rajeet Singh|email@gmail.com|0123456789|Delhi  
Abhishek|email2@gmail.com|0123456987|Pune

I want to extract the data from the text file and convert it into XML form as shown below:

<user>
<item0>
<name>Rajeet</name>
<email>email@gmail.com</email>
<mobile>0123654789</mobile> 
<address>Delhi</address>
</item0>
<item1>
<name>Abhishek</name>
<email>email@gmail.com</email>
<mobile>0123654789</mobile> 
<address>Pune</address>
</item1>   
</user>

This is what I have done so far.

I have extracted the data from the text file and converted into an array.

$fh=fopen('file/dat.txt','r');
$xml = new SimpleXMLElement('<user></user>');

while($line=fgets($fh)){
  $line_arr=explode('|',$line);
}

And converted a static valued array to xml like this:

$users_array = array(
        array(
            "name" => "Rajeet",
            "email" => "email@gmail.com",
            "mobile" => "0123654789",
            "address" => "Delhi",
        ),
        array(
            "name" => "Abhishek",
            "email" => "email@gmail.com",
            "mobile" => "0123654789",
            "address" => "Pune",
        )
);
print_r($users_array);
//function defination to convert array to xml
function array_to_xml($array, &$xml_user_info) {
    foreach($array as $key => $value) {
        if(is_array($value)) {
            if(!is_numeric($key)){
                $subnode = $xml_user_info->addChild("$key");
                array_to_xml($value, $subnode);
            }else{
                $subnode = $xml_user_info->addChild("item$key");
                array_to_xml($value, $subnode);
            }
        }else {
            $xml_user_info->addChild("$key",htmlspecialchars("$value"));
        }
    }
}

//creating object of SimpleXMLElement
$xml_user_info = new SimpleXMLElement("<?xml version=\"1.0\"?><user></user>");

//function call to convert array to xml
array_to_xml($users_array,$xml_user_info);

//saving generated xml file
$xml_file = $xml_user_info->asXML('users.xml');

//success and error message based on xml creation
if($xml_file){
    echo 'XML file have been generated successfully.';
}else{
    echo 'XML file generation error.';
}
?>

But I am not sure how to format the array I got from the Text file.
Any help will be highly appreciated. Thanks

  • Have you tried anything? It should be feasible enough to create an XML writer and read the data via [`fgetcsv`](http://php.net/manual/en/function.fgetcsv.php) using `|` as a delimiter but expecting anyone to go to all the trouble of writing all that code for you is not a reasonable expectation. – apokryfos Aug 12 '17 at 06:29
  • my try could not generate a fruitful result, so I thought my code might confuse others, should I edit the code and post what I did? @apokryfos – Rajeet singh Aug 12 '17 at 06:33
  • the xml you show has the email for mobile number and abishek has the same mails than rajeet. this doesnt match the code you show. please fix this. – Gordon Aug 12 '17 at 07:26
  • on a side note: it's somewhat unclear what you are asking. If your question is only *"how to format the output of `SimpleXml::asXml`"*, then the answer is https://stackoverflow.com/questions/798967/php-simplexml-how-to-save-the-file-in-a-formatted-way – Gordon Aug 12 '17 at 08:55

3 Answers3

1

Using SimpleXML, you can build up the hierarchy of the XML document using...

    $data = 'Rajeet Singh|email@gmail.com|0123456789|Delhi  
    Abhishek|email2@gmail.com|0123456987|Pune';

    $lines = explode(PHP_EOL, $data);
    $xml = new SimpleXMLElement('<user />');
    $root = $xml->user;
    foreach($lines as $line){
        $data = explode("|",$line);
        $user = $xml->addChild('item');
        $user->addChild('name', $data[0]);
        $user->addChild('email', $data[1]);
        $user->addChild('mobile', $data[2]);
        $user->addChild('address', $data[3]);
    }

    echo $xml->asXML();

One thing which I don't do is create elements with a numeric postfix, you wouldn't normally (in XML) have elements item0, item1 as this means they are different element types. You wold simply have them all as item. If you needed an index, you could create them with item id="0" so the id becomes the identifier (for example the unique ID of a database).

Nigel Ren
  • 56,122
  • 11
  • 43
  • 55
1

I am adding an XMLWriter solution as an alternative.

XmlWriter can be a faster and less memory intensive solution over DOM or SimpleXml because it uses streams instead of holding the entire xml tree in memory.

Like mentioned elsewhere, you don't want <item0>, <item1> but instead use an ID attribute. XML provides this via the xml:id attribute. The code below makes use of this.

I am using an SplFileObject because it is a convenient file wrapper implementing the Iterator interface and providing CSV control.

<?php

$reader = new SplFileObject('file/dat.txt');
$reader->setFlags(
    SplFileObject::READ_CSV |
    SplFileObject::DROP_NEW_LINE |
    SplFileObject::READ_AHEAD |
    SplFileObject::SKIP_EMPTY
);
$reader->setCsvControl('|');

$writer = new XMLWriter;
$writer->openURI('file/dat.xml'); // write to this file
$writer->setIndent(true);         // format the output
$writer->startDocument('1.0', 'UTF-8');
$writer->startElement("user");    // the root element

foreach ($reader as $row_data) {
    $row = array_map('trim', $row_data);
    $writer->startElement('item');
    $writer->writeAttributeNS('xml', 'id', null, $reader->key());
    $writer->writeElement("name", $row_data[0] ?? null);
    $writer->writeElement("email", $row_data[1] ?? null);
    $writer->writeElement("mobile", $row_data[2] ?? null);
    $writer->writeElement("address", $row_data[3] ?? null);
    $writer->endElement();
    $writer->flush();
}

$writer->fullEndElement();
$writer->endDocument();

Note that this requires PHP7 due to the use of the null coalesce operator when writing the elements. If you are not on 7 yet, either update or use the old isset/empty constructs.

Gordon
  • 312,688
  • 75
  • 539
  • 559
0

For example, you can write as follows.

<?php

$string = <<<EOM
Rajeet Singh|email@gmail.com|0123456789|Delhi
Abhishek|email2@gmail.com|0123456987|Pune
EOM;

$line = explode(PHP_EOL, $string);

$tags = ['name', 'email', 'mobile', 'address'];

$xml = '';

$xml .= "<user>" . PHP_EOL;
foreach($line as $key => $row){
    $elements = explode("|",$row);
    $xml .= "<item{$key}>" . PHP_EOL;
    $boxes = array_map(NULL, $elements, $tags);
    foreach($boxes as $box){
        $xml .= "<{$box[1]}>{$box[0]}</{$box[1]}>" . PHP_EOL;
    }
    $xml .= "</item{$key}>" . PHP_EOL;
}
$xml .= "</user>" . PHP_EOL;

echo $xml;

EDIT

If you want to format the array from Text file.

$string = <<<EOM
Rajeet Singh|email@gmail.com|0123456789|Delhi
Abhishek|email2@gmail.com|0123456987|Pune
EOM;

$tags = ['name','email','mobile','address'];

$users_array = array_map(function($n) use($tags){
    $elements = explode('|', $n);
    return array_combine($tags, $elements);
},explode(PHP_EOL, $string));

var_dump($users_array);

Result...

array(2) {
  [0] =>
  array(4) {
    'name' =>
    string(12) "Rajeet Singh"
    'email' =>
    string(15) "email@gmail.com"
    'mobile' =>
    string(10) "0123456789"
    'address' =>
    string(5) "Delhi"
  }
  [1] =>
  array(4) {
    'name' =>
    string(8) "Abhishek"
    'email' =>
    string(16) "email2@gmail.com"
    'mobile' =>
    string(10) "0123456987"
    'address' =>
    string(4) "Pune"
  }
}
Yujiro
  • 351
  • 1
  • 6