3

I am building up an xml file and need to include a segment of xml saved in a database (yeah, I wish that wasn't the case too).

    // parent element
    $parent = $dom->createElement('RecipeIngredients');

    // the xml string I want to include
    $xmlStr = $row['ingredientSectionXml'];

    // load xml string into domDocument
    $dom->loadXML( $xmlStr );

    // add all Ingredient Sections from xmlStr as children of $parent
    $xmlList = $dom->getElementsByTagName( 'IngredientSection' );
    for ($i = $xmlList->length; --$i >= 0; ) {
      $elem = $xmlList->item($i);
      $parent->appendChild( $elem );
    }

    // add the parent to the $dom doc
    $dom->appendChild( $parent );

Right now, I get the following error when I hit the line $parent->appendChild( $elem );

Fatal error: Uncaught exception 'DOMException' with message 'Wrong Document Error'

The XML in the string might look something like the following example. An important point is that there may be multiple IngredientSections, all of which need to be appended to the $parent element.

<IngredientSection name="Herbed Cheese">
  <RecipeIngredient>
    <Quantity>2</Quantity>
    <Unit>cups</Unit>
    <Item>yogurt cheese</Item>
    <Note>(see Tip)</Note>
    <MeasureType/>
    <IngredientBrand/>
  </RecipeIngredient>
  <RecipeIngredient>
    <Quantity>2</Quantity>
    <Unit/>
    <Item>scallions</Item>
    <Note>, trimmed and minced</Note>
    <MeasureType/>
    <IngredientBrand/>
  </RecipeIngredient>
<IngredientSection name="Cracked-Wheat Crackers">
</IngredientSection>
  <RecipeIngredient>
    <Quantity>2</Quantity>
    <Unit>teaspoon</Unit>
    <Item>salt</Item>
    <Note/>
    <MeasureType/>
    <IngredientBrand/>
  </RecipeIngredient>
  <RecipeIngredient>
    <Quantity>1 1/4</Quantity>
    <Unit>cups</Unit>
    <Item>cracked wheat</Item>
    <Note/>
    <MeasureType/>
    <IngredientBrand/>
  </RecipeIngredient>
</IngredientSection>
doub1ejack
  • 10,627
  • 20
  • 66
  • 125

2 Answers2

5

Here a two possible solutions:

Import From A Source Document

This works only if the XML string is a valid document. You need to import the document element, or any descendant of it. Depends on the part you would like to add to the target document.

$xml = "<child>text</child>";

$source = new DOMDocument();
$source->loadXml($xml);

$target = new DOMDocument();
$root = $target->appendChild($target->createElement('root'));
$root->appendChild($target->importNode($source->documentElement, TRUE));

echo $target->saveXml();

Output:

<?xml version="1.0"?>
<root><child>text</child></root>

Use A Document Fragment

This works for any valid XML fragment. Even if it has no root node.

$xml = "text<child>text</child>";

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

$fragment = $target->createDocumentFragment();
$fragment->appendXml($xml);
$root->appendChild($fragment);

echo $target->saveXml();

Output:

<?xml version="1.0"?>
<root>text<child>text</child></root>
ThW
  • 19,120
  • 3
  • 22
  • 44
  • Thanks! I ended up creating a second DomDocument (your first example). In retrospect it seems like it would be less overhead using a Document Fragment though. – doub1ejack Feb 25 '15 at 21:41
0

You need to use ->importNode() instead of ->appendChild(). Your XML snippets are coming from a completely different XML document, and appendChild will only accept nodes which are part of the SAME xml tree. importNode() will accept "foreign" nodes and incorporate them into the main tree.

Marc B
  • 356,200
  • 43
  • 426
  • 500
  • `importNode()` is not a method on [DOMElement](http://php.net/manual/en/class.domelement.php). And I get the same "Wrong Document Error" when I try `$parent->appendChild( $dom->importNode( $elem, true ) );`. Can you provide an example? – doub1ejack Feb 05 '15 at 16:11
  • Interesting. My code works after following the second answer to [this post](http://stackoverflow.com/questions/5783716/php-xml-dom-uncaught-exception-domexception-with-message-wrong-document-error). It seems I had to load the xml string into a second, separate DOMDocument and import that element. Seems like a lot of overhead to create a second DOMDocument - I suspect that's what [DOMDocumentFragment](http://php.net/manual/en/class.domdocumentfragment.php) is for, but I'll need to find an example. – doub1ejack Feb 05 '15 at 16:19
  • `->importNode()` is a method of DOMDocument. Like `createElement()` it returns a node that you can append. So "ìnstead of" should be replaced with "before". – ThW Feb 05 '15 at 22:30