Chapter 6. XML

XML is another very common data format used with APIs, and should feel familiar to us as developers. Anyone who has spent much time with the Web will understand the “pointy brackets” style of XML and will be able to read it. XML is a rather verbose format; the additional punctuation and scope for attributes, character data, and nested tags can make for a slightly bigger data size than other formats.

XML has many more features than JSON, and can represent a great many more things. You’ll see more of this in Chapter 7, where complex data types and namespaces will come into play. XML doesn’t have to be complicated; simple data can also be easily represented, just as it is with JSON. Consider our shopping list again:

  • eggs

  • bread

  • milk

  • bananas

  • bacon

  • cheese

The XML representation of this list would be:

<?xml version="1.0"?>
<list>
  <item>eggs</item>
  <item>bread</item>
  <item>milk</item>
  <item>bananas</item>
  <item>bacon</item>
  <item>cheese</item>
</list>

Working with XML in PHP isn’t quite as easy as working with JSON was, because XML is more complicated. To produce the previous example, the code in Example 6-1 was used.

Example 6-1. Working with XML
<?php

$list = array(
	"eggs",
	"bread",
	"milk",
	"bananas",
	"bacon",
	"cheese"
);

$xml = new SimpleXMLElement("<list />");
foreach($list as $item) {
    $xml->addChild("item", $item);
}

// for nice output
$dom = dom_import_simplexml($xml)->ownerDocument;
$dom->formatOutput = true;
echo $dom->saveXML();

The starting point is the array that will be our list. Next, a SimpleXMLElement object is instantiated with a root tag that forms the basis for the document. In XML, everything has to be in a tag, so an <item> tag has been introduced in order to contain each list item.

The final block only makes the output prettier, which isn’t usually important because XML is for machines, not for humans. To get the XML to convert from a SimpleXMLElement object, call the asXML() method on that object, which returns a string. The string, however, is all on one line!

The previous example instead converted from SimpleXMLElement to DOMElement, and then grabbed the DOMDocument from that. Set the formatOutput to true, so when a call is made to DOMDocument::saveXML() (to ask it to return the XML as a string), the resulting output will be nicely formatted.

XML’s abilities to represent attributes, children, and character data all provide a more powerful and descriptive way to represent data than, for example, JSON. These same features make XML a great way to represent very detailed information, including data-type information, so it’s a great choice when those details really do matter. It can include information about the types of data and custom data types, and each element can have attributes to describe specific properties of an element. XML also supports namespaces that are sometimes used in complex data types (beware that namespaces are better supported by DOM in PHP than by SimpleXML).

The larger data format is less of a concern when working with powerful machines and fast network connections, so XML is a popular choice when exchanging data between computers or servers, rather than sending things to phones or web browsers. Do be aware, however, that bandwidth costs may well still apply and may be a significant cost factor when large amounts of data are being transferred.

APIs are all about integration between systems and sometimes the choice of data format will be dictated by whatever is on the other end of the relationship. XML is particularly popular among many enterprise technology platforms such as Java, Oracle, and .NET, so users of these technologies will often request XML as a preferred format. If you are working with products or people that would prefer XML or are more confident handling this format, then offer XML, even if only as one of multiple data format options in your API.

XML in PHP

There are many ways we can work with XML in PHP, and they’re all useful in different situations. There are three main approaches to choose from and they all have their advantages and disadvantages:

  1. SimpleXML is the most approachable, and my personal favorite. It is easy to use and understand, is well documented, and provides a simple interface (as the name suggests) for getting the job done. SimpleXML does have some limitations, but it is recommended for most applications.

  2. DOM is handy when a project encounters some of the limitations in SimpleXML. It’s more powerful and therefore more complicated to use, but there are a small number of operations that can’t be done with SimpleXML. There are built-in functions to allow conversion between these two formats, so it’s very common to use a combination of both in applications, as we saw earlier in Example 6-1.

  3. XMLReader, XMLWriter, and their sister XMLParser are lower-level ways of dealing with XML. In general, these tools are complicated and unintuitive but they have a major advantage: they are streams-based and therefore don’t load the entire XML document into memory at once. If very large data sets are involved, then this approach will be your friend.

Creating XML

There are a few libraries around but let’s look at some examples of how to create a simple XML document. We’ll be aiming to output sample output with a mixture of elements and attributes, as seen in Example 6-2.

Example 6-2. Sample XML document to use for our examples
<?xml version="1.0" ?>
<hotels>
	<hotel name="Queens Hotel">
		<rooms>17</rooms>
		<price>150</price>
	</hotel>
	<hotel name="Kings Hotel">
		<rooms>12</rooms>
		<price>150</price>
	</hotel>
	<hotel name="Grand Hotel">
		<rooms>27</rooms>
		<price>100</price>
	</hotel>
</hotels>

Usually we generate XML from stored data, but here are some examples with hardcoded values so you can see very clearly just the XML parts on their own. In a real application, you’d use all the XML functionality I’m showing here, with loops to select data from a database. First, look at Example 6-3 for an example of creating this in SimpleXML.

Example 6-3. Create a sample XML document using SimpleXML in PHP
<?php

$document = new SimpleXMLElement("<hotels />");

$kings = $document->addChild("hotel");
$kings->addAttribute("name", "Kings Hotel");
$kings->addChild("rooms", 12);
$kings->addChild("price", 150);

$queens = $document->addChild("hotel");
$queens->addAttribute("name", "Queens Hotel");
$queens->addChild("rooms", 17);
$queens->addChild("price", 150);

$grand = $document->addChild("hotel");
$grand->addAttribute("name", "Grand Hotel");
$grand->addChild("rooms", 27);
$grand->addChild("price", 100);

This is fairly straightforward and easy to follow. Example 6-4 uses the DOM extension instead, which is a bit longer.

Example 6-4. Create a sample XML document using PHP’s DOM extension
<?php

$document = new DOMDocument();
$hotels = $document->createElement('hotels');
$document->appendChild($hotels);

$kings = $document->createElement("hotel");
$name = $document->createAttribute('name');
$name->value = "Kings Hotel";
$kings->appendChild($name);
$rooms = $document->createElement("rooms", 12);
$kings->appendChild($rooms);
$price = $document->createElement("price", 150);
$kings->appendChild($price);

$hotels->appendChild($kings);

$queens = $document->createElement("hotel");
$name = $document->createAttribute('name');
$name->value = "Queens Hotel";
$queens->appendChild($name);
$rooms = $document->createElement("rooms", 17);
$queens->appendChild($rooms);
$price = $document->createElement("price", 150);
$queens->appendChild($price);

$hotels->appendChild($queens);

$grand = $document->createElement("hotel");
$name = $document->createAttribute('name');
$name->value = "Grand Hotel";
$grand->appendChild($name);
$rooms = $document->createElement("rooms", 27);
$grand->appendChild($rooms);
$price = $document->createElement("price", 100);
$grand->appendChild($price);

$hotels->appendChild($grand);

The DOM example is longer and for this trivial example it can seem quite clunky. It’s worth including, though, since if you work with advanced XML services and especially if you need to work with namespaces and do complex manipulation of XML (for example, you can only change the order of nodes with DOM), then this extension will be an excellent approach.

Converting between SimpleXML and DOM extensions is very simple; I often do this in my own applications where most of the work can be done with SimpleXML, but perhaps just one more piece of advanced functionality is required from DOM. PHP offers the functions dom_import_simplexml() and simplexml_import_dom() so you can easily switch between the two rather than being locked into one or the other in a particular project.

Consuming XML APIs

We’ll look at a specific example shortly (the Flickr kitten photos) but first let’s take a look at how we can use PHP to get data from an XML document.

Parsing XML

We’ve seen how to create XML already. Let’s use the same document and do the opposite: translate the XML into data we can use. SimpleXML is a really excellent way to parse XML and Example 6-5 has an example of how that could look.

Example 6-5. Parse our sample XML with SimpleXML
<?php

$xml = new SimpleXMLElement(file_get_contents("sample.xml"));

echo("List of Hotels:
");

foreach($xml->children() as $hotel) {
	echo $hotel['name'];
	echo " has " . $hotel->rooms . " rooms";
	echo " and costs " . $hotel->price. " EUR per night";
	echo "
";
}
Tip

When working with SimpleXML, be aware that properties such as rooms and price in the preceding example are actually of type SimpleXMLElement. You will need to cast them to strings, either by echoing as done here, or by expressly casting the values so you can assign or return them.

If you need to parse a very large XML document (bigger than the memory PHP has available) then check out the XMLReader functionality in PHP. This works using streams, which means you don’t need to load the entire document into memory to work on it. For all other cases, SimpleXML is a great idea and regular expressions are never recommended for parsing XML. Now that we’ve got our tools ready, let’s move on to look at a real example.

Flickr’s XML API

There are a wide variety of APIs using XML. This next example looks at the photo-sharing site Flickr. The Flickr API provides a wide variety of functionality for working with photos, and every language will have some classes available that you can use with it, but there’s no reason not to interact with the API directly. Example 6-6 shows how to find a list of kitten pictures.

Example 6-6. Fetching data from Flickr’s XMLRPC service
<?php

require("api-key.php");
$animal = "kitten";
$data = file_get_contents('https://api.flickr.com/services/rest/?'
    . http_build_query(array(
        "method" => "flickr.photos.search",
        "api_key" => $api_key,
        "tags" => $animal,
        "format" => "xmlrpc",
        "per_page" => 6
    ))
);

This example requests all the newest photos tagged “kitten” from Flickr. It relies on another file called api-key.php that simply defines the $api_key variable; it’s separate to make it easier to avoid accidentally sharing it or adding it to my git repository.

Flickr uses an API key passed as a URL parameter, which is a different approach than the Authorization header examples that have been demonstrated so far; each API will implement this in a different way. Although the header is a better practice, the developers of Flickr were trailblazers with implementing APIs for users, so there was no best practice when it was built. Since it’s simply a GET request, this example uses file_get_contents() to fetch the carefully crafted URL. The resulting response looks something like this:

<?xml version="1.0" encoding="utf-8" ?>
<methodResponse>
	<params>
		<param>
			<value>
				<string>
&lt;photos page=&quot;1&quot; pages=&quot;81588&quot; perpage=&quot;6&quot; total=&quot;489527&quot;&gt;
	&lt;photo id=&quot;19456951044&quot; owner=&quot;130395922@N06&quot; secret=&quot;5986d9cdf8&quot; server=&quot;505&quot; farm=&quot;1&quot; title=&quot;Lounging&quot; ispublic=&quot;1&quot; isfriend=&quot;0&quot;
	isfamily=&quot;0&quot; /&gt;
	&lt;photo id=&quot;19890527230&quot; owner=&quot;41867033@N00&quot; secret=&quot;7863b99ca0&quot; server=&quot;276&quot; farm=&quot;1&quot; title=&quot;Sholai, Kodaikanal, Cats&quot; ispublic=&quot;1&quot; isfriend=&quot;0&quot;
	isfamily=&quot;0&quot; /&gt;
	&lt;photo id=&quot;19455867524&quot; owner=&quot;41867033@N00&quot; secret=&quot;400c7ba669&quot; server=&quot;428&quot; farm=&quot;1&quot; title=&quot;Sholai, Kodaikanal, Cats&quot; ispublic=&quot;1&quot; isfriend=&quot;0&quot; isfamily=&quot;0&quot; /&gt;
	&lt;photo id=&quot;20083899801&quot; owner=&quot;41867033@N00&quot; secret=&quot;89e2242440&quot; server=&quot;328&quot; farm=&quot;1&quot; title=&quot;Sholai, Kodaikanal, Cats&quot; ispublic=&quot;1&quot; isfriend=&quot;0&quot; isfamily=&quot;0&quot; /&gt;
	&lt;photo id=&quot;20083891431&quot; owner=&quot;41867033@N00&quot; secret=&quot;bf47f466ec&quot; server=&quot;429&quot; farm=&quot;1&quot; title=&quot;Sholai, Kodaikanal, Cats&quot; ispublic=&quot;1&quot; isfriend=&quot;0&quot; isfamily=&quot;0&quot; /&gt;
	&lt;photo id=&quot;19457506953&quot; owner=&quot;41867033@N00&quot; secret=&quot;98b030686f&quot; server=&quot;477&quot; farm=&quot;1&quot; title=&quot;Sholai, Kodaikanal, Cats&quot; ispublic=&quot;1&quot; isfriend=&quot;0&quot; isfamily=&quot;0&quot; /&gt;
&lt;/photos&gt;
				</string>
			</value>
		</param>
	</params>
</methodResponse>

Because the data is sent as an escaped XML string, the XML is parsed in PHP, then the string is extracted and parsed as a separate step in order to obtain the real data. Flickr doesn’t supply the actual URL of the image, but gives enough information in the response that the instructions can be followed to assemble the desired URL. SimpleXML is used in this example—first to parse the response, then to parse the data inside it. This library represents child elements as object properties (and each child is a SimpleXMLElement), while attributes are accessed using array notation.

Here’s Example 6-6 again, processing the data and outputting it with titles and <img> tags:

<?php

require("api-key.php");
$animal = "kitten";
$data = file_get_contents('http://api.flickr.com/services/rest/?'
    . http_build_query(array(
        "method" => "flickr.photos.search",
        "api_key" => $api_key,
        "tags" => $animal,
        "format" => "xmlrpc",
        "per_page" => 6
    ))
);

$simplexml = new SimpleXMLElement($data);
$data_array = $simplexml->params->param->value->children();

$photos = new SimpleXMLElement($data_array->string);

if($photos) {
    foreach($photos->photo as $photo) {
        echo $photo['title'] . "
";
        echo '<img src="http://farm' . $photo['farm'] . '.staticflickr.com/'
            . $photo['server'] . '/' .$photo['id'] . '_' . $photo['secret']
            . '.jpg" /><br />' . "
";
    }
}

The main body of the data contains a <photos> tag with multiple <photo> tags inside it—one for each photo. Each <photo> tag has some attributes inside it, so array notation is used to access these, retrieve the title, and build the image tag.

When working with APIs, you will see different data formats in use in a variety of settings. This chapter has shown how to create, work with, and parse XML. XML is more common on older and larger applications, but the data format will depend on the target market of the API, and many providers will offer multiple formats. Flickr, for example, offers data in both JSON and XML format, but also offers a serialized PHP format. PHP’s serialized format is very easy to work with and is a great choice for two PHP applications exchanging data; if you were to integrate Flickr into your own PHP application, this would be good format to choose. When integrating with applications on other technology platforms, XML is a better-supported choice.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset