re-add CDATA when saving simpleXMLObject

gherkins

Loading a rather large nested XML file via

$content = simplexml_load_string(
    $xmlString, null, LIBXML_NOCDATA
);

Is there a simple way to add CDATA escaping back to all nodes when exporting/saving the xml back to a string?

I thought that something like this would work.

 $xmlIterator = new RecursiveIteratorIterator(
    new SimpleXMLIterator($xml_string), 
    RecursiveIteratorIterator::SELF_FIRST
 );
 foreach ($xmlIterator as $nodeName => &$node) {
   $node->textContent = sprintf('<![CDATA[%s]]>', $node->textContent);
 }

as seen here https://stackoverflow.com/a/31983626/1468708

But then you couldn't use node via reference to update the node directly. Otherwise I would have tried to add cdata via the tree directly.

IMSoP

SimpleXML tries to abstract away differences in encoding of the XML, and concentrate on the semantic data content, so it doesn't directly expose the difference between <![CDATA[foo&bar]]> and foo&amp;bar.

Luckily, PHP also has an implementation of the DOM, which does include these "lower-level" details - and you can use it interchangeably with SimpleXML using dom_import_simplexml and simplexml_import_dom, which switch between the two APIs without re-parsing the XML.

Specifically, the DOM has "node types" of XML_TEXT_NODE and XML_CDATA_SECTION_NODE, with corresponding DOMText and DOMCdataSection classes. So you need to iterate the DOM recursively, finding any XML_TEXT_NODE nodes and replacing them with a new DOMCdataSection object with the same text.

We can use the recursive iterator you have already to get all the elements in the XML, and then switch to the DOM to handle their text content:

$simplexml = new SimpleXMLIterator($xml);

$xmlIterator = new RecursiveIteratorIterator(
    $simplexml,
    RecursiveIteratorIterator::SELF_FIRST
);
foreach ($xmlIterator as $nodeName => $node) {
    $nodeAsDom = dom_import_simplexml($node);
    var_dump($nodeAsDom); // DOM logic goes here
}
 
echo $simplexml->asXML();

For each DOM node, we then loop over its children looking for Text nodes and replacing them. Note that we need the new DOMCdataSection object to be "owned by" the same document as the original, so we use a helper function rather than directly calling the constructor:

    foreach ( $nodeAsDom->childNodes as $childNode ) {
        if ( $childNode->nodeType === XML_TEXT_NODE ) {
            $cdataNode = $nodeAsDom->ownerDocument->createCdataSection($childNode->data);
            $nodeAsDom->replaceChild($cdataNode, $childNode);
        }
    }

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Saving CDATA with saveXML in PHP

Add completion block when saving to user defaults

django rest add data to serializer when saving

How to add a character when saving files with lapply

add title when saving element as pdf

Saving input to a file is replaced when re-running

Add CDATA to a Node Value in a loop

Office Web Add-ins - Internal error when saving settings

How to add a delay when saving video frames as images

Django User Model: add extra behavior when saving

How to add alternating blank lines when saving csv file in Pandas

How to add current user data when saving in django model

xsl:when test with CDATA not working

XML to JSON when there is <![CDATA[]]> in PHP

In Nuxt w/ Express how to prevent re-compilation when saving server

How to add <! [CDATA[ tag to exist XML file

XSLT to XML transform | add url and CDATA to tags

When is a CDATA section necessary within a script tag?

How to preserve newlines in CDATA when generating XML?

AttributeError: free when taking ownership or freeing cdata

IndexOutOfBoundsException when processing empty CDATA with Transformer

Bootstrap Dropdown: add class when re-rendered

How to re-add "unique" salt when user logs in?

How to add tags when saving an object in an Algolia index using the Java API

"Error: Don't know how to add RHS to a theme object" when saving theme formatting in R

How to add title to a networkD3 visualisation when saving as a web page?

Firebase Realtime Database not saving data when I add "location.replace"

ConcurrentModificationException when saving entity

Django: When saving issue