0

I have the following XML data:

<?xml version="1.0" encoding="utf-8"?>
<source>
    <publisher>some-data</publisher>
    <publisherurl>some-data</publisherurl>
    <lastBuildDate>a-date</lastBuildDate>
    <element>
        <sub-element><![CDATA[some-data]]></sub-element>
    </element>
</source>

I'm trying to use PHP's built in DOMdocument parser to update the text inside sub-element.

I've tried:

$dom=new DOMDocument();
$dom->load("document.xml");

$ele=$root->getElementsByTagName('element');
foreach ($ele as $e) {
    $e->getElementsByTagName('sub-element')->item(0)->nodeValue = "new val";
}

this kind of works but it removes the CDATA and just replaces it with new-val. I want to preserve the CDATA field so I tried the following:

$dom=new DOMDocument();
$dom->load("document.xml");

$ele=$root->getElementsByTagName('element');
foreach ($ele as $e) {  
    $sub=$e->getElementsByTagName('sub-element');   
    foreach($sub->childNodes as $child) {
        if ($child->nodeType == XML_CDATA_SECTION_NODE) {
            $child->nodeValue = 'new-val';
        }
    }
}

This seems like it should work but PHP returns the following Notice

Undefined property: DOMNodeList::$childNodes

Feel like I'm on the right path but I just can't figure out what I'm doing wrong here. Does anyone know how to fix?

My end goal output is:

<?xml version="1.0" encoding="utf-8"?>
<source>
    <publisher>some-data</publisher>
    <publisherurl>some-data</publisherurl>
    <lastBuildDate>a-date</lastBuildDate>
    <element>
        <sub-element><![CDATA[new-val]]></sub-element>
    </element>
</source>

1 Answer 1

3

You need to compare against firstChild

$xml = '<?xml version="1.0" encoding="utf-8"?>
<source>
    <publisher>some-data</publisher>
    <publisherurl>some-data</publisherurl>
    <lastBuildDate>a-date</lastBuildDate>
    <element>
        <sub-element><![CDATA[some-data]]></sub-element>
    </element>
    <element>
        <sub-element>some-other-data</sub-element>
    </element>
</source>';

$dom = new DOMDocument();
$dom->loadXML($xml);

$ele=$dom->getElementsByTagName('element');
foreach ($ele as $e) {
    $item = $e->getElementsByTagName('sub-element')->item(0);
    if($item->firstChild->nodeType == XML_CDATA_SECTION_NODE) { //<------
        //it's CDATA do whatever
         $item->firstChild->nodeValue = "new val";
    } else {
        //it's not , do something else
        $item->nodeValue = "new val";
    }
}
echo "<pre>";
print_r(htmlentities($dom->saveXML()));
echo "</pre>";

Output:

<?xml version="1.0" encoding="utf-8"?>
<source>
    <publisher>some-data</publisher>
    <publisherurl>some-data</publisherurl>
    <lastBuildDate>a-date</lastBuildDate>
    <element>
        <sub-element><![CDATA[new val]]></sub-element>
    </element>
    <element>
        <sub-element>new val</sub-element>
    </element>
</source>

PS: if you don't have to make a distinction between CDATA or not, just use firstChild

foreach ($ele as $e) {
    $item = $e->getElementsByTagName('sub-element')->item(0);
    $item->firstChild->nodeValue = "new val";
}
Sign up to request clarification or add additional context in comments.

3 Comments

The output I'm looking for would be this: <sub-element><![CDATA[new val]]></sub-element> How do I do that?
$item->firstChild->nodeValue = "new val"; Edited, take a look
Or if can just ignore the comparison and use firstChild all the time

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.