Location: PHPKode > projects > Taxonomic Search Engine > ipni_wrapper.php
<?php
// $Id: ipni_wrapper.php,v 1.1.1.1 2005/05/19 10:31:10 rdmpage Exp $

/**
 * @brief Wrapper to talk to the International Plant Names Database (IPNI)
 * using its URL API. This API is described at <A HREF="http://www.ipni.org/link_to_ipni.html">
 * http://www.ipni.org/link_to_ipni.html</A>.
 *
 */
class IPNIWrapper extends Wrapper {

	var $rank_map;

	/**
	 *
	 *
	 * As well as setting the base URL for the IPNI site, the constructor
	 * sets up a mapping between rank names returned by IPNI, and their proper
	 * names. For example, "gen." is "Genus".
	 */
	function IPNIWrapper ()
	{
	
//		$this->server = "www.ipni.org";
$this->server = "www.uk.ipni.org"; // UK Mirror
		$this->authority = "ipni.org";
		$this->namespace = "Id";
		
		$this->rank_map['gen.'] = 'Genus';
		$this->rank_map['spec.'] = 'Species';
		
		$this->StartXML();
	}
	
	/**
	 * @brief Try to connect to IPNI server
	 *
	 * Simply tries to open an HTTP connection to www.ipni.org.
	 
	 * @return true if service is live, false otherwise
	 */
	function IsAlive ()
	{
		$query = "http://";
		$query .= $this->server;
		$result = true;
		$http = new Net_HTTP_Client();
		if ($config['proxy_name'] != '')
		{
			$http->setProxy ($config['proxy_name'], $config['proxy_port']);
		}
		$http->Connect($query, 80 ) or $result = false;
		$http->Disconnect();
		return $result;				
	}
	
	//----------------------------------------------------------------------------
	/**
	 * @brief Return details for a single record in IPNI
	 *
	 * @param id 
	 * @return Result in my XML format
	 */
	function GetDataForID ($id)
	{
		$result = "";
		
		global $config;
		
		$text = "";
		
		$text = $this->GetDataFromCache ("GetDataForID", "txt", $id);
		if ($text == "")
		{

		
			$query = "http://";
			$query .= $this->server;
			$query .= "/ipni/plantsearch?";
			
			$parameters = array();
			
			$parameters['id'] =	 $id; 
			$parameters['query_type'] 			= 'by_id';
			$parameters['back_page'] 			= 'query_ipni';
			$parameters['output_format'] 		= 'delimited';
			
			// Build URL
			foreach ($parameters as $key => $value)
			{
				if (strcmp ($key, "id")) {$query .= "&";}
				$query .= $key;
				$query .= "=";
				$query .= $value;
			}
	
			echo $query, "<br/>";
			
			$http = new Net_HTTP_Client();
			if ($config['proxy_name'] != '')
			{
				$http->setProxy ($config['proxy_name'], $config['proxy_port']);
			}
			if (!$http->Connect($query, 80 ))
			{
				$this->Error ("server", "Can't connect");
				$this->EndXML();
				return $this->xml;
			}
			
			$this->StartTimer();
			$status = $http->Get( $query );	
			$this->StopTimer();
			$this->ReportTimeUsed();
			
			if( $status != 200 )
			{
				$this->Error ("GET", $http->getStatusMessage());
				$this->EndXML();
				return $this->xml;
			}
			$text = $http->getBody();
			$http->Disconnect();
			$this->StoreDataInCache ("GetDataForID", "txt", $id, $text);
			
		}
		
		//echo $text;
		
		$this->xml = "<?xml version='1.0' encoding='utf-8'?>\n";
		$this->xml .= "<Result>\n";
		$this->xml .= $this->DelimitedToGetIDXML ($text);
		$this->xml .= "</Result>\n";
		
		return $this->xml;
		
	}
	



	//----------------------------------------------------------------------------
	/**
	 * @brief Search IPNI for a name.
	 *	
	 * @param name The taxon name to search for
	 * @param qualifier Kind of search (default is exact)
	 * @param max_results The maximum number of records to return (default is 1)
	 */
	function NameSearch ($name, $qualifier = EXACT, $max_results = 1) 
	{		
		global $config;
		
		$id = nameToSafe ($name);
		
		$text = "";
		
		$this->StartTimer();
		$text = $this->GetDataFromCache ("NameSearch", "txt", $id);
		if ($text == "")
		{
			$query = "http://";
			$query .= $this->server;
			$query .= "/ipni/plantsearch?";
			
			$parameters = array();
			if ($qualifier == EXACT)
			{
				$parameters['find_wholeName'] =	 str_replace (" " ,"+" ,$name ); 
			}
			else
			{
				// We need to figure out the component parts of the name (to do)
			}
					
			// Additional search parameters
			$parameters['find_searchAll']		= '';
	
			
	/*		$parameters['find_family']						= '';
			$parameters['find_infrafamily']					= '';
			$parameters['find_genus']						= '';
			$parameters['find_infragenus']					= '';
			$parameters['find_species']						= '';
			$parameters['find_infraspecies']				= '';
			$parameters['find_authorAbbrev']				= '';
			$parameters['find_publicationTitle']			= '';
			$parameters['find_rankToReturn']				= 'all';
			$parameters['find_includePublicationAuthors']	= 'on';
			$parameters['find_includeBasionymAuthors']		= 'on';
			$parameters['find_sortByFamily']				= 'on';		
	*/		
			
			
			$parameters['find_isAPNIRecord'] 	= 'on';
			$parameters['find_isGCIRecord'] 	= 'on';
			$parameters['find_isIKRecord'] 		= 'on';
			$parameters['output_format'] 		= 'delimited';
			$parameters['query_type'] 			= 'by_query';
			$parameters['back_page'] 			= 'query_ipni';
			
			// Build URL
			foreach ($parameters as $key => $value)
			{
				if (strcmp ($key, "find_wholeName")) {$query .= "&";}
				$query .= $key;
				$query .= "=";
				$query .= $value;
			}
	
			//echo $query, "<br/>";
			
			$http = new Net_HTTP_Client();
			if ($config['proxy_name'] != '')
			{
				$http->setProxy ($config['proxy_name'], $config['proxy_port']);
			}
			if (!$http->Connect($query, 80 ))
			{
				$this->Error ("server", "Can't connect");
				$this->EndXML();
				return $this->xml;
			}
			
			$this->StartTimer();
			$status = $http->Get( $query );	
			
			if( $status != 200 )
			{
				$this->Error ("GET", $http->getStatusMessage());
				$this->EndXML();
				return $this->xml;
			}
			$text = $http->getBody();
			$http->Disconnect();
			$this->StoreDataInCache ("NameSearch", "txt", $id, $text);
			
			
			//echo $text;
		}
		$this->StopTimer();
		$this->ReportTimeUsed();
		
		$this->xml .= $this->DelimitedToNameSearchXML ($text);
		$this->EndXML();
		return $this->xml;
		


	}
	
	/**
	 * @brief Convert IPNI % delimited text into our XML format
	 *
	 * IPNI returns results in a % delimited format that includes a
	 * header row. We need to extract what we need from this text.
	 * <pre>
	 * Id%Version%Family%Infra family%Hybrid Genus%Genus%...
	 * 11679-1%1.1%Coniferae%%N%Phyllocladus%...
	 * 127747-3%1.1%Phyllocladaceae%%N%Phyllocladus%...
	 * 32178-1%1.1.2.1%Podocarpaceae%%N%Phyllocladus%...
	 * </pre>
	 *
	 * We parse the firslt line to obtain an array of column names, which are
	 * then used to identify the columns of interest.
	 * Note that despite what it says, the column headed "Full name without family"
	 * will contain the family name for a genus. We also need to convert the column
	 * "Rank" into a properly named category (e.g., "gen." should be "Genus").
	 *
	 */
	function DelimitedToGetIDXML ($text)
	{
		$xml = "";
		
		$text = trim($text);
		
		// Get array of individual lines
		$lines = explode ("\n", $text);
		
		// Extract headings from first line
		$parts = explode ("%", $lines[0]);
		$size=count($parts);
		$heading = array();
		for ($i=0; $i < $size; $i++)
		{
			$heading[$parts[$i]] = $i;
		}
		

		// Read each remaining line				
		$size=count($lines);
		for ($i=1; $i < $size; $i++)
		{
			$parts = explode ("%", $lines[$i]);
			
			$id = $parts[$heading["Id"]];
			$name = $parts[$heading["Full name without family and authors"]];
			$author = $parts[$heading["Authors"]];
			// Handle ampersands ('&') linking author names, e.g. "G.Chandler & Crisp"
			$author = htmlspecialchars ($author, ENT_NOQUOTES, UTF-8);
			
			$rank = $this->rank_map[$parts[$heading["Rank"]]];
			
			// Fix for genera being listed with their family name
			if ($rank == 'Genus')
			{
				$p = explode (" ", $name);
				$s=count($p);
				if ($s = 2)
				{
					$name = $p[1];
				}
			}
		
			
			//echo $id, "|", $name, "|", $author, "|", $parts[$heading["Rank"]], "|", $rank, "<br/>";
			
			
			$xml .= "<taxon authority=\"$this->authority\" namespace=\"$this->namespace\" id=\"$id\">\n";
			$xml .= "   <name>$name</name>\n";
			$xml .= "   <author>$author</author>\n";
			$xml .= "   <rank>$rank</rank>\n";
			$xml .= "   <status>unknown</status>\n";
			$xml .= "   <url>http://www.ipni.org/ipni/plantsearch?id=$id&amp;query_type=by_id&amp;back_page=query_ipni.html&amp;output_format=object_view</url>\n";
			$xml .= "</taxon>\n";
		}
			
		//echo $xml;	
		
		return $xml;
		
		
	}

	
	/**
	 * @brief Convert IPNI % delimited text into our XML format
	 *
	 * IPNI returns results in a % delimited format that includes a
	 * header row. We need to extract what we need from this text.
	 * <pre>
	 * Id%Version%Family%Infra family%Hybrid Genus%Genus%...
	 * 11679-1%1.1%Coniferae%%N%Phyllocladus%...
	 * 127747-3%1.1%Phyllocladaceae%%N%Phyllocladus%...
	 * 32178-1%1.1.2.1%Podocarpaceae%%N%Phyllocladus%...
	 * </pre>
	 *
	 * We parse the firslt line to obtain an array of column names, which are
	 * then used to identify the columns of interest.
	 * Note that despite what it says, the column headed "Full name without family"
	 * will contain the family name for a genus. We also need to convert the column
	 * "Rank" into a properly named category (e.g., "gen." should be "Genus").
	 *
	 */
	function DelimitedToNameSearchXML ($text)
	{
		$xml = "";
		
		$text = trim($text);
		
		// Get array of individual lines
		$lines = explode ("\n", $text);
		
		// Extract headings from first line
		$parts = explode ("%", $lines[0]);
		$size=count($parts);
		$heading = array();
		for ($i=0; $i < $size; $i++)
		{
			$heading[$parts[$i]] = $i;
		}
		

		// Read each remaining line				
		$size=count($lines);
		for ($i=1; $i < $size; $i++)
		{
			$parts = explode ("%", $lines[$i]);
			
			$id = $parts[$heading["Id"]];
			$name = $parts[$heading["Full name without family and authors"]];
			$author = $parts[$heading["Authors"]];
			// Handle ampersands ('&') linking author names, e.g. "G.Chandler & Crisp"
			$author = htmlspecialchars ($author, ENT_NOQUOTES, UTF-8);
			
			$rank = $this->rank_map[$parts[$heading["Rank"]]];
			
			// Fix for genera being listed with their family name
			if ($rank == 'Genus')
			{
				$p = explode (" ", $name);
				$s=count($p);
				if ($s = 2)
				{
					$name = $p[1];
				}
			}
		
			
			//echo $id, "|", $name, "|", $author, "|", $parts[$heading["Rank"]], "|", $rank, "<br/>";
			
			
			$xml .= "<taxon authority=\"$this->authority\" namespace=\"$this->namespace\" id=\"$id\">\n";
			$xml .= "   <name>$name</name>\n";
			$xml .= "   <author>$author</author>\n";
			$xml .= "   <rank>$rank</rank>\n";
			$xml .= "   <kingdom>Plantae</kingdom>\n";
			$xml .= "   <rank>$rank</rank>\n";
			$xml .= "   <url>http://www.ipni.org/ipni/plantsearch?id=$id&amp;query_type=by_id&amp;back_page=query_ipni.html&amp;output_format=object_view</url>\n";			
			$xml .= "</taxon>\n";
		}
				
		
		return $xml;
		
		
	}
	

}


?>
Return current item: Taxonomic Search Engine