Mighty Webdeveloper » php http://www.mightywebdeveloper.com Webdevelopment Blog Fri, 14 Mar 2014 11:19:39 +0000 en-US hourly 1 http://wordpress.org/?v=4.0 PHP XPath Generator /coding/php-xpath-generator/ /coding/php-xpath-generator/#comments Fri, 02 Sep 2011 09:47:10 +0000 /?p=89 Continue reading...]]> In this post I’ll explain a clever way to automatically generate a list of XPath expressions that can be used to select any element and attribute in an XML document. We’ll use PHP’s SimpleXML extension to easily parse and traverse the XML document and to build a simple XPath generator.

I’ll start with a simple example XML document and the resulting output. Say that we are trying to import an XML feed with books:

<?xml version="1.0" encoding="UTF-8"?>
<products>
	<book type="paperback">
		<title lang="english">Snowcrash</title>
		<price currency="euro">3,99</price>
		<price currency="dollar">5,49</price>
		<weightGrams>247</weightGrams>
		<isbn10>0140232923</isbn10>
		<isbn13>9780140232929</isbn13>
	</book>
</products>

Running this through our XPath generator function results in the following list of XPath expressions:

products
products/book
products/book/@type
products/book[@type='paperback']
products/book/title
products/book/title/@lang
products/book/title[@lang='english']
products/book/price
products/book/price/@currency
products/book/price[@currency='euro']
products/book/price
products/book/price/@currency
products/book/price[@currency='dollar']
products/book/weightGrams
products/book/isbn10
products/book/isbn13

Generally you will only need the selectors for one particular element, in this case the book element. We’ll use an XPath expression to select this context element to limit the scope of our XPath generator.

An example of where this type of functionality might come in handy is when unknown XML data needs to be mapped into predefined fields such as columns of a database table or content types in a CMS. For example the Drupal Feeds module allows you to import XML data into existing Drupal content types. The source XML fields are mapped to the Drupal content type fields by means of user-defined XPath expressions. Currently the user has to specify these expressions by hand for each field. Wouldn’t it be nice to have a dropdown box available next to each field that contains a list of XPath expressions for all XML elements and attributes (especially when the user is not a progammer/XML expert)?

Here’s the full code, the comments should make it self-explanatory. If you are not familiar with the concept of recursion take a look at this article. In the code below the XML is supplied using the form POST method. You can try out a slightly modified version here.

<?php
$simpleXML = new SimpleXMLElement($_POST['XML']);          //create a SimpleXMLElement object from the XML document
$contextElements = $simpleXML->xpath($_POST['context']);   //select the context nodes
$contextElement = $contextElements[0];                     //grab the first context node
$xpathList = XMLElementToXPath($contextElement->getName(),$contextElement); 

foreach($xpathList as $xpath)
	echo $xpath."\n";

//recursive function that takes a SimpleXMLElement object and returns a list of XPath expressions
function XMLElementToXPath($currentXPath, $myXMLElement)
{
  $xpathList = array();
  $attributes = $myXMLElement->attributes();              //grab attributes from current root element

  foreach($attributes as $att_key=>$att_value)            //process element attributes (if any)
  {
    $xpathList[] = ($currentXPath!=''?$currentXPath.'/':'').'@'. $att_key;  //create XPath for attribute
    $xpathList[] = ($currentXPath!=''?$currentXPath:'').'[@'. $att_key.'=\''.$att_value.'\']'; //create XPath expression for element with certain attribute value
  }	

  foreach($myXMLElement->children() as $childElement)     //process children (if any)
  {
    $xpathList[]= ($currentXPath!=''?$currentXPath.'/':'').(string) $childElement->getName();  //create XPath expression for element
    if($childElement instanceof SimpleXMLElement)                              //if child is an XML node itself then go into recursion
    {
      $xpathList = array_merge($xpathList,XMLElementToXPath(($currentXPath!=''?$currentXPath.'/':'').(string)$childElement->getName(),$childElement));
    }
  }
  return $xpathList;
}
?>

As mentioned you can see a slightly modified version of the script in action here and you can download the source here. The generated list of XPath expressions isn’t complete, for example it doesn’t produce XPath expressions with combinations of multiple attributes. However this should be sufficient in most cases and can be easily extended when extra types of XPath expressions are needed. Feel free to drop any questions/comments below!

]]>
/coding/php-xpath-generator/feed/ 0
Convert MySQL to XML using PHP /coding/mysql-to-xml-php/ /coding/mysql-to-xml-php/#comments Thu, 09 Jun 2011 15:20:51 +0000 /?p=4 Continue reading...]]> How to  convert any MySQL table and data to a well-formed XML document using PHP. Building a  generic solution to a common problem.

In this tutorial we will create a standardized script that will convert a MySQL table of any shape or size into a valid XML document. This can be useful for any situation where you have to transfer data from a MySQL database into an XML based system. In some cases the “mysqldump –xml” might be sufficient. If you require output that’s different from the mysqldump format, or if you don’t have access to the mysqldump tool you will need to code your own solution. Creating a single-use script to handle specific data is of course quite easy, but would require custom coding for each table that needs to be converted to XML. I’m going to show you how (using a handy PHP function) you can build a more generalized solution. This mechanism will allow you to convert a MySQL table to XML, but also to a PHP array, CSV file (even though MySQL already supports CSV natively) or any other required format.

Let’s start with an example table and some data:

Table name: fruit

+--------------+----------------+------------------+--------------+
| fruit_id     | fruit_name     | fruit_colour     | price_per_kg |
+--------------+----------------+------------------+--------------+
| 1            | Banana         | yellow           | 2,99         |
| 2            | Orange         | orange           | 2,45         |
| 3            | Strawberries   | red              | 4,99         |
+--------------+----------------+------------------+--------------+

After running our PHP script the resulting XML will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<fruits>
   <fruit>
      <fruit_id>1</fruit_id>
      <fruit_name>Banana</fruit_name>
      <fruit_colour>yellow</fruit_colour>
      <price_per_kg>2,99</price_per_kg>
   </fruit>
   <fruit>
      <fruit_id>2</fruit_id>
      <fruit_name>Orange</fruit_name>
      <fruit_colour>orange</fruit_colour>
      <price_per_kg>2,45</price_per_kg>
   </fruit>
   <fruit>
      <fruit_id>3</fruit_id>
      <fruit_name>Strawberry</fruit_name>
      <fruit_colour>red</fruit_colour>
      <price_per_kg>4,99</price_per_kg>
   </fruit>
</fruits>

Pretty neat huh? ;-) So let’s get down to business and start by setting up our database connection:

<?php
//database configuration
$config['mysql_host'] = "localhost";
$config['mysql_user'] = "root";
$config['mysql_pass'] = "grape01";
$config['db_name']    = "fruit_store";
$config['table_name'] = "fruit";

//connect to host
mysql_connect($config['mysql_host'],$config['mysql_user'],$config['mysql_pass']);
//select database
@mysql_select_db($config['db_name']) or die( "Unable to select database");
]]>
/coding/mysql-to-xml-php/feed/ 45