Display nested content from an RSS Feed

I based my implementation on the article “Content from an RSS feed”. However, I have problems to get all values of a XML file. I am currently trying to read out the values that are inside . The XML-file looks something like this:

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <item>
    <hash>07548882287dc5asdasd2dbf741639abce</hash>
    <ids label="IDs">
      <system_id label="System ID">5874123</system_id>
    </ids>
    <publications locked="0">
      <en>
        <title>English Projecttitle</title>
        <sample><![CDATA[<span style="color: #222222; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">Sample English</span>]]></sample>
        <contacts>
          <contact>
            <type>
              <id>3525</id>
              <name>Print Owner</name>
            </type>
            <text><![CDATA[Sample Name, City]]></text>
          </contact>
        </contacts>
      </en>
      <de>
        <title>Deutscher Projekttitel</title>
        <sample><![CDATA[<span style="color: #222222; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">Sample Deutsch</span>]]></sample>
        <contacts>
          <contact>
            <type>
              <id>3525</id>
              <name>Print Owner</name>
            </type>
            <text><![CDATA[Sample Name, City]]></text>
          </contact>
        </contacts>
      </de>
  </item>
</films>

The model like this

<?php

class MyRssfeedPage extends Page {

    public function children()
    {
        $results = [];
        $pages   = [];

        $request = Remote::get('sample.xml');

        if ($request->code() === 200) {
            $results = Xml::parse($request->content());
        }

        if (count($results) > 0) {
            foreach ($results['item'] as $item) {
                $pages[] = [
                    'slug'     => Str::slug($item['hash']),
                    'template' => 'feeditem',
                    'model'    => 'feeditem',
                    'content'  => [
                        'title'   => $item['publications']['de']['title'] ?? '',
                        'sample'   => $item['publications']['de']['sample'] ?? '',
                        'contacts'   => $item['publications']['de']['contacts'] ?? '',
                    ]
                ];
            }
        }

        return Pages::factory($pages, $this);
    }

}

and the template like this:

<?php foreach ($page->children()->sortBy('date', 'desc') as $item): ?>
      <?= $item->sample() ?>

        DISPLAY CONTACT TEXT HERE
      
    <?php endforeach ?>

Any hints on how to display the contact information would be appreciated.

What do you get when you dump($item->contacts())?

I guess you just posted an extract from your xml file but it is invalid and therefore not suitable for testing the result.

I shortened the XML yes. The original file is much, much longer …

When I dump $item->contacts() it looks something like this.

Kirby\Cms\Field Object
(
    [contacts] => Array
        (
            [contact] => Array
                (
                    [0] => Array
                        (
                            [type] => Array
                                (
                                    [id] => 3525
                                    [name] => Sample Name, City
                                )
                            [text] => 
                        )
                )
        )
)

The problem here is that you now have a field object with an array. You can either convert the field to an array with $item->contacts()->toArray().

Or you store the contacts array as yaml or json in your page model.

What do you think is the best way to do that? If I convert it to an array in the template as you suggested I still get the error “Array to string conversion”. And if I do something like $listcontacts = Json::encode($item->contacts()); in the model then I get the error “Call to a member function contacts() on array”.

I guess there is a lot that I am missing here?

Then you are probably trying to echo an array instead of getting the array values by there indices.

Where are you doing this? In the template?

I did it in the modal. When I place the code in the template I get the raw values of the Json data. I am not that used to working with Json. Do I have to loop over them in order to access the fields?

But in the model, you would have to json_encode your array:

'contacts'   => json_encode($results['item']['publications']['de']['contacts'] ?? []),

Then you would json_decode the field value again in the template, which would again give you an array (or an object)

$contacts = json_decode($page->contacts()->value(), true);

But as I wrote above, you can directly work with the converted field array, you just cannot echo an array.

I tried my best to get it to run. Thank you very much for your suggestions! But unfortunately I failed so far. Here is my modal again.

<?php

class MyRssfeedPage extends Page {

    public function children()
    {
        $results = [];
        $pages   = [];

        $request = Remote::get('sample.xml');

        if ($request->code() === 200) {
            $results = Xml::parse($request->content());
        }

        if (count($results) > 0) {
            foreach ($results['item'] as $item) {
                $pages[] = [
                    'slug'     => Str::slug($item['hash']),
                    'template' => 'feeditem',
                    'model'    => 'feeditem',
                    'content'  => [
                        'title'   => $item['publications']['de']['title'] ?? '',
                        'sample'   => $item['publications']['de']['sample'] ?? '',
                        'contacts'   => json_encode($results['item']['publications']['de']['contacts'] ?? []),
                    ]
                ];
            }
        }


        return Pages::factory($pages, $this);
    }

}

And here my template

<?php snippet('header') ?>

<main>
  <header>
    <h1><?= $page->title() ?></h1>
  </header>

  <div class="feed">
    <?php foreach ($page->children()->sortBy('date', 'desc') as $item): ?>
      <div style="margin-bottom:50px;">
      <?= $item->sample() ?>
      <?= $item->directors() ?>
      <?php $contacts = json_decode($page->contacts()->value(), true); ?>
      <?= var_dump($contacts)?>
    </div>
    <?php endforeach ?>
      
  </div>

</main>
<?php snippet('footer') ?>

When I dump $contacts I get NULL. I tried converting it to an array in the template with $item->contacts()->toArray() without luck. Again I got the Array to String conversion error.

But because I initially shortened the XML-File I omitted some contact information. There are more than one contacts available. Could that be the reason for the errors? Here my a sample of the XML-File again:

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <item>
    <hash>07548882287dc5asdasd2dbf741639abce</hash>
    <ids label="IDs">
      <system_id label="System ID">5874123</system_id>
    </ids>
    <publications locked="0">
      <en>
        <title>English Projecttitle</title>
        <sample><![CDATA[<span style="color: #222222; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">Sample English</span>]]></sample>
        <contacts>
          <contact>
            <type>
              <id>3525</id>
              <name>Print Owner</name>
            </type>
            <text><![CDATA[Sample Name, City]]></text>
          </contact>
          <contact>
            <type>
              <id>3526</id>
              <name>Sample Owner</name>
            </type>
            <text><![CDATA[Sample Name, City]]></text>
          </contact>
        </contacts>
      </en>
      <de>
        <title>Deutscher Projekttitel</title>
        <sample><![CDATA[<span style="color: #222222; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px;">Sample Deutsch</span>]]></sample>
        <contacts>
          <contact>
            <type>
              <id>3525</id>
              <name>Print Owner</name>
            </type>
            <text><![CDATA[Sample Name, City]]></text>
          </contact>
          <contact>
            <type>
              <id>3526</id>
              <name>Sample Owner</name>
            </type>
            <text><![CDATA[Sample Name, City]]></text>
          </contact>
        </contacts>
      </de>
  </item>
</project>

The resulting structure is a bit unexpected. If you change the current setup in your model to this:

'contacts'   => json_encode($results['item']['publications']['de']['contacts']['contact'] ?? []),

then you can do it like this:

<?php foreach ($page->children()->sortBy('date', 'desc') as $item): ?>
      <?php $contacts = json_decode($item->contacts()->value(), true) ?>

      <?php foreach ($contacts as $contact):?>
        <?php echo $contact['text'] ?>
        <?php echo $contact['type']['id'] ?>
      <?php endforeach ?>
      
    <?php endforeach ?>

Unfortunately, I cannot read out any values this way. But I can with the following code (in the template).

<?php 
  $results = [];
  $pages = [];
  $results = simplexml_load_file('sample.xml');
?>

<?php foreach ($results as $item): ?>
  <?php if (isset($item->publications->de->contacts)): ?>
    <?php foreach ($item->publications->de->contacts as $contact):?>
      <?php foreach ($contact as $i):?>
        <?= $i->text ?><br>
        <?= $i->type->id ?><br>
      <?php endforeach ?>
    <?php endforeach ?>
  <?php endif ?>
<?php endforeach ?>

I have not yet managed to reproduce this in the model. But many thanks for your help. I appreciate it.

Allright. I managed to get it to run with this model

<?php

class FeedPage extends Page {

    public function children()
    {
        $results = [];
        $pages   = [];

        $request = Remote::get('sample.xml');

        if ($request->code() === 200) {
            $results = Xml::parse($request->content());
        }

        if (count($results) > 0) {
            foreach ($results['item'] as $item) {
                $pages[] = [
                    'slug'     => Str::slug($item['hash']),
                    'template' => 'feeditem',
                    'model'    => 'feeditem',
                    'content'  => [
                        'title'   => $item['publications']['de']['title'] ?? '',
                        'contacts'   => $item['publications']['de']['contacts'] ?? '',
                    ]
                ];
            }
        }


        return Pages::factory($pages, $this);
    }

}

and this code inside the template

<?php foreach ($page->children()->sortBy('date', 'desc') as $item): ?>
        <?php $contacts = $item->contacts() ?>

        <?php if (isset($contacts)): ?>
          <?php foreach ($contacts as $contact):?>
            <?php if (is_array($contact)==1):?>
              <?php foreach ($contact["contact"] as $j):?>
                <?= $j["type"]["id"] ?><br>
                <?= $j["text"] ?><br>
              <?php endforeach?>
            <?php endif?>
          <?php endforeach ?>
        <?php endif ?>
      <?php endforeach ?>