php domdocument get node value where attribute value is - php

Say my XML looks like this:
<record>
<row name="title">this item</row>
<row name="url">this url</row>
</record>
Now I'm doing something like this:
$xml = new DOMDocument();
$xml->load('xmlfile.xml');
echo $xml->getElementByTagName('row')->item(0)->attributes->getNamedItem('title')->nodeValue;
But this just gives me:
NOTICE: Trying to get property of non-object id
Does anybody know how to get the node value where the "name" attribute has value "title"?

Try:
$xml = new DOMDocument();
$xml->loadXml('
<record>
<row name="title">this item</row>
<row name="url">this url</row>
</record>
');
$xpath = new DomXpath($xml);
// traverse all results
foreach ($xpath->query('//row[#name="title"]') as $rowNode) {
echo $rowNode->nodeValue; // will be 'this item'
}
// Or access the first result directly
$rowNode = $xpath->query('//row[#name="title"][1]')->item(0);
if ($rowNode instanceof DomElement) {
echo $rowNode->nodeValue;
}

foreach ($xml->getElementsByTagName('row') as $element)
{
if ($element->getAttribute('name') == "title")
{
echo $element->nodeValue;
}
}

$xpath = new DOMXPath( $xml );
$val = $xpath->query( '//row[#name="title"]' )->item(0)->nodeValue;

Related

how to get the different tag values when receiving response from an xml file

i have an xml file and a php file.i have received a result from an the xml file but i am not being able to get the different values of the tags.what i want is the data from individual tags.Any idea how to do it?
Here is the xml file:
<?xml version="1.0" encoding="utf-8"?>
<users xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<user>
<id>1</id>
<username>neem99</username>
<password>dbhcasvc</password>
<email>vgwdevwe#hfvuejd.com</email>
</user>
</users>
Sample php file:
$xp = new DOMXPath( $dom );
echo var_dump($xp);
$col = $xp->query( $query );
echo var_dump($col);
$array = array();
if( $col->length > 0 ){
foreach( $col as $node) echo $node->nodeValue
}
result : 1 neem99 dbhcasvc vgwdevwe#hfvuejd.com
DOMXpath::evaluate() allows to use Xpath expressions that return scalar values. string() casts a list of nodes to a string by returning the text content of the first node.
Demo:
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
// get first user id
var_dump($xpath->evaluate('string(/users/user/id)'));
//iterate all user nodes
foreach ($xpath->evaluate('/users/user') as $user) {
// get its username
var_dump($xpath->evaluate('string(username)', $user));
}
I would do like:
$doc = new DOMDocument; #$doc->load('yourFileName.xml');
$user = $doc->getElementsByTagName('user');
foreach($user as $u){
echo 'nodeName:'.$u->nodeName.'; nodeValue:'.$u->nodeValue.PHP_EOL;
}

Replace HTML tags with DOMdocument while keeping nested tags [duplicate]

I'm trying to figure out how to rename a node in XML using PHP?
I Have come this far:
$dom = new DOMDocument( '1.0' );
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
// load the xml file
$dom->loadXML( '<?xml version="1.0" encoding="ISO-8859-1"?>
<library>
<data>
<invite>
<username>jmansa</username>
<userid>1</userid>
</invite>
<update>1</update>
</data>
</library>', LIBXML_NOBLANKS );
$xpath = new DOMXPath($dom);
//find all 'data' nodes.
$node = $xpath->query("//data");
// if found
if( $node->length ) {
foreach ($node as $n) {
// RENAME HERE? //
}
}
echo "<xmp>". $dom->saveXML() ."</xmp>";
Now, I want to rename <data> to <invites>. Can this be done and if yes, how?
A Node's name ("data" or "invites" respectively) cannot be renamed via the DOM because the Node::nodeName property is read-only.
You can create a new node named "invites", append it before the "data" node, move the children of "data" to the new "invites" node, remove the "data" node, and then output the tree to get your result.
Example:
<?php
// Create a test document.
$dom = new DOMDocument( '1.0' );
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
// Load the xml file.
$dom->loadXML('<?xml version="1.0" encoding="ISO-8859-1"?'.'>
<library>
<data attr1="1" attr2="2">
<invite>
<username>jmansa</username>
<userid>1</userid>
</invite>
<update>1</update>
</data>
</library>', LIBXML_NOBLANKS );
$xpath = new DOMXPath($dom);
// Convert <data> to <invites>.
if ($dataNode = $xpath->query("/library/data")->item(0))
{
// Create the <invites> node.
$invitesNode = $dom->createElement('invites');
$dataAttrs = $dataNode->attributes;
foreach ($dataAttrs as $dataAttr)
{ $invitesNode->setAttributeNodeNS($dataAttr->cloneNode()); }
$dom->documentElement->appendChild($invitesNode);
// Move the <data> children over.
if ($childNodes = $xpath->query("/library/data/*"))
{
foreach ($childNodes as $childNode)
{ $invitesNode->appendChild($childNode); }
}
// Remove <data>.
$dataNode->parentNode->removeChild($dataNode);
}
// Test the result.
echo $dom->saveXML();
?>
My solution, with extended test case:
// Changes the name of element $element to $newName.
function renameElement($element, $newName) {
$newElement = $element->ownerDocument->createElement($newName);
$parentElement = $element->parentNode;
$parentElement->insertBefore($newElement, $element);
$childNodes = $element->childNodes;
while ($childNodes->length > 0) {
$newElement->appendChild($childNodes->item(0));
}
$attributes = $element->attributes;
while ($attributes->length > 0) {
$attribute = $attributes->item(0);
if (!is_null($attribute->namespaceURI)) {
$newElement->setAttributeNS('http://www.w3.org/2000/xmlns/',
'xmlns:'.$attribute->prefix,
$attribute->namespaceURI);
}
$newElement->setAttributeNode($attribute);
}
$parentElement->removeChild($element);
}
function prettyPrint($d) {
$d->formatOutput = true;
echo '<pre>'.htmlspecialchars($d->saveXML()).'</pre>';
}
$d = new DOMDocument( '1.0' );
$d->loadXML('<?xml version="1.0"?>
<library>
<data a:foo="1" x="bar" xmlns:a="http://example.com/a">
<invite>
<username>jmansa</username>
<userid>1</userid>
</invite>
<update>1</update>
</data>
</library>');
$xpath = new DOMXPath($d);
$elements = $xpath->query('/library/data');
if ($elements->length == 1) {
$element = $elements->item(0);
renameElement($element, 'invites');
}
prettyPrint($d);
By the way, I added this solution as a comment to the PHP documentation for DOMElement.

Rename an XML node using PHP

I'm trying to figure out how to rename a node in XML using PHP?
I Have come this far:
$dom = new DOMDocument( '1.0' );
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
// load the xml file
$dom->loadXML( '<?xml version="1.0" encoding="ISO-8859-1"?>
<library>
<data>
<invite>
<username>jmansa</username>
<userid>1</userid>
</invite>
<update>1</update>
</data>
</library>', LIBXML_NOBLANKS );
$xpath = new DOMXPath($dom);
//find all 'data' nodes.
$node = $xpath->query("//data");
// if found
if( $node->length ) {
foreach ($node as $n) {
// RENAME HERE? //
}
}
echo "<xmp>". $dom->saveXML() ."</xmp>";
Now, I want to rename <data> to <invites>. Can this be done and if yes, how?
A Node's name ("data" or "invites" respectively) cannot be renamed via the DOM because the Node::nodeName property is read-only.
You can create a new node named "invites", append it before the "data" node, move the children of "data" to the new "invites" node, remove the "data" node, and then output the tree to get your result.
Example:
<?php
// Create a test document.
$dom = new DOMDocument( '1.0' );
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
// Load the xml file.
$dom->loadXML('<?xml version="1.0" encoding="ISO-8859-1"?'.'>
<library>
<data attr1="1" attr2="2">
<invite>
<username>jmansa</username>
<userid>1</userid>
</invite>
<update>1</update>
</data>
</library>', LIBXML_NOBLANKS );
$xpath = new DOMXPath($dom);
// Convert <data> to <invites>.
if ($dataNode = $xpath->query("/library/data")->item(0))
{
// Create the <invites> node.
$invitesNode = $dom->createElement('invites');
$dataAttrs = $dataNode->attributes;
foreach ($dataAttrs as $dataAttr)
{ $invitesNode->setAttributeNodeNS($dataAttr->cloneNode()); }
$dom->documentElement->appendChild($invitesNode);
// Move the <data> children over.
if ($childNodes = $xpath->query("/library/data/*"))
{
foreach ($childNodes as $childNode)
{ $invitesNode->appendChild($childNode); }
}
// Remove <data>.
$dataNode->parentNode->removeChild($dataNode);
}
// Test the result.
echo $dom->saveXML();
?>
My solution, with extended test case:
// Changes the name of element $element to $newName.
function renameElement($element, $newName) {
$newElement = $element->ownerDocument->createElement($newName);
$parentElement = $element->parentNode;
$parentElement->insertBefore($newElement, $element);
$childNodes = $element->childNodes;
while ($childNodes->length > 0) {
$newElement->appendChild($childNodes->item(0));
}
$attributes = $element->attributes;
while ($attributes->length > 0) {
$attribute = $attributes->item(0);
if (!is_null($attribute->namespaceURI)) {
$newElement->setAttributeNS('http://www.w3.org/2000/xmlns/',
'xmlns:'.$attribute->prefix,
$attribute->namespaceURI);
}
$newElement->setAttributeNode($attribute);
}
$parentElement->removeChild($element);
}
function prettyPrint($d) {
$d->formatOutput = true;
echo '<pre>'.htmlspecialchars($d->saveXML()).'</pre>';
}
$d = new DOMDocument( '1.0' );
$d->loadXML('<?xml version="1.0"?>
<library>
<data a:foo="1" x="bar" xmlns:a="http://example.com/a">
<invite>
<username>jmansa</username>
<userid>1</userid>
</invite>
<update>1</update>
</data>
</library>');
$xpath = new DOMXPath($d);
$elements = $xpath->query('/library/data');
if ($elements->length == 1) {
$element = $elements->item(0);
renameElement($element, 'invites');
}
prettyPrint($d);
By the way, I added this solution as a comment to the PHP documentation for DOMElement.

Need to show child data on parent id

i'm struggling with Xpath, i have an xml list and i need to get the child data based on the parent id ...
My xml file :
<projecten>
<project id="1">
<titel>Shop 1</titel>
<siteurl>http://test.be</siteurl>
<screenshot>test.jpg</screenshot>
<omschrijving>comment 1</omschrijving>
</project>
<project id="2">
<titel>Shop 2</titel>
<siteurl>http://test2.be</siteurl>
<screenshot>test2.jpg</screenshot>
<omschrijving>comment</omschrijving>
</project>
</projecten>
the code i use to get for example the project 1 data (does not work):
$xmlDoc = new DOMDocument();
$xmlDoc->load(data.xml);
$xpath = new DOMXPath($xmlDoc);
$projectId = '1';
$query = '//projecten/project[#id='.$projectId.']';
$details = $xpath->query($query);
foreach( $details as $detail )
{
echo $detail->titel;
echo $detail->siteurl;
echo $detail->screenshot;
echo $detail->omschrijving;
}
But this does not show anything, if someone can point me out ... thanks
In addition to the solution already given you can also use:
foreach ($xpath->query(sprintf('/projecten/project[#id="%d"]', $id)) as $projectNode) {
echo
$projectNode->getElementsByTagName('titel')->item(0)->nodeValue,
$projectNode->getElementsByTagName('siteurl')->item(0)->nodeValue,
$projectNode->getElementsByTagName('screenshot')->item(0)->nodeValue,
$projectNode->getElementsByTagName('omschrijving')->item(0)->nodeValue;
}
or fetch the DOMText node values directly with Xpath
foreach ($xpath->query(sprintf('/projecten/project[#id="%d"]', $id)) as $projectNode) {
echo
$xpath->evaluate('string(titel)', $projectNode),
$xpath->evaluate('string(siteurl)', $projectNode),
$xpath->evaluate('string(screenshot)', $projectNode),
$xpath->evaluate('string(omschrijving)', $projectNode);
}
or import the node to SimpleXml
foreach ($xpath->query(sprintf('/projecten/project[#id="%d"]', $id)) as $projectNode) {
$detail = simplexml_import_dom($projectNode);
echo
$detail->titel,
$detail->siteurl,
$detail->screenshot,
$detail->omschrijving;
}
or even concatenate all the values directly in the XPath:
$xpath = new DOMXPath($dom);
echo $xpath->evaluate(
sprintf(
'concat(
/projecten/project[#id = %1$d]/titel,
/projecten/project[#id = %1$d]/siteurl,
/projecten/project[#id = %1$d]/screenshot,
/projecten/project[#id = %1$d]/omschrijving
', $id
)
);
Accessing the child nodes as you do:
echo $detail->title;
Is not valid, if you use DOM* functions. This would probably work if you were using SimpleXML.
For DOM* try this:
$dom = new DOMDocument;
$dom->loadXml('<projecten>
<project id="1">
<titel>Shop 1</titel>
<siteurl>http://test.be</siteurl>
<screenshot>test.jpg</screenshot>
<omschrijving>comment 1</omschrijving>
</project>
<project id="2">
<titel>Shop 2</titel>
<siteurl>http://test2.be</siteurl>
<screenshot>test2.jpg</screenshot>
<omschrijving>comment</omschrijving>
</project>
</projecten>
');
$id = 2;
$xpath = new DOMXPath($dom);
foreach ($xpath->query(sprintf('/projecten/project[#id="%s"]', $id)) as $projectNode) {
// repeat this for every needed node
$titleNode = $xpath->query('titel', $projectNode)->item(0);
if ($titleNode instanceof DOMElement) {
echo $titleNode->nodeValue;
}
// or us a loop for all child nodes
foreach ($projectNode->childNodes as $childNode) {
echo $childNode->nodeValue;
}
}

How do extract child element in XML using DOM in PHP 5.0?

I am having the XML like this
<?xml version="1.0" encoding="utf-8"?>
<root>
<mynode catid="10" catname="Animals" label="Animals" catdesc="" parent_id="2">
<mynode catid="11" catname="Lions" label="Lions" catdesc="" parent_id="10">
<mynode catid="12" catname="lion" label="lion" catdesc="" parent_id="11"/>
<mynode catid="13" catname="lioness" label="lioness" catdesc="" parent_id="11"/>
</mynode>
</mynode>
</root>
From this I want to remove
<?xml version="1.0" encoding="utf-8"?>
<root>
and
</root>
So expected result is
<mynode catid="10" catname="Animals" label="Animals" catdesc="" parent_id="2">
<mynode catid="11" catname="Lions" label="Lions" catdesc="" parent_id="10">
<mynode catid="12" catname="lion" label="lion" catdesc="" parent_id="11"/>
<mynode catid="13" catname="lioness" label="lioness" catdesc="" parent_id="11"/>
</mynode>
</mynode>
How can I do this?
Edit 1:TO Phil
$dom = new DomDocument();
//$dom->preserveWhitespace = false;
$dom->load('treewithchild.xml');
function DOMinnerHTML($element)
{
$innerHTML = "";
$children = $element->childNodes;
foreach ($children as $child)
{
$tmp_dom = new DOMDocument();
$tmp_dom->appendChild($tmp_dom->importNode($child, true));
$innerHTML.=trim($tmp_dom->saveXML());
echo $tmp_dom->saveXML();
}
return $innerHTML;
}
$dom->preserveWhiteSpace = false;
$domTable = $dom->getElementsByTagName("mynode");
foreach ($domTable as $tables)
{
//echo $tables;
DOMinnerHTML($tables);
}
As you want the inner markup of the <root> node, that is the element who's child nodes you'll want to iterate. You can access this element using the DOMDocument::documentElement property.
Try this (tested and working)
$doc = new DOMDocument;
$doc->load('treewithchild.xml');
$inner = '';
foreach ($doc->documentElement->childNodes as $child) {
$inner .= $doc->saveXML($child);
}
echo $inner;
I expect that the root element is returned also, you have to know that for each xml file an is added impliicitly, even if it exists in your file. so try to do this
$children = $element->childNodes->childNodes;
i think that would help you.

Categories