Jump to content

Creating new element Tag in XML using XMLReader in PHP


kacperwozniak

Recommended Posts

I want to add Tag element <is_active> with CDATA true or false. Because of huge XML file I have to use XMLReader. I am not sure if I should use SimpleXML or XMLWriter for adding Tag Element.
Here is my XML file (short version):

<?xml version="1.0" encoding="UTF-8" ?>
<offers>
<offer>
    <id><![CDATA[2109]]></id>
    <name><![CDATA[Sleek Frozen Sausages]]></name>
    <category><![CDATA[Sleek]]></category>
    <description><![CDATA[Eum aut qui est delectus suscipit aut voluptas quaerat maiores architecto perferendis dolorum tenetur iure nemo omnis laboriosam voluptatem et iste molestias sed voluptas eum facilis aliquam tempora autem aspernatur ipsum corrupti cum corrupti quae dolor modi consequatur provident illo maiores eius aspernatur id nostrum nisi repellat enim a hic unde laboriosam possimus est ipsam qui mollitia nesciunt est culpa voluptatem sit dignissimos quidem facilis dolorem facilis et explicabo ea veniam quis architecto autem occaecati quaerat omnis reprehenderit doloribus labore saepe asperiores a ea possimus dolor necessitatibus numquam doloremque velit fuga ipsam numquam quia omnis voluptas voluptas rerum sint eveniet sit in error quia nemo delectus perferendis asperiores quam quam assumenda reiciendis sunt aut et saepe ea adipisci eum debitis odit similique consectetur nesciunt ducimus maxime sed consequuntur repellendus qui illum vero necessitatibus perferendis cumque optio voluptatibus et quas velit voluptatem tempore est et officiis tempora iusto rerum eum amet a qui corrupti ex nobis laborum eum assumenda velit laboriosam et sed sapiente accusantium officia enim doloremque perspiciatis quos ut rerum molestias ut ut aut omnis vitae placeat voluptas iusto distinctio ea molestias et at et aliquam libero non neque dicta quos numquam est non explicabo ipsa neque dolores rerum.]]></description>
    <price><![CDATA[252.65 EUR]]></price>
    <url><![CDATA[https://example.com/product/2109]]></url>
    <image_url><![CDATA[http://lorempixel.com/640/480]]></image_url>
    <opening_times><![CDATA[{"1":[{"opening":"10:00","closing":"22:30"}],"2":[{"opening":"10:00","closing":"22:30"}],"3":[{"opening":"10:00","closing":"22:30"}],"4":[{"opening":"10:00","closing":"22:30"}],"5":[{"opening":"10:00","closing":"22:30"}],"6":[{"opening":"10:00","closing":"22:30"}],"7":[],"timezone":"Europe/Warsaw"}]]></opening_times>
</offer>
<offer>
    <id><![CDATA[7673]]></id>
    <name><![CDATA[Ergonomic Soft Fish]]></name>
    <category><![CDATA[Rustic]]></category>
    <description><![CDATA[Pariatur consectetur autem reiciendis ab ea est fugiat tenetur suscipit ut sit rem accusamus accusamus accusamus veniam commodi omnis quia minus ratione reprehenderit est porro omnis modi et ipsa aut itaque impedit inventore modi nisi nemo commodi nesciunt earum quia sed assumenda nulla quia qui neque laborum vitae nobis dolorem perspiciatis tenetur nisi asperiores eos itaque dolorem sit est nostrum sequi similique doloremque vero id voluptas exercitationem eveniet saepe non impedit aut neque aut sed molestiae aut cum hic consectetur facilis porro atque perspiciatis maiores maiores ut aut enim iste maxime dolores est dolores quaerat dolores error nisi et esse voluptas occaecati nostrum quasi vero porro natus iste molestiae totam culpa vero voluptate porro aut ut iusto non ullam quam aut itaque velit quis maiores nobis officia ut iure voluptatibus iure nihil optio repellendus eum similique eum in excepturi doloremque rerum cumque accusantium fuga sed sed odit vel qui nam eum iure sapiente magni et temporibus quis qui pariatur tempora odit explicabo et mollitia autem nihil autem repellat ut et laudantium ab dolores nisi porro fuga sed laudantium quae delectus debitis quaerat doloremque praesentium quod ullam accusamus architecto earum impedit esse sint sint fugiat nihil itaque ut ut aut provident.]]></description>
    <price><![CDATA[384.12 EUR]]></price>
    <url><![CDATA[https://example.com/product/7673]]></url>
    <image_url><![CDATA[http://lorempixel.com/640/480]]></image_url>
    <opening_times><![CDATA[{"1":[{"opening":"14:00","closing":"23:00"}],"2":[{"opening":"14:00","closing":"23:00"}],"3":[{"opening":"14:00","closing":"23:00"}],"4":[{"opening":"14:00","closing":"23:00"}],"5":[{"opening":"14:00","closing":"23:00"}],"6":[{"opening":"14:00","closing":"23:00"}],"7":[],"timezone":"Europe/Warsaw"}]]></opening_times>
</offer>
</offers>

 

Code in PHP using XMLWriter:

<?php

require('xmlreader-iterators.php'); // require XMLReaderIterator library
$xmlInputFile  = 'feed_sample.xml';
$xmlOutputFile = 'output.xml';

$reader = new XMLReader();
$reader->open($xmlInputFile);

$writer = new XMLWriter();
$writer->openUri($xmlOutputFile);

$iterator = new XMLWritingIteration($writer, $reader);

$writer->startDocument();

foreach ($iterator as $node) {
    $isElement = $node->nodeType === XMLReader::ELEMENT;

    if ($isElement && $node->name === 'offer') {
        $writer->startElement('is_active');
        $writer->text('true');
        if ($node->isEmptyElement) {
            $writer->endElement();
        }
    } else {
        // handle everything else
        $iterator->write();
    }
}

$writer->endDocument();

 Code in PHP using SimpleXML

<?php

$fn = __DIR__ . '/feed_sample.xml';

$tag = 'offer';
$reader = new \XMLReader();

if (!$reader->open($fn)) {
    throw new \RuntimeException("Could not open {$fn} with XMLReader");
}


while ($reader->read()) {


    while ($tag === $reader->name) {

        $elem = new \SimpleXMLElement($reader->readOuterXML());
        $opening_times = (string) $elem->opening_times;
        $opening_times_array = explode('"', $opening_times);
        print_r($opening_times_array);
        $add = $elem->addChild('is_active', 'true');

        $reader->next($tag);
        $elem->asXML('outputSimple.xml');
    }

}

When I run codes above I recieve:

For XMLWriter:

<?xml version="1.0"?>
<offers>
<is_active>true
    <id/>
    <name/>
    <category/>
    <description/>
    <price/>
    <url/>
    <image_url/>
    <opening_times/>
</is_active>
</offers>

For SimpleXML:

<?xml version="1.0"?>
<offer>
    <id><![CDATA[5086]]></id>
    <name><![CDATA[Ergonomic Frozen Fish]]></name>
    <category><![CDATA[Incredible]]></category>
    <description><![CDATA[Molestiae et et esse temporibus iure numquam fugiat impedit dolor molestiae neque mollitia doloremque aut minus debitis officia ut alias earum voluptas quas velit consequatur qui aut possimus ut corporis quis aut numquam est sint unde sint aliquam qui qui dolor distinctio accusamus quae eveniet sit et itaque dolorem aut ea quia et repellat delectus quaerat aperiam blanditiis repellat esse architecto inventore delectus enim voluptates non hic amet ut aut aut et quis earum pariatur ut ex eos in sed sit ut quo inventore et quo officia suscipit tempore doloremque rerum iusto aperiam quae quas laboriosam et et quia facere qui facilis magni earum perferendis rerum saepe accusantium dolorem nostrum nam et et sequi nam aliquam et facilis repellendus omnis impedit minus eligendi ipsum et quidem qui corrupti possimus est iusto alias libero illum voluptate vel blanditiis minus dolorem voluptas at eum laborum aut architecto maxime voluptatem et debitis ab enim neque eum aliquid quis officiis quidem molestiae sint est vero voluptas dolores qui commodi aspernatur eius numquam eos voluptatem voluptatem praesentium rerum voluptatibus doloremque labore iste ex cupiditate asperiores tenetur voluptatem dolorem quo aut corrupti omnis iusto mollitia eligendi eum natus repudiandae error porro quisquam eum eligendi aut officiis.]]></description>
    <price><![CDATA[219.57 EUR]]></price>
    <url><![CDATA[https://example.com/product/5086]]></url>
    <image_url><![CDATA[http://lorempixel.com/640/480]]></image_url>
    <opening_times><![CDATA[{"1":[{"opening":"10:00","closing":"21:00"}],"2":[{"opening":"10:00","closing":"21:00"}],"3":[{"opening":"10:00","closing":"21:00"}],"4":[{"opening":"10:00","closing":"21:00"}],"5":[{"opening":"10:00","closing":"21:00"}],"6":[{"opening":"10:00","closing":"21:00"}],"7":[{"opening":"10:00","closing":"20:00"}],"timezone":"Europe/Warsaw"}]]></opening_times>
<is_active>true</is_active></offer>

As we can see for XMLWriter results replace Tag Name <offer> with Tag name <is_active> what is unwanted, there are no data inside all Tag elements and there is modified only one Tag Element <offer> (I would like to modified all <offer> Tag Names).

In SimpleXML case there are data for each Tag Name and I wrote inside <offer> Tag Name <is_active>, but as response there is Tag Name <is_active> for only one <offer>.

XMLWritter: Why there are no data in each element Tag?

XMLWritter: How can I create Tag Name inside <offer>. NOT instead <offer>

XMLWritter: How can I create Tag Name for all <offer> Tag Names?

SimpleXML: How can I write a code which take into account all Tags <offer> and add inside Tag <is_active>.

I hope it is clear explanation. I will be greatful for any answer.

Edited by kacperwozniak
Link to comment
Share on other sites

try

$xml = simplexml_load_string($str);
foreach ($xml->xpath("//offer") as $o) {
    $o->is_active = 'true';
}

gives

<?xml version="1.0" encoding="UTF-8"?>
<offers>
<offer>
    <id><![CDATA[2109]]></id>
    <name><![CDATA[Sleek Frozen Sausages]]></name>
    <category><![CDATA[Sleek]]></category>
    <description><![CDATA[Eum aut qui est delectus suscipit aut voluptas quaerat maiores architecto perferendis dolorum tenetur iure nemo omnis laboriosam voluptatem et iste molestias sed voluptas eum facilis aliquam tempora autem aspernatur ipsum corrupti cum corrupti quae dolor modi consequatur provident illo maiores eius aspernatur id nostrum nisi repellat enim a hic unde laboriosam possimus est ipsam qui mollitia nesciunt est culpa voluptatem sit dignissimos quidem facilis dolorem facilis et explicabo ea veniam quis architecto autem occaecati quaerat omnis reprehenderit doloribus labore saepe asperiores a ea possimus dolor necessitatibus numquam doloremque velit fuga ipsam numquam quia omnis voluptas voluptas rerum sint eveniet sit in error quia nemo delectus perferendis asperiores quam quam assumenda reiciendis sunt aut et saepe ea adipisci eum debitis odit similique consectetur nesciunt ducimus maxime sed consequuntur repellendus qui illum vero necessitatibus perferendis cumque optio voluptatibus et quas velit voluptatem tempore est et officiis tempora iusto rerum eum amet a qui corrupti ex nobis laborum eum assumenda velit laboriosam et sed sapiente accusantium officia enim doloremque perspiciatis quos ut rerum molestias ut ut aut omnis vitae placeat voluptas iusto distinctio ea molestias et at et aliquam libero non neque dicta quos numquam est non explicabo ipsa neque dolores rerum.]]></description>
    <price><![CDATA[252.65 EUR]]></price>
    <url><![CDATA[https://example.com/product/2109]]></url>
    <image_url><![CDATA[http://lorempixel.com/640/480]]></image_url>
    <opening_times><![CDATA[{"1":[{"opening":"10:00","closing":"22:30"}],"2":[{"opening":"10:00","closing":"22:30"}],"3":[{"opening":"10:00","closing":"22:30"}],"4":[{"opening":"10:00","closing":"22:30"}],"5":[{"opening":"10:00","closing":"22:30"}],"6":[{"opening":"10:00","closing":"22:30"}],"7":[],"timezone":"Europe/Warsaw"}]]></opening_times>
    <is_active>true</is_active>
</offer>
<offer>
    <id><![CDATA[7673]]></id>
    <name><![CDATA[Ergonomic Soft Fish]]></name>
    <category><![CDATA[Rustic]]></category>
    <description><![CDATA[Pariatur consectetur autem reiciendis ab ea est fugiat tenetur suscipit ut sit rem accusamus accusamus accusamus veniam commodi omnis quia minus ratione reprehenderit est porro omnis modi et ipsa aut itaque impedit inventore modi nisi nemo commodi nesciunt earum quia sed assumenda nulla quia qui neque laborum vitae nobis dolorem perspiciatis tenetur nisi asperiores eos itaque dolorem sit est nostrum sequi similique doloremque vero id voluptas exercitationem eveniet saepe non impedit aut neque aut sed molestiae aut cum hic consectetur facilis porro atque perspiciatis maiores maiores ut aut enim iste maxime dolores est dolores quaerat dolores error nisi et esse voluptas occaecati nostrum quasi vero porro natus iste molestiae totam culpa vero voluptate porro aut ut iusto non ullam quam aut itaque velit quis maiores nobis officia ut iure voluptatibus iure nihil optio repellendus eum similique eum in excepturi doloremque rerum cumque accusantium fuga sed sed odit vel qui nam eum iure sapiente magni et temporibus quis qui pariatur tempora odit explicabo et mollitia autem nihil autem repellat ut et laudantium ab dolores nisi porro fuga sed laudantium quae delectus debitis quaerat doloremque praesentium quod ullam accusamus architecto earum impedit esse sint sint fugiat nihil itaque ut ut aut provident.]]></description>
    <price><![CDATA[384.12 EUR]]></price>
    <url><![CDATA[https://example.com/product/7673]]></url>
    <image_url><![CDATA[http://lorempixel.com/640/480]]></image_url>
    <opening_times><![CDATA[{"1":[{"opening":"14:00","closing":"23:00"}],"2":[{"opening":"14:00","closing":"23:00"}],"3":[{"opening":"14:00","closing":"23:00"}],"4":[{"opening":"14:00","closing":"23:00"}],"5":[{"opening":"14:00","closing":"23:00"}],"6":[{"opening":"14:00","closing":"23:00"}],"7":[],"timezone":"Europe/Warsaw"}]]></opening_times>
    <is_active>true</is_active>
</offer>
</offers>

 

Edited by Barand
Link to comment
Share on other sites

Thank you for response! 

One more thing: As you can see in Tag Name <opening_times> there are opening and closeing hours. What I want to do is assign <is_active>true</is_active> when current hour when we run a script is between opening and closeing hours else assign <is_active>false</is_active>. 

I will be at home in 3 hours and check how your way for adding Tag Name works and try to implement it with such condition wrote above. I wrote it before but using DOMDocument, which take into account all data together, so I am looking a solution with XMLReader. 

Thank you again and I will let you know how it works!

Edited by kacperwozniak
Link to comment
Share on other sites

Assuming day #1 is Monday,

$xml = simplexml_load_string($str);
foreach ($xml->xpath("//offer") as $offer) {
    $open = json_decode((string)$offer->opening_times,1);
    $today = new DateTime('now', new DateTimeZone($open['timezone']));
    $now = $today->format('H:i');
    $day = $today->format('N');
    $offer->is_active = ($open[$day][0]['opening'] <= $now && $now <= $open[$day][0]['closing']) ? 'true':'';
}

 

  • Great Answer 1
Link to comment
Share on other sites

Ok, I checked your solution. Indeed Tag Name <is_active> is inside each <offer>.

But by using your code we take into account whole XML file. My purpose was to read offer after offer, what saves computer memory. 

The XMLReader acts as a cursor going forward on the document stream and stopping at each node on the way.

And here is a problem, because I can't invent code, which take <offer>, check hours in <opening_times>, add <is_active>true/false</is_active> and go to the next offer one by one.

The code below return Tag <opening_times> value as a array separated by " for each offer, so it proves that XMLReader works properly. The problem is when I am trying to add <is_active> Tag, because using simpleXML it works only for the last <offer> (code on first post in that topic). It looks like the code go thru whole XML file data and return <offer> with <is_active> Tag, but when it go to next <offer> it destroy previous <offer>.

 

<?php

$fn = __DIR__ . '/feed_sample.xml';
$reader = new \XMLReader();

if (!$reader->open($fn)) {
    throw new \RuntimeException("Could not open {$fn} with XMLReader");
}

while ($reader->read()) {
    while ($tag === $reader->name) {
        $opening_times = (string) $elem->opening_times;
        $opening_times_array = explode('"', $opening_times);
        print_r($opening_times_array);
        $reader->next($tag);
    }

}

 

Link to comment
Share on other sites

The important code to look at from Barand's post:

 

$xml = simplexml_load_string($str);
foreach ($xml->xpath("//offer") as $offer) {

Look at the manual page for the simplexml.  Then look at the xpath function.  Do you understand what it does?

He is showing you a different library to load your xml file with, that has some features that the xmlreader doesn't.  So you can:

  • Convert entirely to using simplexml
  • Keep your existing code, doing whatever it is doing, then add code that closes the xml file, and reopens it using simplexml, which will then allow you to use Barand's code
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.