How to generate XHTML Documents using DOMDocument in php

Post Reply
User avatar
Neo
Site Admin
Site Admin
Posts: 2642
Joined: Wed Jul 15, 2009 2:07 am
Location: Colombo

How to generate XHTML Documents using DOMDocument in php

Post by Neo » Mon Mar 01, 2010 12:03 am

PHP 5 includes a powerful set of DOM manipulation classes that gives you full control over XML documents. This functionality behaves very similar to JavaScript's DOM manipulation engine. In this tutorial, we'll explore the DOMDocument class by generating an entire (X)HTML page without writing a single bit of raw markup. This may not be practical for most applications, but it should give you a good idea of how the basic DOMDocument methods work.

First, let's look at what the final output should look like. The generated version will have slightly different formatting and indentation, but the functionality will be the same.

Code: Select all

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>DOMDocument</title>
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="wrapper">
  <div id="header"><img src="header.gif" alt="Header" width="400" height="100" /></div>
  <div id="nav">
    <ul>
      <li class="active"><a href="index.php">Home</a></li>
      <li><a href="download.php">Download</a></li>
      <li><a href="features.php">Features</a></li>
      <li><a href="about.php">About</a></li>
    </ul>
  </div>
  <div id="content">
    <h1>DOMDocument</h1>
    <p>This page was generated using PHPs <strong>DOMDocument</strong> class!</p>
  </div>
</div>
</body>
</html> 
As you can see, this is a very basic template with a header, navigation, and content sections. The header includes a single image, the navigation includes a list of links, and the content has a heading and any page content. All three sections are also wrapped in a "wrapper" div. Of course, all the page styling will be handled by the included CSS file in the header.

So now let's start writing code! Below each snippet is an explanation.

Code: Select all

<?php
// Create document
$doctype = DOMImplementation::createDocumentType('html',
                  '-//W3C//DTD XHTML 1.1//EN',
                  'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd');
 
$document = DOMImplementation::createDocument('http://www.w3.org/1999/xhtml',
                   'html',
                   $doctype); 

Here is where we setup the document, using a special class called DOMImplementation that allows us to easily create a document with the appropriate DOCTYPE declaration. The createDocumentType method stores the document type information in an object to be passes to the createDocument method, which actually creates the document. This document has the root <html> tag already created.

If you compare the call to createDocumentType to the <!DOCTYPE line of the XHTML, you can see where the 3 parameters come from. The createDocument class accepts the value of the xmlns attribute of the html tag, the name of the root element (<html>), and the object created by createDocumentType as parameters.

Code: Select all

// Create head element
$head = $document->createElement('head'); 
Here is an example of creating a simple element using the createElement method, in this case it is the head tag of the document. The createElement class accepts either one or two parameters. The first, and required, one is the name of the element to create. If a second parameter is supplied, it will create a text node of the supplied text and append it to the created element.

Code: Select all

$metahttp = $document->createElement('meta');
$metahttp->setAttribute('http-equiv', 'Content-Type');
$metahttp->setAttribute('content', 'text/html; charset=utf-8');
$head->appendChild($metahttp);
 
$title = $document->createElement('title', 'DOMDocument');
$head->appendChild($title);
 
$css = $document->createElement('link');
$css->setAttribute('href', 'styles.css');
$css->setAttribute('rel', 'stylesheet');
$css->setAttribute('type', 'text/css');
$head->appendChild($css); 
More examples of creating elements, as well as actually adding them to the document with the DOMNode::appendChild method. This method can be called on any node created with createElement, and accepts the node that you want to add as its parameter. For example, here we created a $title element, which we added to the $head element.

This segment also demonstrates setting attributes with the DOMElement::setAttribute method, which simply accepts the attribute name and value as parameters.

Code: Select all

// Create body element
$body = $document->createElement('body');
 
// Wrapper div
$wrapper = $document->createElement('div');
$wrapper->setAttribute('id', 'wrapper'); 
Here we created the body tag and the wrapper div.

Code: Select all

// Header div
$header = $document->createElement('div');
$header->setAttribute('id', 'header');
$wrapper->appendChild($header);
 
// Header img
$himg = $document->createElement('img');
$himg->setAttribute('src', 'header.gif');
$himg->setAttribute('alt', 'Header');
$himg->setAttribute('width', '400');
$himg->setAttribute('height', '100');
$header->appendChild($himg); 
Here, we created the header div and added the header image to it.

Code: Select all

// Nav div
$nav = $document->createElement('div');
$nav->setAttribute('id', 'nav');
$wrapper->appendChild($nav);
 
// Nav ul
$navlist = $document->createElement('ul');
$nav->appendChild($navlist); 
Here is where the nav div and list are created.

Code: Select all

$menuArray = array();
$menuArray['index.php'] = 'Home';
$menuArray['download.php'] = 'Download';
$menuArray['generate.php'] = 'Generate';
$menuArray['about.php'] = 'About';
 
$currentPage = basename($_SERVER['SCRIPT_FILENAME']);
 
foreach($menuArray as $page => $title) {
    $navitem = $document->createElement('li');
    if($page == $currentPage) {
        $navitem->setAttribute('class', 'active');
    }
 
    $navlink = $document->createElement('a', $title);
    $navlink->setAttribute('href', $page);
 
    $navitem->appendChild($navlink);
    $navlist->appendChild($navitem);
} 
Here's the fun part! First, we set up an array of navigation links and figured out the file name of the current page. Then, we looped through the array to create and append the list items and links to the nav list. We also check to see if the item is the current page, and add the "active" class if it is.

Code: Select all

// Content div
$content = $document->createElement('div');
$content->setAttribute('id', 'content');
$wrapper->appendChild($content);
 
// Actual page content
$h1 = $document->createElement('h1', 'DOMDocument');
$content->appendChild($h1); 
Here is where we start creating the content area. We created the content div and added a heading tag.

Code: Select all

$p = $document->createElement('p');
$text = $document->createTextNode('This page was generated using PHP\'s ');
$p->appendChild($text);
$text = $document->createElement('strong', 'DOMDocument');
$p->appendChild($text);
$text = $document->createTextNode(' class!');
$p->appendChild($text);
$content->appendChild($p); 
Here is where we create the paragraph element with text. In this case, since the text has a strong tag within the text, we need to break the text into pieces. First, we create the text before, then the strong text, and then the remaining text. I don't know of a better way to do this other than automating the process of breaking up text.

Code: Select all

$body->appendChild($wrapper);
 
// Add head and body to document
$html = $document->getElementsByTagName('html')->item(0);
$html->appendChild($head);
$html->appendChild($body); 
Here, we actually add the wrapper div to the body, and the head and body elements to the document. In order to access the root tag, we use getElementsByTagName and grab the first item (since there is only one, the first is the correct one). If you know of a better way to access the root element, please comment!

Code: Select all

// Output document
$document->formatOutput = true;
echo $document->saveXML();
 
Here is where we finally output the document in text form to the browser using the saveXML method. I also set the formatOutput property to true so it indents the code nicely.

Note: I used saveXML instead of saveHTML since XHTML documents follow some of the same standards as XML, such as self-closing tags using <tag />.
Post Reply

Return to “PHP & MySQL”