Search code examples
xmldomdocumentphp-7.3

DOMDocument - Create book, load chapters and append


Need to use DOMDocument to construct a book with loaded and appended chapters. Each chapter would be stored in separate xml file. Below would create the root book and append the first child chapter_1. I understand that the "foreach"-loop will never load any other chapters since it is hardcoded for the chapter_1.

The aim is to solve the problem using DOMDocument to take care of proper tag wrapping. I know I could in this case use PHP include for all the chapters, and include root at start and end, (as a wrapper).

Question:

What would I need to change in the for-loop to be able to append a growing amount of chapters? Would I need to specify an array first and perform a "foreach" -loop to iterate over the array?

My code:

File: merge.php

<?php

$book = new DOMDocument();
$book->load('1_build_block_(book).xml');

$chapter_1 = new DOMDocument();
$chapter_1->load('2_build_block_(chapter_1).xml');

$chapter_2 = new DOMDocument();
$chapter_2->load('3_build_block_(chapter_2).xml');

// chapter_3, chapter_4, etc...

/**
 * Merge chapters into book.
 */

foreach ($chapter_1->childNodes as $child) {
    $book->documentElement->appendChild(
        $book->importNode($child, TRUE)
    );
}

echo $book->saveXML();
$book->saveHTMLFile("result.xml");

File: 1_build_block_(book).xml

<book></book>

File: 2_build_block_(chapter_1).xml

<chapter_1></chapter_1>

File: 3_build_block_(chapter_2).xml

<chapter_2></chapter_2>

Result:

<book>
  <chapter_1></chapter_1>
</book>

Wanted result:

<book>
  <chapter_1></chapter_1>
  <chapter_2></chapter_2>
</book>

Solution

  • You could use for example preg_grep in combination with scandir to get the files with the specific filenames.

    If the files are in the same dir, you could use this pattern to get the chapters only, where \d+ matches 1 or more digits.

    ^\d+_build_block_\(chapter_\d+\)\.xml$
    

    Regex demo

    $book = new DOMDocument();
    $book->load('1_build_block_(book).xml');
    $path = "./";
    $chapters = preg_grep('~^\d+_build_block_\(chapter_\d+\)\.xml$~', scandir("./"));
    
    foreach ($chapters as $chapter) {
        $doc = new DOMDocument();
        $doc->load($chapter);
        foreach ($doc->childNodes as $child) {
            $book->documentElement->appendChild(
                $book->importNode($child, TRUE)
            );
        }
    }
    
    echo $book->saveXML();
    $book->saveHTMLFile("result.xml");
    

    Output

    <?xml version="1.0"?>
    <book><chapter_1/><chapter_2/></book>