How to Retrieve Comments from Within an Xml Document in PHP

How to retrieve comments from within an XML Document in PHP

SimpleXML cannot handle comments, but the DOM extension can. Here's how you can extract all the comments. You just have to adapt the XPath expression to target the node you want.

$doc = new DOMDocument;
$doc->loadXML(
'<doc>
<node><!-- First node --></node>
<node><!-- Second node --></node>
</doc>'
);

$xpath = new DOMXPath($doc);

foreach ($xpath->query('//comment()') as $comment)
{
var_dump($comment->textContent);
}

Is there any way to retrieve the comments from an XML file?

You can use XMLReader to read through all of the nodes and pull out the comments. I've included some sample code to get you started, as it just pulls out the nodes, and doesn't take into account where the comment is inside, below or above any xml nodes.

$comments = '';
$xml =<<<EOX
<xml>
<!--data here -->
<data>
<!-- more here -->
<more />
</data>
</xml>
EOX;

$reader = new XMLReader();
$reader->XML($xml);

while ($reader->read()) {
if ($reader->nodeType == XMLReader::COMMENT) {
$comments .= "\n".$reader->value;
}
}

$reader->close();

echo "all comments below:\n-------------------".$comments

The expected output is:

all comments below:
-------------------
data here
more here

So just the values of the comments (not the <!-- -->) will be taken, as well as whitespace.

How can i read the first XML comment in PHP?

What about this:

$xpath = new DOMXPath($xml);
foreach ($xpath->query('//comment()') as $comment) {
var_dump($comment->textContent);
}

Since you probably only want the first one:

$xpath = new DOMXPath($xml);
$results = $xpath->query('//comment()');
$comment = $results[0];
var_dump($comment);

Source: How to retrieve comments from within an XML Document in PHP

How to load XML file with its comments using PHP

Use file_get_contents instead:

$xml = file_get_contents('https://xxxxx/xxxxx.xml');

If you need xml to load into object then I think you have to use DOMDocument():

$dom = new DOMDocument();
$dom->load('https://xxxxx/xxxxx.xml');
$xpath = new DOMXpath($dom);
$comment = $xpath->evaluate('string(//channel/item[1]/comment())');
echo $comment;

var_dump($xml); // showing comments

Sample Image

Commenting and Un-Commenting a Node in an XML Document

Comments can be created using DOMDocument::createComment(). Replacing comments with actual nodes is just like replacing any other node type, use DOMElement::replaceChild().

$doc = new DOMDocument;
$doc->loadXML('<?xml version="1.0"?>
<example>
<a>
<aardvark/>
<adder/>
<alligator/>
</a>
</example>
');

$node = $doc->getElementsByTagName('a')->item(0);

// Comment by making a comment node from target node's outer XML
$comment = $doc->createComment($doc->saveXML($node));
$node->parentNode->replaceChild($comment, $node);
echo $doc->saveXML();

// Uncomment by replacing the comment with a document fragment
$fragment = $doc->createDocumentFragment();
$fragment->appendXML($comment->textContent);
$comment->parentNode->replaceChild($fragment, $comment);
echo $doc->saveXML();

The (super-simplified) examples above should output something like:

<?xml version="1.0"?>
<example>
<!--<a>
<aardvark/>
<adder/>
<alligator/>
</a>-->
</example>
<?xml version="1.0"?>
<example>
<a>
<aardvark/>
<adder/>
<alligator/>
</a>
</example>

Reference

  • DOMDocument::createComment() to create <-- comments -->
  • DOMElement::replaceChild() to swap nodes around
  • DOMDocument::createDocumentFragment() to create a document fragment
  • DOMDocumentFragment::appendXML() to append a string of xml to a fragment
  • DOMDocument::saveXML() to get the XML for an element
  • DOMCharacterData->data to get the content of a comment

PHP SimpleXML read comment with xPath

Alternatively, you could use DOMDocument to access those comments. Example:

$dom = new DOMDocument();
$dom->load($feed_url);
$xpath = new DOMXpath($dom);
$comment = $xpath->evaluate('string(//channel/item[1]/title/comment())');
echo $comment;

How to get comments within an HTML element by XPath?

Comments have to be selected relative to the given Context node.

The // (descendant-or-self) prefix in the xpath expression is selecting every comment anywhere in the node regardless of context.

I suggest to do a relative search using .// (self, descendant-or-self) xpath expression to search in the provided context.

For example,

<?php
$xml = <<< XML
<!-- FIRST -->
<div id="parent">
<!-- SECOND -->
<span id="child">
<!-- THIRD -->
</span>
</div>
XML;

$dom = new DOMDocument;
$dom->loadHTML($xml);
$xpath = new DOMXpath($dom);

All comments in the document

<?php
$comments = $xpath->query('.//comment()', $dom);
foreach($comments as $comment){
echo $comment->nodeValue.PHP_EOL;
}
 FIRST
SECOND
THIRD

All comments in the div#parent

<?php
$el = $dom->getElementById('parent');
$comments = $xpath->query('.//comment()', $el);
foreach($comments as $comment){
echo $comment->nodeValue.PHP_EOL;
}
 SECOND
THIRD

All comments in span#child

<?php
$el = $dom->getElementById('child');
$comments = $xpath->query('.//comment()', $el);
foreach($comments as $comment){
echo $comment->nodeValue.PHP_EOL;
}
 THIRD

Is it possible to insert a comment tag into an xml using simplexml?

Unfortunately, SimpleXML doesn't handle comments. As it's been mentionned, DOM does handle comments but it's a kind of a bother to use for simple stuff, compared to SimpleXML.

My recommendation: try SimpleDOM. It's an extension to SimpleXML, so everything works the same and it has a bunch of useful methods to deal with DOM stuff.

For instance, insertComment($content, $mode) can append to or insert comments before or after a given node. For example:

include 'SimpleDOM.php';

$root = simpledom_load_string('<root><value/></root>');

$root->value->insertComment(' mode: append ', 'append');
$root->value->insertComment(' mode: before ', 'before');
$root->value->insertComment(' mode: after ', 'after');

echo $root->asPrettyXML();

...will echo

<?xml version="1.0"?>
<root>
<!-- mode: before -->
<value>
<!-- mode: append -->
</value>
<!-- mode: after -->
</root>


Related Topics



Leave a reply



Submit