php count xml elements
With DOM
you can either use
$dom->getElementsByTagName('OfferName')->length;
to count all OfferName elements only. length
is an attribute of DOMNodeList
.
To count all OfferName elements within an OfferNameList, you can use DOMXPath::evaluate
$xpath->evaluate('count(//OfferNameList/OfferName');
Note that within is somewhat inaccurate here as the XPath query will only consider direct children. Please adjust your question if you need OfferName elements anywhere below a OfferNameList element.
Also note that //
will query anywhere in the document, which might be less efficient for large documents. If you know OfferNameList elements occur at a certain position in your XML only, use a direct path.
Full working example (run on codepad):
$xml = <<< XML
<root>
<NotOfferNameList>
<OfferName>...</OfferName>
<OfferName>...</OfferName>
<OfferName>...</OfferName>
</NotOfferNameList>
<OfferNameList>
<OfferName>...</OfferName>
<OfferName>...</OfferName>
<OfferName>...</OfferName>
</OfferNameList>;
</root>
XML;
$dom = new DOMDocument;
$dom->loadXml($xml);
// count all OfferName elements
echo $dom->getElementsByTagName('OfferName')->length, PHP_EOL; // 6
// count all OfferNameList/OfferName elements
$xp = new DOMXPath($dom);
echo $xp->evaluate('count(//OfferNameList/OfferName)'); // 3
PHP - Count XML Child Nodes
you can simply use this:
echo $xml->response->services->service->count();
or you use a loop:
$xml = new SimpleXMLElement($result);
foreach ($xml as $services) {
foreach($services as $service) {
echo "<pre>";
print_r($service->count());
echo "</pre>";
}
}
How to count nodes of an xml file with php?
You can't use the simple XML parser as a DOM document. Quite simply getElementsByTagName
doesn't exist in SimpleXML
. Use this instead:
$pars_emsc = new DOMDocument( "1.0", "ISO-8859-15" );
$pars_emsc->load("/file");
$count_folder_emsc= $pars_emsc->getElementsByTagName("Document")[0]->getElementsByTagName('Folder')->length;
print_r($count_folder_emsc);
Alternatively just do:
$pars_emsc= simplexml_load_file("/file");
$count_folder_emsc= $pars_emsc-> Document -> Folder -> count();
count xml elements/nodes using SimpleXML
This should work for you:
echo count($xml->channel->item);
EDIT:
Why you have to it this way? Because form simplexml_load_file()
you get a structure like this (print_r($xml);
):
SimpleXMLElement Object
(
[@attributes] => Array
(
[version] => 2.0
)
[channel] => SimpleXMLElement Object
(
[item] => Array
(
Because of this structure you have to access the object like i said (above).
Count all elements of a certain name in an XML file using PHP
It is easily done with XPath:
$doc = new DOMDocument();
$doc->load('my_file.xml', LIBXML_PARSEHUGE);
$xp = new DOMXPath($doc);
$count = $xp->evaluate('count(//Item)');
The XPath expression returns the number of all Item
tags in the document.
The LIBXML_PARSEHUGE
option only affects internal limits on the depth, entity recursion, and the size of text nodes. However, the DOM parser loads the entire document into memory.
For really huge files, use a SAX parser, which operates on each piece of XML sequentially (and thus loads only a small portion of the document into memory):
$counter = 0;
$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, function ($parser, $name) use (&$counter) {
if ($name === 'ITEM') {
$counter++;
}
}, null);
if (!($fp = fopen('my_file.xml', 'r'))) {
die('Could not open XML input');
}
while ($data = fread($fp, 4096)) {
if (!xml_parse($xml_parser, $data, feof($fp))) {
die(sprintf("XML error: %s at line %d",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
}
}
xml_parser_free($xml_parser);
Get Count of XML nodes in PHP
You can get a count of SimpleXML child-nodes just by using PHP's native count
function:
echo count($xml->datafile);
// 2
In this case, rather than using a for
loop and a count, it might make more sense just to use a foreach
loop instead:
foreach ($xml->datafile as $xmlItem) {
$fileName = "xml/";
$fileName .= $xmlItem;
...
}
See https://eval.in/951668 for a quick example
Count how many children are in XML with PHP
Try replacing foreach ($xml->alert->info[$i] as $entry)
with:
foreach ($xml->alert->info[$i] as $j => $entry)
The current item index will be $j
How to get count of distinct XML nodes?
While your solution works, and pretty efficiently given that it operates in O(n*k)
time (where n
is the number of nodes in the tree and k
is the number of vertices), I figured I'd propose an alternative solution that doesn't rely on arrays or references and is more generalized to work, not just for XML, but for any DOM tree. This solution also operates in O(n*k)
time, so it's just as efficient. The only difference is you can consume the values from a generator without having to build out the entire array first.
Modeling The Problem
The easiest way for me to understand this problem is to model it as a graph. If we model the document that way what we get are levels and vertices.
So effectively, this allows us to divide and conquer, breaking down the problem into two distinct steps.
- Count the cardinal child node names of a given vertical as the
sum
(verticies) - Find the
max
of the collectivesum
on the horizontal (levels)
Which means that if we do level-order traversal on this tree we should be able to easily produce the cardinality of node names as the maximum sum of all the verticals.
In other words, there's a cardinality problem of getting the distinct child node names of each node. Then there's the issue of finding the maximum sum for that entire level.
Minimal, Complete, Verifiable, Self-Contained Example
So to provide a Minimal, Complete, Verifiable, and Self-Contained Example I'm going to rely on extending PHP's DOMDocument
rather than the third party XML library you're using in your example.
It's probably worth noting that this code is not backwards compatible with PHP 5, (because of the use of
yield from
), so you must use PHP 7 for this implementation to work.
First, I'm going to implement a function in DOMDocument
that allows us to iterate over the DOM tree in level-order by using a generator.
class SpecialDOM extends DOMDocument {
public function level(DOMNode $node = null, $level = 0, $ignore = ["#text"]) {
if (!$node) {
$node = $this;
}
$stack = [];
if ($node->hasChildNodes()) {
foreach($node->childNodes as $child) {
if (!in_array($child->nodeName, $ignore, true)) {
$stack[] = $child;
}
}
}
if ($stack) {
yield $level => $stack;
foreach($stack as $node) {
yield from $this->level($node, $level + 1, $ignore);
}
}
}
}
The mechanics of the function itself is actually quite simple. It doesn't rely on passing around arrays or using references, but instead uses the DOMDocument
object itself, to build a stack of all child nodes in a given node. Then it can yield
this entire stack at once. This is the level part. At which point we rely on recursion to yield from each element in this stack any other nodes on the next level.
Here's a very simple XML document to demonstrate how straight-forward this is.
$xml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Record>
<SAMPLE>Some Sample</SAMPLE>
</Record>
<Note>
<SAMPLE>Some Sample</SAMPLE>
</Note>
<Record>
<SAMPLE>Sample 1</SAMPLE>
<SAMPLE>Sample 2</SAMPLE>
</Record>
</Data>
XML;
$dom = new SpecialDOM;
$dom->loadXML($xml);
foreach($dom->level() as $level => $stack) {
echo "- Level $level\n";
foreach($stack as $item => $node) {
echo "$item => $node->nodeName\n";
}
}
The output will look like this.
- Level 0
0 => Data
- Level 1
0 => Record
1 => Note
2 => Record
- Level 2
0 => SAMPLE
- Level 2
0 => SAMPLE
- Level 2
0 => SAMPLE
1 => SAMPLE
So at least now we have a way of knowing what level a node is on and in what order it appears on that level, which is useful for what we intend to do.
Now the idea of building a nested array is actually unnecessary to obtain the cardinality sought by max_count
. Because we already have access to the nodes themselves from the DOM tree. Which means we know what elements
are contained therein inside of our loop at each iteration. We don't have to generate the entire array at once to begin exploring it. We can do this at a level-order instead, which is actually really cool, because it means you can build a flat array to get to max_count
for each record.
Let me demonstrate how that would work.
$max = [];
foreach($dom->level() as $level => $stack) {
$sum = [];
foreach($stack as $item => $node) {
$name = $node->nodeName;
// the sum
if (!isset($sum[$name])) {
$sum[$name] = 1;
} else {
$sum[$name]++;
}
// the maximum
if (!isset($max[$level][$name])) {
$max[$level][$name] = 1;
} else {
$max[$level][$name] = max($sum[$name], $max[$level][$name]);
}
}
}
var_dump($max);
The output we get would look like this.
array(3) {
[0]=>
array(1) {
["Data"]=>
int(1)
}
[1]=>
array(2) {
["Record"]=>
int(2)
["Note"]=>
int(1)
}
[2]=>
array(1) {
["SAMPLE"]=>
int(2)
}
}
Which proves that we can calculate max_count
without the need for references or complex nested arrays. It's also easier to wrap your head around when you obviate the one-way mapping semantics of PHP arrays.
Synopsis
Here's the resulting output from this code on your sample XML document.
array(5) {
[0]=>
array(1) {
["Data"]=>
int(1)
}
[1]=>
array(1) {
["Record"]=>
int(2)
}
[2]=>
array(1) {
["SAMPLE"]=>
int(2)
}
[3]=>
array(4) {
["TITLE"]=>
int(1)
["SUBTITLE"]=>
int(1)
["AUTH"]=>
int(2)
["ABSTRACT"]=>
int(1)
}
[4]=>
array(2) {
["FNAME"]=>
int(1)
["DISPLAY"]=>
int(1)
}
}
Which is identical to the max_count
of each of your sub arrays.
- Level 0
Data => max_count 1
- Level 1
Record => max_count 2
- Level 2
SAMPLE => max_count 2
- Level 3
TITLE => max_count 1
SUBTITLE => max_count 1
AUTH => max_count 2
ABSTRACT => max_count 1
- LEVEL 4
FNAME => max_count 1
DISPLAY => max_count 1
To get the elements for any of these nodes throughout the loop just look at $node->childNodes
as you already have the tree (thus eliminating the need for references).
The only reason you needed to nest the elements into your array is because the keys of a PHP array have to be unique and since you're using the node name as the key this requires nesting to get the lower levels of the tree and still structure the value of max_count
properly. So it's a data structure problem there and I solve it differently by avoiding modeling the solution after the data structure.
php count xml elements isn't work fine when there is one element
Finally I made a solution: I must check whether product
is multidimensional array or not.
In first case:
Array
(
[0] => Array
([id]=>1...)
[1] => Array
([id]=>2...)
)
In Second case:
Array
(
[id]=>1...
)
Now I wrote a function to check whether it's multidimensional array or not. If the array is not multidimensional, so the count is one!
public function isMultiArray($arr){
foreach ($arr as $key) {
if (is_array($key)) {
return true;
}
else return false;
}
}
Related Topics
Fatal Error: Call to Undefined Function Socket_Create()
999 Error Code on Head Request to Linkedin
Load Data Local Infile Forbidden In... PHP
Check If Site Is Inside Iframe
In PHP, What Is the Differences Between Null and Setting a String to Equal 2 Single Quotes
PHP + SQL Server - How to Set Charset for Connection
Get Parent Directory of Running Script
Allowed Memory Size of 262144 Bytes Exhausted (Tried to Allocate 24576 Bytes)
Laravel 5 - After Login Redirect Back to Previous Page
Symfony2: After Successful Login Event, Perform Set of Actions
Get Updated Value in MySQL Instead of Affected Rows
How to Convert Uppercase Text to Title Case Using CSS
Decode a Quoted Printable Message in PHP
How to Get a PHP Class Constructor to Call Its Parent's Parent's Constructor
How to Count the Numbers of Rows That a MySQL Query Returned