Searching XML using XPath for multiple attributes in php - php

I found same topics but I didn't solve my problem :(
I want to search in XML with product code
this is my code;
$xml = simplexml_load_file('http://xml.aksel.com.tr/Xml.aspx?SK=d021da08&CK=50288');
$product_code = $_GET['s'];
$products = $xml->xpath("//STOK_KODU[contains(text(), '".$product_code."')]/STOK_ADI/GRUPKODU");
if I remove "/STOKADI/GRUPKODU", its working. But Product title, product image, product category didn't show. Where is the problem?
And my second problem, when I want to show all products; I see some products at least 4-5 times.
(Note: I work in WordPress)

I don't use simple_xml but the approach below, using DOMDocument and DOMXPath should be easy enough to port to simple_xml if desired. Initially I thought you were looking for child nodes of STOK_KODU but the structure of the XML suggests otherwise. The XPath query will find the node with the relevant $product_code from which you can easily find the parent and thus any/all of it's children.
$file='http://xml.aksel.com.tr/Xml.aspx?SK=d021da08&CK=50288';
#$file='c:/temp/Xml.xml'; /* saved locally to test */
$output=array();
$product_code=13775;
$query='//XMLWEBDATA/STOK_KODU[ contains( text(), "'.$product_code.'" ) ]';
$dom=new DOMDocument;
$dom->load( $file );
$xp=new DOMXPath( $dom );
$col=$xp->query( $query );
if( $col && $col->length > 0 ){
foreach( $col as $node ){
/* get the parent */
$parent=$node->parentNode;
$data=array();
for( $i=0; $i < $parent->childNodes->length; $i++ ){
$tag=$parent->childNodes->item( $i )->tagName;
$value=$parent->childNodes->item( $i )->nodeValue;
if( !empty( $tag ) && !empty( $value ) ) $data[ $tag ]=$value;
}
$output[]=$data;
}
/* remove duplicates if there are any */
$output=array_unique( $output );
}
$xp = $dom = null;
/* process the results accordingly */
if( !empty( $output ) ){
foreach( $output as $obj ){
printf('<pre>%s</pre>', urldecode( http_build_query( $obj, null, PHP_EOL ) ) );
}
}
The output of which will be
STOK_KODU=13775
STOK_ADI=CHIP EPSON C3800 Black (S051127)
LISTEFIYAT=2,73
STOKBAKIYE1=16
GRUPKODU=DOLUM ÜRÜNLERİ GRUBU
KOD1=TONER DOLUM ÜRÜNLERİ
KOD2=ÇİPLER
PARABIRIMI=$
KULL5N=9500
RESIMURL=http://xml.aksel.com.tr/Photo.aspx?ID=22705&STOK=13775
To access each field as a variable ( which is what I understand your comment to be )
foreach( $col as $node ){
/* get the parent */
$parent=$node->parentNode;
$data=array();
for( $i=0; $i < $parent->childNodes->length; $i++ ){
try{
/* test node type to avoid errors */
if( $parent->childNodes->item( $i )->nodeType==XML_ELEMENT_NODE ){
$tag=$parent->childNodes->item( $i )->tagName;
$value=$parent->childNodes->item( $i )->nodeValue;
if( !empty( $tag ) && !empty( $value ) ) $data[ $tag ]=$value;
}
}catch( Exception $e ){
echo $e->getMessage();
continue;
}
}
$output[]=$data;
}
and to access as variables, use extract
if( !empty( $output ) ){
foreach( $output as $obj ){
extract( $obj );
printf("<pre>%s\n%s\n%s</pre>", $STOK_KODU, $STOK_ADI, $GRUPKODU );
}
}

If you look at the structure of the XML, the GRUPKODU and STOKADI are elements at the same level. So trying to access these in you XPath at the same time isn't going to work. If instead you look for the XMLWEBDATA element your after, you can then access these elements inside this element. This XPath looks for an XMLWEBDATA with a STOK_KODU with content that contains the product code your after, then using foreach to print out each match, it outputs the two values your after...
$products = $xml->xpath("//XMLWEBDATA[STOK_KODU[contains(text(), '".$product_code."')]]");
foreach ( $products as $product ) {
echo (string)$product->STOK_ADI.PHP_EOL;
echo (string)$product->GRUPKODU.PHP_EOL;
}
(I only cast the return values to strings as this is needed if assigning to other values, echo will automatically cast it anyway and it can cause confusing results when used in assignments)
If I set
$product_code = 14037;
This outputs
EPSON T2711XL (27XL) > WF3620,3640,7110,7610,7620 Black
TÜKETİM ÜRÜNLERİ GRUBU
Note: You may want to use....
$products = $xml->xpath("//XMLWEBDATA[STOK_KODU='".$product_code."']");
to ensure that you only find a code that fully matches in case there are cases where it will match parts of other codes.

Related

How to access array list in Json by php?

I am currently working with Accessing json using php in wordpress. I have successfully decoded the json but when i try to access the values it doesn't fetch . I am trying to access the Cluster_ID and Image
values.
Here's my api link http://ec2-13-127-149-66.ap-south-1.compute.amazonaws.com:5000/api/news
I have tried the following code:
<?php
/**
*Plugin Name: plugin two
**/
function myjson8(){
$request = wp_remote_get( 'http://ec2-13-127-149-66.ap-south-1.compute.amazonaws.com:5000/api/news' );
if( is_wp_error( $request ) ) {
return false; // Bail early
}
$body = wp_remote_retrieve_body( $request );
$data = json_decode( $body );
if( ! empty( $data) ) {
foreach( $data as $product ) {
echo $product->Cluster_ID;
foreach($data->data as $news){
echo $news->Image;
}
}
}
}
Taking the data from the news feed that you supplied then placing it in a JSON viewer you get:
On opening level 0 we get
This is not what you want so we need to look at level 1 and its structure
So your code would be:
for($x=0; $x<count($data[1]); $x++ ) {
$clusterId = $data[1][$x]['Cluster_ID'];
for( $p=0; $p<count( $data[1][$x]['data'] ); $p++ ) {
$pic = $data[1][$x]['data'][$p];
}
}

How to display multiple consecutive html elements

I'm using ACF on my wordpress site to display HTML text in the search bar next to post titles based on that posts array values.
Right now the script only displays up to 1 of the html values, but I want it to include all of the values if they exist.
add_filter( 'asp_results', 'asp_custom_field_to_results', 10, 1 );
function asp_custom_field_to_results( $results ) {
$custom_field = 'trade_status';
foreach ($results as $k=>&$r) {
if ($r->content_type != 'pagepost') continue;
if ( function_exists('get_field') )
$trade_status = get_field( $custom_field, $r->id, true ); // ACF support
else
$trade_status = get_post_meta( $r->id, $custom_field, true );
// Modify the post title to add the meta value
if ( !empty($trade_status) ) {
if ( in_array('30', $trade_status) ) {
$html = '<span class="new">New</span>';
} else if ( in_array('20', $trade_status) ) {
$html = '<span class="active">Active</span>';
} else if ( in_array('10', $trade_status) ) {
$html = '<span class="closed">Closed</span>';
} else {
$html = '';
}
$r->title = $html . $r->title;
}
}
return $results;
}
So, it looks like right now you're overwriting the value of $html for each matching iteration in the loop. My guess is that you'd want to concatenate (.=) rather than overwrite (=) when you're doing this.

Trouble returning usable string or array with foreach loop

I am trying to return an string that I can use in a function (programatically adding terms in WordPress).
My function that generates my string is basically looping through html meta tags that match a certain criteria and is as follows:
function getYouTubeTags( $post_id ) {
$video_id = get_post_meta( get_the_ID(), 'rfvi_video_id', true );
$tag_url = "http://www.youtube.com/watch?v=" . $video_id;
$sites_html = file_get_contents($tag_url);
$html = new DOMDocument();
#$html->loadHTML($sites_html);
$meta_og_tag = null;
foreach( $html->getElementsByTagName('meta') as $meta ) {
if( $meta->getAttribute('property')==='og:video:tag' ){
$meta_og_tag = $meta->getAttribute('content');
print_r ($meta_og_tag . ",");
}
}
}
When I simply execute this (getYouTubeTags();), it returns the string:
supra vs lambo,tt lambo,twin turbo,street race,texas streets,underground racing,supra,turbo supra,1200hp,nitrous,superleggera,gallardo,
In my function to add terms to a post, the following DOES NOT work:
function rct_save_post_terms( $post_id ) {
$terms = getYouTubeTags();
wp_set_post_terms( $post_id, $terms, 'post_tag', true );
}
If I manually add the string as outputted from the first function, it DOES work:
function rct_save_post_terms( $post_id ) {
$terms = 'supra vs lambo,tt lambo,twin turbo,street race,texas streets,underground racing,supra,turbo supra,1200hp,nitrous,superleggera,gallardo,';
wp_set_post_terms( $post_id, $terms, 'post_tag', true );
}
Also, according to WordPress, $terms in wp_set_post_terms: Can be an array or a comma separated string.
I know I must be missing something simple here but cannot seem to figure it out. Thank in advance for some help!
Since you want to get those string to be reused, why not return those:
function getYouTubeTags( $post_id ) {
$out = null;
$video_id = get_post_meta( get_the_ID(), 'rfvi_video_id', true );
$tag_url = "http://www.youtube.com/watch?v=" . $video_id;
$sites_html = file_get_contents($tag_url);
$html = new DOMDocument();
#$html->loadHTML($sites_html);
$meta_og_tag = null;
foreach( $html->getElementsByTagName('meta') as $meta ) {
if( $meta->getAttribute('property')==='og:video:tag' ){
// i seriously doubt this checking i think this should be
// if($meta->getAttribute('property') == 'og:video') {
$meta_og_tag = $meta->getAttribute('content');
// print_r ($meta_og_tag . ",");
$out[] = $meta_og_tag; // gather them inside first
}
}
return implode(',', $out); // return implode comma delimited strings
}
And then utimately, then you could use them:
function rct_save_post_terms( $post_id ) {
$terms = getYouTubeTags(); // strings are in here
wp_set_post_terms( $post_id, $terms, 'post_tag', true );
}
You don't seem to be returning a value in your original function. You need to use;
return $meta_og_tag;
at the end of your function to return a value back to an assigned variable.
Also, you need to append strings to the end of your returned variable using .=;
$meta_og_tag .= $meta->getAttribute('content');
OR you can save each attribute in an array and implode for the return;
// inside loop
$meta_og_tag[] = $meta->getAttribute('content');
// outside loop
return implode(', ',$meta_og_tag);
print_r will simply echo the contents of the variable, not return a value.
Hope this helps.

Match multiple attribute terms in Wordpress PHP loop

This seems like a simple enough problem but I'm a novice at PHP and I've been working on this for hours. I'm looping through posts in an archive and showing a different logo for each post based on a certain attribute. Here's my existing function in functions.php:
function show_logo() {
global $post;
$attribute_names = array( 'pa_product-type'
);
foreach ( $attribute_names as $attribute_name ) {
$taxonomy = get_taxonomy( $attribute_name );
if ( $taxonomy && ! is_wp_error( $taxonomy ) ) {
$terms = wp_get_post_terms( $post->ID, $attribute_name );
$terms_array = array();
if ( ! empty( $terms ) ) {
foreach ( $terms as $term ) {
if ( $term->name == 'L1' ) {
// Show L1 Logo
}
elseif ( $term->name == 'M1' ) {
// Show M1 Logo
}
elseif ( $term->name == 'H1' ) {
// Show H1 Logo
}
else {
$full_line = '<span>'. $term->name . '</span>';
}
array_push( $terms_array, $full_line );
}
echo implode( $terms_array );
}
}
}
}
All I want to do is do show a different logo if the post matches multiple terms (e.g. 'L1' AND 'M1'). I have tried many very different things but I have no idea if I'm even on the right track. Any help would be greatly appreciated.
This should be fairly easy, I'm just not exactly sure the full context of all the data involved.
Assuming you are only showing one logo per post, here is one approach:
Right before foreach ( $terms as $term ) { create three boolean variables:
$hasL1 = false;
$hasM1 = false;
$hasH1 = false;
Then when one of your term names matches, instead of just showing the logo set the appropriate variable equal to true, ie $hasL1 = true;
After the foreach is complete, either before or after echo implode( $terms_array ); depending on what makes sense, setup a new if/elseif/else block to decide what logo to show as follows:
if ($hasL1 && $hasM1 && $hasH1) { // Pick logo for all 3 }
elseif ($hasL1 && $hasM1) { // Pick logo for pair }
elseif ($hasL1 && $hasH1) { // Pick logo for pair }
elseif ($hasH1 && $hasM1) { // Pick logo for pair }
elseif ($hasL1) { // Pick logo }
elseif ($hasM1) { // Pick logo }
elseif ($hasH1) { // Pick logo }
else { // default logo }
Of course there are many other ways to implement this too.

Array Splice does not preserve "trail_end"

I am a newbie and have a piece of Wordpress code which has a glitch in it.
Sorry if my question is silly, though the support from where I bought the theme seems to answer with a great delay.
I will paste it and maybe someone can help. If no one can figure out the problem I will delete the question.
The code adds a few changes to the breadcrumb navigation on my site.
The problem I think is with this:
// Add the trail back on to the end.
$links[] = $trail['trail_end'];
// Add the new links, and the original trail's end, back into the trail.
array_splice( $trail, 1, count( $trail ) - 1, $links );
These two line of code should add a <span class="trail-end"></span> to the end of the breadcrumbs around the words "Xpand Xtreme Pump" (in my link example)
Here is the code:
function woo_custom_breadcrumbs_trail_add_product_categories ( $trail ) {
if ( ( get_post_type() == 'product' ) && is_singular() ) {
global $post;
$taxonomy = 'product_cat';
$terms = get_the_terms( $post->ID, $taxonomy );
$links = array();
if ( $terms && ! is_wp_error( $terms ) ) {
foreach ( $terms as $c ) {
$parents = woo_get_term_parents( $c->term_id, $taxonomy, true, ', ', $c->name, array() );
if ( $parents != '' && ! is_wp_error( $parents ) ) {
$parents_arr = explode( ', ', $parents );
foreach ( $parents_arr as $p ) {
if ( $p != '' ) { $links[] = $p; }
}
}
}
// Add the trail back on to the end.
$links[] = $trail['trail_end'];
// Add the new links, and the original trail's end, back into the trail.
array_splice( $trail, 1, count( $trail ) - 1, $links );
}
}
return $trail;
} // End woo_custom_breadcrumbs_trail_add_product_categories()
Try this:
...
// Wrap the trail_end with your span tag
$trail['trail_end'] = '<span class="trail-end">' . end($trail) . '</span>';
// Add the trail back on to the end.
$links[] = $trail['trail_end'];
...
Remember, that this is a hack, I'd recommend doing this in the template rendering the bread-crumbs.

Categories