How can I set text value of SimpleXmlElement without using its parent?

22,229

Solution 1

You can do with a SimpleXMLElement self-reference:

$firstC->{0} = "Victory!!"; // hackity, hack, hack!
//  -or-
$firstC[0]   = "Victory!!";

found after looking at

var_dump((array) reset($xml->xpath("(//c)[3]")))

This also works with unset operations as outlined in an answer to:

Solution 2

The real answer is: you kind of can't.

On the other hand you can use DOM for it, e.g.

dom_import_simplexml($node)->nodeValue = 'foo';
Share:
22,229

Related videos on Youtube

Kamil Szot
Author by

Kamil Szot

I'm mostly PHP developer. But I am interested in a lot of things.

Updated on July 09, 2022

Comments

  • Kamil Szot
    Kamil Szot almost 2 years

    I want to set text of some node found by xpath()

    <?php
    
    $args = new SimpleXmlElement(
    <<<XML
    <a>
      <b>
        <c>text</c>
        <c>stuff</c>
      </b>
      <d>
        <c>code</c>
      </d>
    </a>
    XML
    );
    
    // I want to set text of some node found by xpath 
    // Let's take (//c) for example
    
    // convoluted and I can't be sure I'm setting right node
    $firstC = reset($args->xpath("//c[1]/parent::*")); 
    $firstC->c[0] = "test 1";
    
    // like here: Found node is not actually third in its parent.
    $firstC = reset($args->xpath("(//c)[3]/parent::*")); 
    $firstC->c[2] = "test 2";
    
    // following won't work for obvious reasons, 
    // some setText() method would be perfect but I can't find nothing similar, 
    $firstC = reset($args->xpath("//c[1]"));
    $firstC = "test"; 
    
    // maybe there's some hack for it?
    $firstC = reset($args->xpath("//c[1]"));
    $firstC->{"."} = "test"; // nope, just adds child named .
    $firstC->{""} = "test"; // still not right, 'Cannot write or create unnamed element'
    $firstC["."] = "test"; // still no luck, adds attribute named .
    $firstC[""] = "test"; // still no luck, 'Cannot write or create unnamed attribute'
    $firstC->addChild('','test'); // grr, 'SimpleXMLElement::addChild(): Element name is required'
    $firstC->addChild('.','test'); // just adds another child with name .
    
    echo $args->asXML();
    
    // it outputs:
    // 
    // PHP Warning:  main(): Cannot add element c number 2 when only 1 such elements exist 
    // PHP Warning:  main(): Cannot write or create unnamed element 
    // PHP Warning:  main(): Cannot write or create unnamed attribute 
    // PHP Warning:  SimpleXMLElement::addChild(): Element name is required 
    // <?xml version="1.0"? >
    // <a>
    //  <b>
    //   <c .="test">test 1<.>test</.><.>test</.></c>
    //   <c>stuff</c>
    //  </b>
    //  <d>
    //   <c>code</c>
    //  <c>test 2</c></d>
    // </a>
    
  • hakre
    hakre over 10 years
    Why is that the kind of real answer?
  • Josh Davis
    Josh Davis over 10 years
    That's because at the time of writing there was no supported way to do it, and I don't think it's changed. The fact that setting the value of a non-existing node named "0" changes a node's textContent may be a side effect, the result of sheer luck. It may unexpectedly stop working.
  • hakre
    hakre over 10 years
    The supported way of doing that is outlined in the accepted answer which was there already at the time you answered here for quite some time (just asked to learn more). That way actually is supported and it's documented in PHP's src, you find the implementation here: lxr.php.net/xref/PHP_5_3/ext/simplexml/… - the zero offset is always available for all element nodes. Also your answer misses to check the node-type of a SimpleXMLElement object and risks to produce errors and also side-effects.
  • Josh Davis
    Josh Davis over 10 years
    That's still an implementation detail though. The fact that you had to link to the (uncommented) source code rather than the manual only makes it clearer. Get the developer to officially support it by documenting it and I'll consider it an official feature. Otherwise, to me it's literally an undocumented behaviour.
  • quickshiftin
    quickshiftin about 10 years
    This should be the correct answer as it is the technique prescribed by php since a long time ago. The accepted answer is a hack and use-at-your-own-risk 'solution'.
  • Christian Studer
    Christian Studer over 6 years
    Note that the first variant using the object notation doesn't seem to work anymore in PHP 7.