After parsing some html, we have an array similar to ["\u00a0","\u00a0", "foo", "\u00a0", "bar"]. I want to filter out the "\u00a0" leaving us with ["foo", "bar"]. However, when we run an equality check, we are not getting a match.
We have tried
$item != "\u00a0"
$item != "\\u00a0"
$item != ""
$item != " "
$item != chr(160)
We get the same array returned without the "\u00a0" filtered out.
function getContent($xPath) {
$query = "//div[#class='WordSection1']";
$elements = $xPath->query($query);
if (!is_null($elements)) {
$content = array();
foreach ($elements as $element){
$nodes = $element->childNodes;
foreach ($nodes as $node) {
if ($node->nodeValue != "\u00a0") {
$content[] = $node->nodeValue;
}
}
}
return $content;
}
}
Try doing this condition:
if ($node->nodeValue != "\u{00a0}") {
$content[] = $node->nodeValue;
}
Here's the sample script I used:
<?php
$words = [chr(0xC2).chr(0xA0), 'foo', chr(0xC2).chr(0xA0), 'bar'];
$output = [];
foreach ($words as $word) {
if ($word != "\u{00a0}")
$output[] = $word;
}
var_dump($output);
Related
I need to recursively cast a PHP SimpleXMLObject to an array. The problem is that each sub element is also a PHP SimpleXMLElement.
Is this possible?
json_decode(json_encode((array) simplexml_load_string($obj)), 1);
Didn't test this one, but this seems to get it done:
function convertXmlObjToArr($obj, &$arr)
{
$children = $obj->children();
foreach ($children as $elementName => $node)
{
$nextIdx = count($arr);
$arr[$nextIdx] = array();
$arr[$nextIdx]['#name'] = strtolower((string)$elementName);
$arr[$nextIdx]['#attributes'] = array();
$attributes = $node->attributes();
foreach ($attributes as $attributeName => $attributeValue)
{
$attribName = strtolower(trim((string)$attributeName));
$attribVal = trim((string)$attributeValue);
$arr[$nextIdx]['#attributes'][$attribName] = $attribVal;
}
$text = (string)$node;
$text = trim($text);
if (strlen($text) > 0)
{
$arr[$nextIdx]['#text'] = $text;
}
$arr[$nextIdx]['#children'] = array();
convertXmlObjToArr($node, $arr[$nextIdx]['#children']);
}
return;
}
Taken from http://www.codingforums.com/showthread.php?t=87283
It is possible. This is a recursive function which prints out the tags of parent elements and the tags + contents of elements that have no more children. You can alter it to build an array:
foreach( $simpleXmlObject as $element )
{
recurse( $element );
}
function recurse( $parent )
{
echo '<' . $parent->getName() . '>' . "\n";
foreach( $parent->children() as $child )
{
if( count( $child->children() ) > 0 )
{
recurse( $child );
}
else
{
echo'<' . $child->getName() . '>';
echo iconv( 'UTF-8', 'ISO-8859-1', $child );
echo '</' . $child->getName() . '>' . "\n";
}
}
echo'</' . $parent->getName() . '>' . "\n";
}
I don't see the point since SimpleXMLObject can be threated just like arrays anyway...
But if you really need that, just check chassagnette's answer of in this thread or this post in a forum.
Depending on some troubles with CDATA, arrays etc.
(see: SimpleXMLElement to PHP Array)
I think, this would be the best solution:
public function simpleXml2ArrayWithCDATASupport($xml)
{
$array = (array)$xml;
if (count($array) === 0) {
return (string)$xml;
}
foreach ($array as $key => $value) {
if (is_object($value) && strpos(get_class($value), 'SimpleXML') > -1) {
$array[$key] = $this->simpleXml2ArrayWithCDATASupport($value);
} else if (is_array($value)) {
$array[$key] = $this->simpleXml2ArrayWithCDATASupport($value);
} else {
continue;
}
}
return $array;
}
Here my iterative (even if I don't think you will get a stack explosion by parsing data with a recursive one) implementation of a recursive cast to array. This is a more direct manner of doing it than passing through json_**decode functions:
function xml2Array(SimpleXMLElement $el): stdClass {
$ret = $el;
$stack = [&$ret];
while (count($stack) > 0) {
$cur = &$stack[count($stack) - 1];
array_splice($stack, -1);
$cur = (object) (array) $cur;
foreach ($cur as $key => $child) {
$childRef = &$cur->{$key};
if ($child instanceof SimpleXMLElement)
$stack[count($stack) - 1] = &$childRef;
elseif(is_array($child))
foreach ($childRef as $ckey => $cell) {
if ($cell instanceof SimpleXMLElement)
$stack[count($stack) - 1] = &$childRef[$ckey];
}
}
}
return $ret;
}
For those of you who have concerns about the CDATA case,
combining #ajayi-oluwaseun-emmanuel's answer with this answer worked for me:
$xml = simplexml_load_string($xml_str, 'SimpleXMLElement', LIBXML_NOCDATA);
$json = json_encode($xml);
$arr = json_decode($json,TRUE);
I am trying to loop through a string that contains html from a scraped webpage. First I look to return all links that contain the word "result" and then I would like to organize all the links that contain one of four cases, "base", "second", "third" or "latest" and create a fluid array.
Below is what I have come up with but it returns "Warning: strpos(): needle is not a string or an integer". I cannot seem to get the array cases to work.
Any help would be greatly appreciated. Thank you
$key = "results";
$reportKey = array("base", "second", "third","latest");
$keyArray = array();
foreach($html->find('a') as $element){
if (strpos($element->href, $key) !== false){
if (strpos($element->href, $reportKey) !== false){
$keyArray[] = $element->href;
}
}
}
echo "<pre>" . print_r($keyArray) . "</pre> ";
You can't use an array as a needle in strpos. Change second if to:
if (str_replace($reportKey, "", $element->href) === $element->href) {
$keyArray[] = $element->href;
}
strpos() does not allow more than one needle, you can do this:
$key = "results";
$reportKey = array("base", "second", "third","latest");
$keyArray = array();
foreach($html->find('a') as $element)
{
if (strpos($element->href, $key) !== false){
if (
strpos($element->href, $reportKey[0]) !== false
|| strpos($element->href, $reportKey[1]) !== false
|| strpos($element->href, $reportKey[2]) !== false
|| strpos($element->href, $reportKey[3]) !== false
){
$keyArray[] = $element->href;
}
}
}
echo "<pre>" . print_r($keyArray) . "</pre> ";
You could also do your own function, this is only an example:
function multi_strpos($string, $check, $getResults = false)
{
$result = array();
$check = (array) $check;
foreach ($check as $s)
{
$pos = strpos($string, $s);
if ($pos !== false)
{
if ($getResults)
{
$result[$s] = $pos;
}
else
{
return $pos;
}
}
}
return empty($result) ? false : $result;
}
A solution using array_map() and in_array():
$key = 'results';
$reportKey = ['base', 'second', 'third', 'latest'];
$keyArray = [];
foreach($html->find('a') as $element) {
if (false !== strpos($element->href, $key)) {
// I changed the condition here
$pos = array_map(fn($k) => strpos($element->href, $k) !== false, $reportKey);
if (in_array(true, $pos)){
$keyArray[] = $element->href;
}
}
}
$pos will be an array containing booleans based on matches between $element->href and $reportKey items.
Then we check with in_array() if it matched at least one time.
$val = array();
foreach ($value as $key) {
$nested = $this->Mdl_mymodel->arr($key);
if($nested != NULL) {
$n = 0;
foreach ($nested as $nest) {
$n++;
$val[$n] = $nest->num;
}
}
else {
$val = '';
}
print_r($val);
}
print_r($val);
Here $val inside the loop is printed but outside it is empty. I think i am missing something. Please help!
Note: I am using codeigniter.
$val = array();
foreach ($value as $key) {
$nested = $this->Mdl_mymodel->arr();
if($nested != NULL) {
$n = 0;
foreach ($nested as $nest) {
$n++;
$val[$n] = $nest->num;
}
}
else {
// $val = ''; Commented this line because you have already
// initialized $val. If you do not get records,
// it will return as blank array.
}
print_r($val);
}
print_r($val);
hi i have an array of about 20/30 items big.
i need to have it loop threw the array and echo out only the items with the text p1 in them.
the array looks like so
"lolly","lollyp1","top","topp1","bum","bump1","gee","geep1"
and so on
i have tried to use something like this
foreach ($arr as $value) {
$needle = htmlspecialchars($_GET["usr"]);
$ret = array_keys(array_filter($arr, function($var) use ($needle){
return strpos($var, $needle) !== false;
}));
but all this gives me is a blank page or 1s
how can i have it echo out the items with p1 in them ?
Try This:
$needle = htmlspecialchars($_GET["usr"]);
$rtnArray = array();
foreach ($arr as $value) {
$rtnArray = strpos($value,$needle);
};
return $rtnArray;
If your trying to write directly to the page the lose the $rtnarray and echo:
$needle = htmlspecialchars($_GET["usr"]);
foreach ($arr as $value) {
echo strpos($value,$needle);
};
To only show ones with 'p1' then filter:
$needle = htmlspecialchars($_GET["usr"]);
foreach ($arr as $value) {
$temp = strpos($value,$needle);
if($temp > 1){
echo $value;
}
};
Using a direct loop with string-comparison would be a simple way to go here:
$needle = $_GET['usr'];
$matches = array();
foreach ($arr as $key => $value) {
if (strpos($value, $needle) !== false) {
$matches[] = $key;
}
}
The use of array_filter() in your post should work, pending the version of PHP you're using. Try updating to use a separate / defined function:
function find_needle($var) {
global $needle;
return strpos($var, $needle) !== false;
}
$ret = array_keys(array_filter($arr, 'find_needle'));
Codepad Example of the second sample
I'm trying to validate a string to an array of numbers. If the string only contains numbers then the function should validate, but in_array isn't working, any suggestions?
$list = array(0,1,2,3,4,5,6,7,8,9);
$word = 'word';
$split = str_split($word);
foreach ($split as $s) {
if (!in_array($s, $list)) {
print 'asdf';
}
}
here is the class:
class Validate_Rule_Whitelist {
public function validate($data, $whitelist) {
if (!Validate_Rule_Type_Character::getInstance()->validate($data)) {
return false;
}
$invalids = array();
$data_array = str_split($data);
foreach ($data_array as $k => $char) {
if (!in_array($char, $whitelist)) {
$invalids[] = 'Invalid character at position '.$k.'.';
}
}
if (!empty($invalids)) {
$message = implode(' ', $invalids);
return $message;
}
return true;
}
}
in_array comparison with loosely typed values is somewhat strange. What would work in your case is:
$list = array('0','1','2','3','4','5','6','7','8','9');
$word = 'word';
$split = str_split($word);
foreach ($split as $s) {
if (!in_array($s, $list, true)) {
print 'asdf';
}
}
This compares strings with strings and results in no surprises.
But, as noted in the comments already, this is quite wrong way to do things and it is much better to use filter_var() or regular expressions** to achieve what you're trying.
it's ugly as sin but it works, no elegant solution here, just a double loop, if you see any problems please let me know
$match = array();
foreach ($data_array as $k => $char) {
foreach ($whitelist as $w) {
if (!isset($match[$k])) {
if ($char === $w) {
$match[$k] = true;
}
}
}
if (!isset($match[$k]) || $match[$k] !== true) {
$invalids[$k] = 'Invalid character at position '.$k.'.';
}
}
Something along the lines of this should work:
<?php
$validate_me = '123xyz';
if(preg_match("/[^0-9]/", $validate_me, $matches))
print "non-digit detected";
?>
update: add the $type = gettype ... settype($char, $type) to allow === to function correctly when checking for integers
foreach ($data_array as $k => $char) {
foreach ($whitelist as $w) {
if (!isset($match[$k])) {
$type = gettype($w);
if (gettype($char) !== $type) {
settype($char, $type);
}
if ($char === $w) {
$match[$k] = true;
}
}
}
...