tohokuaikiのチラシの裏

技術的ネタとか。

PHPのDOMDocumentでHTML→XMLに再構築する方法

PHPのDOMDocument、なかなか戦えるじゃないか。

空タグ(<br/>とかね)をappendChildすると、そのままDOMTextみたいにつなげてくれるっていうのは知らなかった。Nice!

ということでサンプル。
次のHTMLを HTML/body/table/td[@class=pagebody]のDOMだけ取り出して再構築してみる。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>DEMO Space : I. はじめに</title>
	    <link rel="stylesheet" href="styles/site.css" type="text/css" />
        <META http-equiv="Content-Type" content="text/html; charset=UTF-8">	    
    </head>

    <body>
	    <table class="pagecontent" border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="#ffffff">
		    <tr>
			    <td valign="top" class="pagebody">
				    <div class="pageheader">
					    <span class="pagetitle">
                            DEMO Space : I. はじめに
                                                    </span>
				    </div>
				    <div class="pagesubheading">
					    This page last changed on 2 01, 2011 by <font color="#0050B2"></font>.
				    </div>

				    <p><br class="atl-forced-newline" /></p>

<h1><a name="I.%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB-%E2%85%A0.%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB"></a>Ⅰ.はじめに</h1>


<h2><a name="I.%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB-1.1%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6"></a>1.1インストールについて</h2>

<p>この説明書はsmartFORCEのインストール方法について説明しています。<br class="atl-forced-newline" /></p>

<h3><a name="I.%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB-1.1.1%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%89%8B%E9%A0%86%5C%5C"></a>1.1.1インストール手順<br class="atl-forced-newline" /></h3>

<p>インストール手順は、</p>

<p>・①データのダウンロード・解凍</p>

<p>・②データベースの作成</p>

<p>・③インストールウィザード画面からインストール</p>

<p>からなります。<br class="atl-forced-newline" /></p>

<h3><a name="I.%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB-1.1.2%E5%89%8D%E6%8F%90%E6%9D%A1%E4%BB%B6%5C%5C"></a>1.1.2前提条件<br class="atl-forced-newline" /></h3>

<p>次のソフトウェアのあらかじめインストールされていることを前提とします。</p>

<p>・Microsoft Windows SQL Server 2005 または MySQL 5.0</p>

<p>・Adobe ColdFusion 8 以上</p>

				    
                    			    </td>
		    </tr>
	    </table>
	    <table border="0" cellpadding="0" cellspacing="0" width="100%">
			<tr>
				<td height="12" background="http://word.wikiworks.jp/images/border/border_bottom.gif"><img src="images/border/spacer.gif" width="1" height="1" border="0"/></td>
			</tr>
		    <tr>
			    <td align="center"><font color="grey">Document generated by Confluence on 12 16, 2011 14:24</font></td>
		    </tr>
	    </table>
    </body>
</html>
<?php
$html=<<EOF
ここに上記のHTMLが入っている
EOF;

$dom = new DOMDocument();
$dom->loadHTML($html);

$rootTagName = 'td';
$tds = $dom->getElementsByTagName($rootTagName);
$td = null;
for ($i=0; $i<$tds->length; $i++){
    if ($tds->item($i)->getAttribute('class') == 'pagebody'){
        $td = $tds->item($i);
    }
}

$xml = new DOMDocument('1.0', 'utf-8');
$root = $xml->createElement('Pages');
$xml->appendChild($root);
$parentNode = $root;
/* clone */
$page = $xml->createElement('Page');
foreach ($td->childNodes as $child){
    $c_node = $xml->importNode($child, true);
    $page->appendChild($c_node);
}
/* /clone */
showElements($page);
$xml->formatOutput = true;
echo $xml->saveXML();


function showElements($element, $is_last = false)
{
    global $xml, $parentNode;
    
    /// 子要素がある場合は、親を委譲して再帰
    if ($element->hasChildNodes()){
        $ele = $xml->createElement($element->tagName);
        $parentNode->appendChild($ele);
        $parentNode = $ele;
        for ($i=0;$i<$element->childNodes->length; $i++){
            showElements($element->childNodes->item($i), $i+1 == $element->childNodes->length);
        }
    }
    else {
        // 子要素が無い場合はテキストノードか空タグ
        $text = trim($element->textContent);
        if (isDOMText($element)){
            /// テキストノード
            if ($text){
                $parentNode->appendChild($xml->createTextNode($text));
            }
        }
        else {
            /// 空タグ
            $parentNode->appendChild($xml->createElement($element->tagName));
        }
    }
    //// DOMのケツを見極める
    if ($is_last){
        $parentNode = $parentNode->parentNode;
    }
}

// echo $dom->saveHTML();

function isDOMText($element)
{
    return strcasecmp('DOMText', get_class($element)) === 0 ;
}

すると、

<?xml version="1.0" encoding="utf-8"?>
<Pages>
  <Page>
    <div>
      <span>DEMO Space : I. はじめに</span>
    </div>
    <div>This page last changed on 2 01, 2011 by<font/>.</div>
    <p>
      <br/>
    </p>
    <h1><a/>Ⅰ.はじめに</h1>
    <h2><a/>1.1インストールについて</h2>
    <p>この説明書はsmartFORCEのインストール方法について説明しています。<br/></p>
    <h3><a/>1.1.1インストール手順<br/></h3>
    <p>インストール手順は、</p>
    <p>・①データのダウンロード・解凍</p>
    <p>・②データベースの作成</p>
    <p>・③インストールウィザード画面からインストール</p>
    <p>からなります。<br/></p>
    <h3><a/>1.1.2前提条件<br/></h3>
    <p>次のソフトウェアのあらかじめインストールされていることを前提とします。</p>
    <p>・Microsoft Windows SQL Server 2005 または MySQL 5.0</p>
    <p>・Adobe ColdFusion 8 以上</p>
  </Page>
</Pages>

というようになる。