How to get perticular node value? in xml using php - php

I am using xml data using a url & because the xml is too long I just want to check condition to get particular node values only :-
Here is my code :-
<?php
$doc = new DOMDocument('1.0', 'utf-8');
$doc->load("https://retailapi.apparel21.com/RetailAPI/products?countrycode=au");
$xpath = new DOMXpath($doc);
/*foreach ($xpath->query("/Products/Product[Code='00122']") as $node)
{
echo $node->nodeValue;
echo "Hi<br>";
}*/
echo $xpath->query("/Products/Product[Code='00122']")->item(0)->nodeValue;
?>
As you can see that I already used foreach loop & successfully executed the condition but.....the thing is inside it, it prints whole data of that all the nodes of it's parent node.
Confused? :)
Ok no worries, just execute this url: https://retailapi.apparel21.com/RetailAPI/products?countrycode=au; please click on Proceed anyway button then wait for some time.
There are many Product tags...now I want the data of the following nodes :-
Id
Code
Name
Description
whose code=00122 that's the first product's data.
I applied foreach then it printed all node's data of that product. I applied simple single statement but then also it printed all node's data :(
And one more thing is can't it be done by simplexml_load_file function?
One more thing :- You can see I am loading url, so the thing is it will read the whole xml first. Can't we query in this itself so that it will only take only related product tags so the loading time can be reduced.
Can anyone please help?

You're nearly there. Replace DOMXpath::query() with DOMXpath::evaluate(). It allows to use Xpath expressions that return scalars like strings. Now the second argument of evaluate() (or query()) is the context, so you can iterate all nodes from one expression and fetch the details using xpath expressions depending on a context node:
$doc = new DOMDocument('1.0', 'utf-8');
$doc->load("https://retailapi.apparel21.com/RetailAPI/products?countrycode=au");
$xpath = new DOMXpath($doc);
$result = [];
foreach ($xpath->evaluate("/Products/Product[Code='00122']") as $node) {
$result[] = [
'id' => $xpath->evaluate('string(Id)', $node),
'code' => $xpath->evaluate('string(Code)', $node),
'name' => $xpath->evaluate('string(Name)', $node),
];
}
var_dump($result);
A call like $xpath->evaluate('Id', $node) would return a list with all Id element nodes that are children of $node. The Xpath function string() casts the first node in this list into a string and returns it. If the list is empty the result will be an empty string.

Related

Search for substrings of text in a node in a XML file

I have this PHP I found in a Q&A forum that queries an XML file:
$doc = new DOMDocument; // Create a new dom document
$doc->preserveWhiteSpace = false; // Set features
$doc->formatOutput = true; // Create indents on xml
$doc->Load('i.xml'); // Load the file
$xpath = new DOMXPath($doc);
$query = '//users/user/firstname[.= "'.$_POST["search"].'"]'; // The xpath (starts from root node)
$names = $xpath->query($query); // A list of matched elements
$Output="";
foreach ($names as $node) {
$Output.=$doc->saveXML($node->parentNode)."\n"; // We get the parent of "<firstname>" element (the entire "<user>" node and its children) (maybe get the parent node directly using xpath)
// and use the saveXML() to convert it to string
}
echo $Output."<br>\n\n"; // The result
echo "<hr><br><b>Below view the results as HTML content. (See also the page's HTML code):</b>\n<pre>".htmlspecialchars($Output)."</pre>";
The script will search the values of all the firstname nodes in the XML document from the input from the POST, and will return the parent node of the nodefirstname, if the POST input value matches any of the node values.
This script works well, but it only returns queries that contain the entire value of a firstname node, and will not work if I search for a substring of the node's text (e.g a query for Potato will return Potato, but a query for Pot, will not give me results for Potato).
So how do you get a result that only contains a substring of the node's text, instead of the entire value ?

Get just the first item with DOMDocument in PHP

I am using this below code to get the elements that are in special HTML element :
$dom = new DOMDocument();
#$dom->loadHTML($google_html);
$xpath = new DOMXPath($dom);
$tags = $xpath->query('//span[#class="st"]');
foreach ($tags as $tag) {
echo $node_value;
}
Now, the problem is that, the code gives all of the elements that are in one special class, but i just need to get the First item that has that class name.
So i don't need using foreach loops.
How to use that code to get JUST the FIRST item ?
The following will make sure you get just the first one in the DOMNodeList that is returned
$xpath->query('//span[#class="st"][1]');
The following gets the only item in the DOMNodeList
$tags = $xpath->query('//span[#class="st"][1]');
$first = $tags->item(0);
$text = $first->textContent;
See XPath: Select first element with a specific attribute

Parsing inline tags with SimpleXML

I'm using SimpleXML & PHP to parse an XML element in the following form:
<element>
random text with <inlinetag src="http://url.com/">inline</inlinetag> XML to parse
</element>
I know I can reach inlinetag using $element->inlinetag, but I don't know how to reach it in such a way that I can basically replace the inlinetag with a link to the attribute source without using it's location in the text. The result would basically have to look like this:
here is a random text with inline XML
This may be a stupid questions, I hope someone here can help! :)
I found a way to do this using DOMElement.
One way to replace the element is by cloning it with a different name/attributes. Here is is a way to do this, using the accepted answer given on How do you rename a tag in SimpleXML through a DOM object?
function clonishNode(DOMNode $oldNode, $newName, $replaceAttrs = [])
{
$newNode = $oldNode->ownerDocument->createElement($newName);
foreach ($oldNode->attributes as $attr)
{
if (isset($replaceAttrs[$attr->name]))
$newNode->setAttribute($replaceAttrs[$attr->name], $attr->value);
else
$newNode->appendChild($attr->cloneNode());
}
foreach ($oldNode->childNodes as $child)
$newNode->appendChild($child->cloneNode(true));
$oldNode->parentNode->replaceChild($newNode, $oldNode);
}
Now, we use this function to clone the inline element with a new element and attribute name. Here comes the tricky part: iterating over all the nodes will not work as expected. The length of the selected nodes will change as you clone them, as the original node is removed. Therefore, we only select the first element until there are no elements left to clone.
$xml = '<element>
random text with <inlinetag src="http://url.com/">inline</inlinetag> XML to parse
</element>';
$dom = new DOMDocument;
$dom->loadXML($xml);
$nodes= $dom->getElementsByTagName('inlinetag');
echo $dom->saveXML(); //<element>random text with <inlinetag src="http://url.com/">inline</inlinetag> XML to parse</element>
while($nodes->length > 0) {
clonishNode($nodes->item(0), 'a', ['src' => 'href']);
}
echo $dom->saveXML(); //<element>random text with inline XML to parse</element>
That's it! All that's left to do is getting the content of the element tag.
Is this the result you want to achieve?
<?php
$data = '<element>
random text with
<inlinetag src="http://url.com/">inline
</inlinetag> XML to parse
</element>';
$xml = simplexml_load_string($data);
foreach($xml->inlinetag as $resource)
{
echo 'Your SRC attribute = '. $resource->attributes()->src; // e.g. name, price, symbol
}
?>

Can explain this block Code to me PHP XML DOMDocument Syntax

I am currently learning different ways to iterate through the xml document tags using the
php DOMDocument object, I understand the foreach loop for iterating through the tags, but the $element->item(0)->childNodes->item(0)->nodeValue is a bit unclear to me could somebody explain to me in detail? Thank you.
<?php
$xmlDoc = new DOMDocument();
$xmlDoc->load('StudentData.xml');
$studentRoot = $xmlDoc->getElementsByTagName('Student');
for ($i = 0; $i < ($studentRoot->length); $i++) {
$firstNameTags = $studentRoot->item($i)->getElementsByTagName('FirstName');
echo $firstNameTags->item(0)->childNodes->item(0)->nodeValue.' <br />';
}
/* so much easier and clear to understand! */
foreach($studentRoot as $node) {
/* For every <student> Tag as a separate node,
step into it's child node, and for each child,
echo the text content inside */
foreach($node->childNodes as $child) {
echo $child->textContent.'<br />';
}
}
?>
$elements->item(0)->childNodes->item(0)->nodeValue
First:
$elements
The current elements$ as parsed and referenced. In the code example, that would be:
$firstNameTags = $studentRoot->item($i)->getElementsByTagName('FirstName');
$firstNameTags->...
Next:
->item(0)
Get a reference to the first of the $elements item in the node list. Since this is zero-indexed, ->item(0) would get the first node in the list by index.
->childNodes
Get a list of the child nodes to that first $elements node referenced by ->item(0) above. As there is no (), this is a (read only) property of the DOMNodeList.
->item(0)
Again, get the first node in the list of child nodes by index.
->nodeValue
The value of the node itself.
If the form of the state alone:
$obj->method()->method()->prop
Confuses you, look into method chaining, which is what this uses to put all of those method calls together.
$ Note, you left off the s, but that indicates there's one or more possible by convention. So $element would be zero or one element reference, $elements might be zero, one or more in a collection of $element.

How to get a specific node text using php DOM

I am trying to get the value (text) of a specific node from an xml document using php DOM classes but I cannot do it right because I get the text content of that node merged with its descendants.
Let's suppose that I need to get the trees from this document:
<?xml version="1.0"?>
<trees>
LarchRedwoodChestnutBirch
<trimmed>Larch</trimmed>
<trimmed>Redwood</trimmed>
</trees>
And I get:
LarchRedwoodChestnutBirchLarchRedwood
You can see that I cannot remove the substring LarchRedwood made by the trimmed trees from the whole text because I would get only ChestnutBirch and it is not what I need.
Any suggest? (Thanx)
I got it. This works:
function specificNodeValue($node, $implode = true) {
$value = array();
if ($node->childNodes) {
for ($i = 0; $i < $node->childNodes->length; $i++) {
if (!(#$node->childNodes->item($i)->tagName)) {
$value[] = $node->childNodes->item($i)->nodeValue;
}
}
}
return (is_string($implode) ? implode($implode, $value) : ($implode === true ? implode($value) : $value));
}
A given node is like a root, if you get no tagName when you parse its child nodes then it is itself, so the value of that child node it is its own value.
Inside a bad formed xml document a node could have many pieces of value, put them all into an array to get the whole value of the node.
Use the function above to get needed node value without subnode values merged within.
Parameters are:
$node (required) must be a DOMElement object
$implode (optional) if you want to get a string (true by default) or an array (false) made up by many pieces of value. (Set a string instead of a boolean value if you wish to implode the array using a "glue" string).
You can try this to remove the trimmed node
$doc = new DOMDocument('1.0', 'utf-8');
$doc->loadXML($xml);
$xpath = new DOMXpath($doc);
$trees = $doc->getElementsByTagName('trees')->item(0);
foreach ($xpath->query('/trees/*') as $node)
{
$trees->removeChild($node);
}
echo $trees->textContent;
echo $trees->nodeValue;
Use $node->nodeValue to get a node's text content. If you use $node->textContent, you get all text from the current node and all child nodes.
Ideally, the XML should be:
<?xml version="1.0"?>
<trees>
<tree>Larch</tree>
<tree>Redwood</tree>
<tree>Chestnut</tree>
<tree>Birch</tree>
</trees>
To split "LarchRedwoodChestnutBirch" into separate words (by capital letter), you'll need to use PHP's "PCRE" functions:
http://www.php.net/manual/en/book.pcre.php
'Hope that helps!

Categories