You are here:  » How to access selected nodes


How to access selected nodes

Submitted by garydarling on Wed, 2012-08-08 20:05 in

I have the following xml format: (truncated for brevity)

{code saved}

I want to show only some of the nodes on my web page, for example:

  • details/listing-title
  • location/street-address
  • details/description

I have this so far:

<?php
 MagicParser_parse
($filename,"myRecordHandler","xml|PROPERTIES/PROPERTY/"); 
?>

How would I iterate through all the nodes to get just those child nodes I want to display? This code grabs all the nodes:

<?php
 
function myRecordHandler($record)
  {
    foreach(
$record as $key => $value)
  }
?>

Whereas I just want three specific nodes. Thanks for any help.

Submitted by support on Fri, 2012-08-10 15:56

Hello Gary,

I hope you recieved my MySQL Insert example which I sent yesterday - let me know if you didn't receive that and I'll resend as this would indicate individual field extraction.

In this instance, $record can be indexed by any value of $k as seen in the loop.

What I normally do when working with a new format for the first time is to create a script that just prints the content of $record using the print_r() function so that you can see what key names to use, so in the case of your properties feed:

<?php
  
require("MagicParser.php");
  
header("Content-Type: text/plain");
  function 
myRecordHandler($record)
  {
    
print_r($record);
    return 
TRUE// stop parsing - just print the first record
  
}
  
$filename "properties.xml";
  
MagicParser_parse($filename,"myRecordHandler","xml|PROPERTIES/PROPERTY/");
?>

- replace the value of $filename with the filename or URL of your XML source

This will output the associative array that is $record as seen by myRecordHandler for each call (per record in your feed), containig items e.g.

[LOCATION/STREET-ADDRESS] => 123 Anydrive

...and its the part between square brackets that you can use to index $record to get only the specific fields you want, so to print the specific fields you are intersted in, you would use:

  function myRecordHandler($record)
  {
    print $record["LOCATION/STREET-ADDRESS"];
    print $record["DETAILS/LISTING-TITLE"];
    print $record["DETAILS/DESCRIPTION"];
  }

Hope this helps!
Cheers,
David
--
MagicParser.com

Submitted by garydarling on Tue, 2012-11-20 22:18

Hi David,

I've been using MagicParser with great success, thanks for your help with the custom code.

Recently I changed the xml feed I'm parsing; it works great but for one side effect. The property listings all come in with a node <status>Active</status>, but the user wishes to manually update the status in the database (example, Status = Sold). I can do this, but every night when the cron runs MagicParser that database modification gets overwritten and is set back to Active.

Is there a quick code modification you can recommend to prevent this? Presently the sql syntax is to truncate the table, would it be feasible to UPDATE the table instead, since it only adds a few properties at the most every night? Here is the present sql:

 $sql = "
    INSERT INTO `properties` SET
`unit_number` = '".database_safe($record["LOCATION/UNIT-NUMBER"])."',
`street_address` = '".database_safe($record["LOCATION/STREET-ADDRESS"])."',
`city_name` = '".database_safe($record["LOCATION/CITY-NAME"])."',
`state_code` = '".database_safe($record["LOCATION/STATE-CODE"])."',
`county` = '".database_safe($record["LOCATION/COUNTY"])."',
`zipcode` = '".database_safe($record["LOCATION/ZIPCODE"])."',
`longitude` = '".database_safe($record["LOCATION/LONGITUDE"])."',
`latitude` = '".database_safe($record["LOCATION/LATITUDE"])."',
`directions` = '".database_safe($record["LOCATION/DIRECTIONS"])."',
`listing_title` = '".database_safe($record["DETAILS/LISTING-TITLE"])."',
`price` = '".database_safe($record["DETAILS/PRICE"])."',
`year_built` = '".database_safe($record["DETAILS/YEAR-BUILT"])."',
`bedrooms` = '".database_safe($record["DETAILS/NUM-BEDROOMS"])."',
`bathrooms` = '".database_safe($record["DETAILS/NUM-BATHROOMS"])."',
`lot_size` = '".database_safe($record["DETAILS/LOT-SIZE"])."',
`square_feet` = '".database_safe($record["DETAILS/SQUARE-FEET"])."',
`property_type` = '".database_safe($record["DETAILS/PROPERTY-TYPE"])."',
`description` = '".database_safe($record["DETAILS/DESCRIPTION"])."',
`mls_id` = '".database_safe($record["DETAILS/MLSID"])."',
`lp_url` = '".database_safe($record["LANDING-PAGE/LP-URL"])."',
`status` = '".database_safe($record["STATUS"])."',
`pictures` = '".database_safe($pictures)."',
`agent_email` = '".database_safe($record["AGENT/AGENT-EMAIL"])."',
`office_id` = '".database_safe($record["OFFICE/OFFICE-ID"])."'
      "; // no comma after last ------------------------------^
    database_queryModify($sql,$result);
    $count++;
  }
  $sql = "TRUNCATE `properties`";
  database_queryModify($sql,$result);

Submitted by support on Wed, 2012-11-21 09:09

Hi Gary,

Sure - the easiest way is if there is an ID field in each record but I notice you are not currently inserting an ID but i'll assume there is, but if not see below regarding how to construct a unique ID using md5().

If you start by adding the ID field listing_id to the database table of type VARCHAR(32), the SQL section of the above code to INSERT or UPDATE (preserving `status`) would be as follows:

  $set = "
`unit_number` = '".database_safe($record["LOCATION/UNIT-NUMBER"])."',
`street_address` = '".database_safe($record["LOCATION/STREET-ADDRESS"])."',
`city_name` = '".database_safe($record["LOCATION/CITY-NAME"])."',
`state_code` = '".database_safe($record["LOCATION/STATE-CODE"])."',
`county` = '".database_safe($record["LOCATION/COUNTY"])."',
`zipcode` = '".database_safe($record["LOCATION/ZIPCODE"])."',
`longitude` = '".database_safe($record["LOCATION/LONGITUDE"])."',
`latitude` = '".database_safe($record["LOCATION/LATITUDE"])."',
`directions` = '".database_safe($record["LOCATION/DIRECTIONS"])."',
`listing_title` = '".database_safe($record["DETAILS/LISTING-TITLE"])."',
`price` = '".database_safe($record["DETAILS/PRICE"])."',
`year_built` = '".database_safe($record["DETAILS/YEAR-BUILT"])."',
`bedrooms` = '".database_safe($record["DETAILS/NUM-BEDROOMS"])."',
`bathrooms` = '".database_safe($record["DETAILS/NUM-BATHROOMS"])."',
`lot_size` = '".database_safe($record["DETAILS/LOT-SIZE"])."',
`square_feet` = '".database_safe($record["DETAILS/SQUARE-FEET"])."',
`property_type` = '".database_safe($record["DETAILS/PROPERTY-TYPE"])."',
`description` = '".database_safe($record["DETAILS/DESCRIPTION"])."',
`mls_id` = '".database_safe($record["DETAILS/MLSID"])."',
`lp_url` = '".database_safe($record["LANDING-PAGE/LP-URL"])."',
`pictures` = '".database_safe($pictures)."',
`agent_email` = '".database_safe($record["AGENT/AGENT-EMAIL"])."',
`office_id` = '".database_safe($record["OFFICE/OFFICE-ID"])."'
";
  // change key into $record to whatever listing_id field is in the XML
  // you can use print_r($record); to output the full record if you're
  // not sure...
  $listing_id = $record["LISTING-ID"];
  // see if listing_id exists in database
  $sql = "SELECT listing_id FROM `properties` WHERE listing_id = '".database_safe($listing_id)."';
  if (database_querySelect($sql,$result))
  {
    // construct UPDATE SQL
    $sql = "UPDATE `properties` SET ".$set." WHERE listing_id = '".database_safe($listing_id)."';
  }
  else
  {
    // construct INSERT SQL
    $sql = "INSERT INTO `properties` SET ".$set.",`status` = '".database_safe($record["STATUS"])."'";
  }
  database_queryModify($sql,$result);

Now, if your feed has no unique ID field that you can use as $listing_id, you can MD5 hash together sufficient fields that will always be unique to a listing, such as the address. So for example, in place of:

  $listing_id = $record["LISTING-ID"];

...you could use:

  $listing_id = md5($record["LOCATION/UNIT-NUMBER"].$record["LOCATION/STREET-ADDRESS"].$record["LOCATION/CITY-NAME"].$record["LOCATION/STATE-CODE"].$record["LOCATION/ZIPCODE"]);

Hope this helps!