I am allowing the user to create XML elements with blank attribute values such as this:
<crimes id="" total="" />
at the same time I am also retrieving an associative array from a database to be used to fill up the attributes that the XML specifies. The array will look like this:
array(
theft => 123,
burglary => 456
)
After retrieving the array, I want to use that array to populate the attribute values of the XML which have been passed in. So as an example, the first array element combined with the example XML would look like this:
<crimes id="theft" total="123" />
Is there a way to use regular expression in PHP to insert the array values between the quotation marks of the XML attributes?
The only time this will work, is if the XML tags you receive are consistent. They need to be the same every time, otherwise there is no pattern, and regex is used for matching patterns.
If your tags will always have id and total, then I can write a regex for it. But if they sometimes have one or the other, it gets too complicated and you need a parser.
Although (as you've been already told) you should better use SimpleXML or DOM for this, here is a custom RegEx solution you asked for:
$list = array(
"theft" => 123,
"burglary" => 456
);
$template = '<crimes id="" total="" />';
foreach($list as $key => $value)
{
$s = preg_replace('/(id=")(")/', '${1}'.$key.'${2}', $template);
$s = preg_replace('/(total=")(")/', '${1}'.$value.'${2}', $s);
echo htmlentities($s)."<br>";
}
Here is its output:
<crimes id="theft" total="123" />
<crimes id="burglary" total="456" />
If "id" or "total" is missing - it just omits it.
Related
I have multiple 'PINs' as I'll call them, stored in a input field in a comma separated format. So these are stored as a string in the format '1234,5678'.
I can already get xPath to filter an XML file for a single value by using this:
xpath("/ReaderDetails/Reader[Pin=1234]")
I'm trying to find a simple way to take the comma separated string, and interpret into the xpath expression so I can use multiple values.
The intended outcome will be:
xpath("/ReaderDetails/Reader[Pin='1234' or Pin='5678']")
It's important, that this should be able to handle as many PINs as are entered in the input field.
So far I'm able to put the PINs into an array using array_map('trim', explode(',', get_option('dream_team_readers'))) but can't figure out how to create the expression as needed above.
You ought, perhaps, to be able to accomplish the desired string pattern like this#
# to emulate the array of PINS...
$pins=[ 1234,3245,5423,4353,64576,5675,2347,3453 ];
$tmp=[];
foreach( $pins as $pin )$tmp[]=sprintf( 'Pin="%d"', $pin );
$expr=sprintf( '/ReaderDetails/Reader[ %s ]', implode( ' or ', $tmp ) );
If you were to print the resultant $expr variable you would get:
/ReaderDetails/Reader[ Pin="1234" or Pin="3245" or Pin="5423" or Pin="4353" or Pin="64576" or Pin="5675" or Pin="2347" or Pin="3453" ]
I have a stock report file (coming from an outer source, therefore I can't modify in any way) and I would like to iterate over all elements (I have to save them into a MySQL table). As I see the $xml->Stockfile is an array of objects (2 items), so I tried to put it into an array.
For some reason the $myarray contains only the first element after the $myarray = $xml->StockFile assignment.
here is my code:
$xml = simplexml_load_file("../docs/stock.xml");
print_r($xml);
$myarray = $xml->StockFile;
print_r($myarray);
stock.xml:
<NewDataSet>
<StockFile>
<MatrixID>1533</MatrixID>
<Brand>myBrand</Brand>
<ProductCode>001</ProductCode>
<RRP>29.99</RRP>
<Image2Name />
<Image3Name />
</StockFile>
<StockFile>
<MatrixID>1534</MatrixID>
<Brand>myBrand</Brand>
<ProductCode>002</ProductCode>
<RRP>29.99</RRP>
<Image2Name />
<Image3Name />
</StockFile>
</NewDataSet>
Why I'm getting only one item instead of all?
What should I do do retrieve the whole array?
Take care with SimpleXMLElement. It has a lot of magic. Know the magic or get puzzled by print_r or var_dump or similar output. Your example extended:
$myarray = $xml->StockFile;
print_r($myarray); # shows one element
# foreach has both elements:
foreach($myarray as $name => $stockfile)
{
echo $name, ":\n", $stockfile->asXML(), "\n\n";
}
Even though it is the same variable ($myarray) it behaves differently depending on context it is used in. Inside a foreach the SimpleXMLElement (that is the type of that object) will provide an iterator over the child-elements named StockFile as specified here:
$myarray = $xml->StockFile;
However using that variable in some kind of single context, it will for example return the inner string of the first child-element with that name:
echo $myarray, "\n";
(which in your case is just some lines of whitespace).
See Demo: https://eval.in/83787
Running into this "trap" by SimpleXML is actually pretty common. I suggest to understand the basic usage by the example given in the manual:
Basic SimpleXML usage
change the last two lines to
foreach ($xml->StockFile as $nextStockFile) {
print_r ($nextStockFile);
}
I want to fetch text in array between all <span> </span> tag from HTML, I have tried with this code but it returns only one occurrence :
preg_match('/<span>(.+?)<\/span>/is', $row['tbl_highlighted_icon_content'], $matches);
echo $matches[1];
My HTML:
<span>The wish to</span> be unfairly treated is a compromise attempt that would COMBINE attack <span>and innocen</span>ce. Who can combine the wholly incompatible, and make a unity of what can NEVER j<span>oin? Walk </span>you the gentle way,
My code returns only one occurrence of span tag, but I want get all text from every span tag in HTML in the form of a php array.
you need to switch to preg_match_all function
Code
$row['tbl_highlighted_icon_content'] = '<span>The wish to</span> be unfairly treated is a compromise attempt that would COMBINE attack <span>and innocen</span>ce. Who can combine the wholly incompatible, and make a unity of what can NEVER j<span>oin? Walk </span>you the gentle way,';
preg_match_all('/<span>.*?<\/span>/is', $row['tbl_highlighted_icon_content'], $matches);
var_dump($matches);
as you can see now array is correctly populated so you can echo all your matches
use preg_match_all() it's the same, it will return all the occurrences in the $matches array
http://php.net/manual/en/function.preg-match-all.php
here is code to get all span value in array
$str = "<span>The wish to</span> be unfairly treated is a compromise
attempt that would COMBINE attack <span>and innocen</span>ce.
Who can combine the wholly incompatible, and make a unity
of what can NEVER j<span>oin? Walk </span>you the gentle way,";
preg_match_all("/<span>(.+?)<\/span>/is", $str, $matches);
echo "<pre>";
print_r($matches);
you output will be
Array
(
[0] => Array
(
[0] => The wish to
[1] => and innocen
[2] => oin? Walk
)
[1] => Array
(
[0] => The wish to
[1] => and innocen
[2] => oin? Walk
)
)
you can use o or 1 index
If you don't mind using a third-party component, I'd like to show you Symfony's DomCrawler component. It 's a very simple way to parse HTML/XHTML/XML files and navigate through the nodes.
You can even use CSS Selectors. Your code would be something like:
$crawler = new Crawler($html);
$spans = $crawler->filter("span");
echo $spans[1]->getText();;
You don't even need to have a full HTML/XML document, if you assign only the <span>...</span> part of your code, it'll work fine.
I am looking for this functionality:
Given is this html-Page:
<body>
<h1>Hello,
<b>world!</b>
</h1>
</body>
I want to get an array that only contains the DISTINCT text elements
(no duplicates) and an array of the tags that surround the text elements:
The result to the above "html" would be an array that looks like this:
array =>
"Hello," surrounded by => "h1" and "body"
"world!" surrounded by => "b", "h1" and "body"
I alreday do this:
$res=$xpath->query("//body//*/text()");
which gives me the distinct text-contents but that omits the html-tags.
When I just do this:
$res=$xpath->query("//body//*");
I get duplicate texts, one for each tag-constellation: e.g.: "world!" would show up 3 times,
one time for "body", one time for "h1" and one time for "b" but I don't seem to be able to
get the information which texts are acutally duplicates. Just checking for duplicate text is
not sufficient, as duplicate texts are sometimes just substrings of former texts or a website
could contain real duplicate text which would then be discarded which is wrong.
How could I solve this issue?
Thank you very much!!
Thomas
You can iterate over the parentNodes of the DOMText nodes:
$dom = new DOMDocument;
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$textNodes = array();
foreach($xpath->query('/html/body//text()') as $i => $textNode) {
$textNodes[$i] = array(
'text' => $textNode->nodeValue,
'parents' => array()
);
for (
$currentNode = $textNode->parentNode;
$currentNode->parentNode;
$currentNode = $currentNode->parentNode
) {
$textNodes[$i]['parents'][] = $currentNode->nodeName;
}
}
print_r($textNodes);
demo
Note that loadHTML will add implied elements, e.g. it will add html and head elements which you will have to take into account when using XPath. Also note that any whitespace used for formatting is considered a DOMText so you will likely get more elements than you expect. If you only want to query for non-empty DOMText nodes use
/html/body//text()[normalize-space(.) != ""]
demo
In your sample code, $res=$xpath->query("//body//*/text()") is a DOMNodeList of DOMText nodes. For each DOMText, you can access the containing element via the parentNode property.
I have an xml how can I get the node in levelone that has an attribute called myatt whose value is a and then access it's myval.
I tried referencing other posts to make it work but it doesn't seem to work what's wrong with my xpath
$this->myXmlObj->xpath("//levelone[myfield[attributes/myatt='a]]]"));
<myxml>
<levelone>
<myfield myatt="a" myval="aa" />
<myfield myatt="b" myval="bb" />
</levelone>
<leveltwo>
<myfield myatt="c" myval="dd" />
<myfield myatt="c" myval="dd" />
</leveltwo>
</myxml>
edit 1
array
0 =>
object(SimpleXMLElement)[41]
public '#attributes' =>
array
'myval' => string 'a' (length=40)
edit 2
$myVar = $this->myXmlObj->xpath("//levelone/myfield[#myatt='a']");
$myOutput = ((string)$myVar[0]->attributes()->myVal;
Attributes in XPATH are referenced with #attr syntax. So, you could retrieve aa with the following xpath
//levelone/myfield[#myatt='a']/#myval
Which means, grab all myfield elements that have attribute myatt equal to 'a'. Then, from those, select the value of their myval attributes. Note that this could be multiple results.
A handy place to test XPATH expressions is at http://chris.photobooks.com/xml/default.htm.