yayheartbeat
yayheartbeat

Reputation: 445

Combine multiple XML files with PHP and wrap in new root element

I'm trying to combine multiple XML files that have the same structure into one file.

This is the structure of my XML files:

file1.xml:

<root information="file1">
 <items>
  <item>FOO</item>
  <item>BAR</item>
 </items>
</root>

file2.xml:

<root information="file2">
 <items>
  <item>BAR</item>
  <item>FOO</item>
 </items>
</root>

Using this code I've been able to combine them:

$files= array(
  'file1.xml',
  'file2.xml'
);

$dom = new DOMDocument();
$dom->appendChild($dom->createElement('root'));

foreach ($files as $filename) {
  $addDom = new DOMDocument();

  $addDom->load($filename);
  if ($addDom->documentElement) {
    foreach ($addDom->documentElement->childNodes as $node) {
      $dom->documentElement->appendChild(
        $dom->importNode($node, TRUE)
      );

    }

  }
}

$dom->save('output.xml');

This works partly but removes the original root element which has the information attribute that I still need. So I would like to keep all the existing root elements but wrap them in a new root element. This is what I would like to end up with:

<files>
 <root information="file1">
  <items>
   <item>FOO</item>
   <item>BAR</item>
  </items>
 </root>
 <root information="file2">
  <items>
   <item>BAR</item>
   <item>FOO</item>
  </items>
 </root>
</files>

But I can't figure out how to append the file. Whatever I try it only ends up at the bottom of the output file instead of appending all old root elements. I'm guessing this is simple as hell but I just can't figure it out. Help much appreciated!

Upvotes: 0

Views: 2205

Answers (2)

ThW
ThW

Reputation: 19512

Actually your source only has some minor mistakes. You create a root document element in the target document, not the files element in you example. Additionally your copy of the nodes in the source documents is a level to deep, you just need to import their document elements.

I modified your code a little to make it self contained and fixed the mistakes.

$files= array(
  'file1.xml' => 
'<root information="file1">
 <items>
  <item>FOO</item>
  <item>BAR</item>
 </items>
</root>',
  'file2.xml' => 
'<root information="file2">
 <items>
  <item>BAR</item>
  <item>FOO</item>
 </items>
</root>'
);

// create a target document with a files root
$target = new DOMDocument();
$target->appendChild($target->createElement('files'));

// iterate the source files array
foreach ($files as $name => $content) {
  // load each source
  $source = new DOMDocument();
  $source->loadXml($content);
  // if it has a document element
  if ($source->documentElement) {
    // copy it to the target document
    $target->documentElement->appendChild(
      $target->importNode($source->documentElement, TRUE)
    );
  }
}

$target->formatOutput = TRUE;
echo $target->saveXml();

Upvotes: 1

Parfait
Parfait

Reputation: 107707

Consider XSLT the special-purpose language designed to transform XML files. XSLT maintains the document() function to parse from external files at paths relative to script. PHP can run XSLT 1.0 scripts with its php-xsl class. Be sure to enable this extension in .ini file.

Should your files be very numerous such as hundreds, consider building the XSLT script on the fly in PHP loop. As information, XSLT is a well-formed XML file, so can be parsed from file or string.

XSLT (save as .xsl file in same directory as all XML files)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <files>
            <xsl:copy-of select="root"/>
            <xsl:copy-of select="document('file2.xml')/root"/>
            <xsl:copy-of select="document('file3.xml')/root"/>
            <xsl:copy-of select="document('file4.xml')/root"/>                 
            <!-- add more as needed -->
        </files>
    </xsl:template>

</xsl:stylesheet>

PHP (load first XML and XSL scripts, then transform/output)

// LOAD XML SOURCE
$xml = new DOMDocument('1.0', 'UTF-8');
$xml->load('file1.xml');                  // ONLY LOAD FIRST XML

// LOAD XSL SOURCE
$xsl = new DOMDocument('1.0', 'UTF-8');
$xsl->load('XSLT_Script.xsl');

// TRANSFORM XML
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl);
$newXML = $proc->transformToXML($xml);

// SAVE NEW XML
file_put_contents('Output.xml', $newXML);

Upvotes: 1

Related Questions