2

I have a little problem with creating an complex XML structure with PHP and Dom Document.

I want the structure to be like this:

<page PathToWeb="www.mysite.com">
    <Questions>
        <Question id="my id" member="true">
        <Question id="my id2" member="true">
        <Question id="my id3" member="true">
    </Questions>
</page>

and the code i have so far is

<?php
/*Create DOM*/
$xml = new DOMDocument;
$xml->load('myxml.xml'); /* wich is just just blank <?xml?\> <page> </page>*/
$xpath = new DOMXPath($xml);

/*Set the base path*/
$hrefs = $xpath->evaluate("/page");

/*Add Path to web to the root /page*/
$href = $hrefs->item(0);
$href->setAttribute("PathToWeb",$PathToWeb);


/*Complex XML Creation with Xpath*/

/*ELEMENT APPEND (create questions into /page)*/
$href = $hrefs->item(0);
$element = $xml->createElement('Questions');
$href->appendChild($element);

/*XPATH EVALUATE*/
$hrefs = $xpath->evaluate("/page/Questions");

/*ELEMENT 1 APPEND*/
$href = $hrefs->item(0);
$element = $xml->createElement('Question');
$href->appendChild($element);
$hrefs = $xpath->evaluate("/page/Questions/Question");
$href = $hrefs->item(0);
$href->setAttribute("id","my id");

/*ELEMENT 2 APPEND*/
$href = $hrefs->item(0);
$element = $xml->createElement('Question');
$href->appendChild($element);
$hrefs = $xpath->evaluate("/page/Questions/Question");
$href = $hrefs->item(0);
$href->setAttribute("id","my id");

/*ELEMENT 3 APPEND*/
$href = $hrefs->item(0);
$element = $xml->createElement('Question');
$href->appendChild($element);
$hrefs = $xpath->evaluate("/page/Questions/Question");
$href = $hrefs->item(0);
$href->setAttribute("id","my id");

$href = $hrefs->item(0);
$href->setAttribute("member","true");

$string2 = $xml->saveXML();
?>  

What is creating is:

<page PathToWeb="www.mysite.com">
<Questions><Question id="my id" member="true"><Question/></Question></Questions>
</page>

Editing only the first Question ...

How can i solve this?

Gordon
  • 312,688
  • 75
  • 539
  • 559
Master345
  • 2,250
  • 11
  • 38
  • 50

4 Answers4

6

Your code looks somewhat more complicated than it needs to be.

Because appendChild returns the appended node and setAttribute returns the set Attribute Node, you could also create the entire tree without any temp variables and also without any Xpath simply by chaining method calls and traversing the DOM tree:

$dom = new DOMDocument('1.0', 'utf-8');
$dom->appendChild($dom->createElement('page'))
    ->setAttribute('PathToWeb', 'www.mysite.com')
        ->parentNode
    ->appendChild($dom->createElement('Questions'))
        ->appendChild($dom->createElement('Question'))
            ->setAttribute('id', 'my_id')
                ->parentNode
            ->setAttribute('member', 'true')
                ->parentNode
            ->parentNode
        ->appendChild($dom->createElement('Question'))
            ->setAttribute('id', 'my_id2')
                ->parentNode
            ->setAttribute('member', 'true')
                ->parentNode
            ->parentNode
    ->appendChild($dom->createElement('Question'))
            ->setAttribute('id', 'my_id3')
                ->parentNode
            ->setAttribute('member', 'true');

$dom->formatOutput = true;
echo $dom->saveXml();

Understanding that DOM is a tree hierarchy of DOMNodes is essential when wanting to work with DOM. See DOMDocument in php for some explanation on that.

Community
  • 1
  • 1
Gordon
  • 312,688
  • 75
  • 539
  • 559
  • +1 as I have never thought of making use of parentNode to achieve chaining when building a DOMTree using DOMDocument. However, I still think the loop is gonna be a better way to go if you are building elements with number ids, as imagine there was gonna be twenty. – Liam Bailey Jul 16 '11 at 12:41
  • @Liam absolutely. The question elements are too similar to not add them in a loop. I really only wanted to stress how to traverse the DOMTree. – Gordon Jul 16 '11 at 12:44
1
    $xml = new DOMDocument('1.0','UTF-8');
    $root = $xml->createElement('page');
    $root->setAttribute("PathToWeb",$PathToWeb);
    $wrap = $xml->createElement('Questions');
    $root->appendChild($wrap);
    for ($i = 1;$i<4;$i++)
    {
    $element = $xml->createElement('question');
    $element->setAttribute("id","my id" . $i);
    $element->setAttribute("member","true");
    $wrap->appendChild($element);
    }
    $xml->appendChild($root);
    $xml->formatOutput = true;
    $xml->save('myxml.xml');// Thanks to Gordon
Liam Bailey
  • 5,879
  • 3
  • 34
  • 46
0
<?php
$xml = new DOMDocument;
$xml->load('myxml.xml'); /* wich is just just blank <?xml?> <page> </page>*/
$xpath = new DOMXPath($xml);

/*Set the base path*/
$base = $xpath->evaluate("/page")->item(0);

$base->setAttrubute("PathToWeb", $PathToWeb);

$questions = $xml->createElement('Questions');
$base->appendChild($questions);

for($i = 0; $i < 2; $i++) {
    $question= $xml->createElement('Question');
    $questions->appendChild($question);
    $question->setAttribute("id","my id");
    $question->setAttribute("member", "true");
}

$string2 = $xml->saveXML();
?>  
marc
  • 6,103
  • 1
  • 28
  • 33
0

This might help you to solve your problem and make your code much more compact and easier to deal with:

appendChild PHP Manual returns the new node. You can then directly work with it. No need to use xpath after appending the child to get access to it.

And if you add/set the attributes you want to set before adding the element node to the document, you most often don't even need to:

/*ELEMENT APPEND (create questions into /page)*/
$href = $hrefs->item(0);
$element = $xml->createElement('Questions');
$questions = $href->appendChild($element);
#   ^^^


/*ELEMENT 1 APPEND*/
$element = $xml->createElement('Question');
$element->setAttribute("id","my id"); # prepare before adding
$questions->appendChild($element);

...

It's quite the same for the root element of your document (<page>). You do not need to use xpath to access it and manipulate it. It's documentElement PHP Manual:

/*Create DOM*/
$xml = new DOMDocument;
$xml->load('myxml.xml'); /* wich is just just blank <?xml?> <page> </page>*/

/*Add Path to web to the root /page*/
$href = $xml->documentElement;
$href->setAttribute("PathToWeb",$PathToWeb);
hakre
  • 193,403
  • 52
  • 435
  • 836
  • @Row Minds: If that answered your question, feel free to accept it: http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work - so it's marked as solved. – hakre Jul 17 '11 at 09:09