Convert($source);
return $body;
}
// 変換クラス
class XHTML2Wiki
{
var $body;
var $text;
var $parent_div;
var $div_level;
var $level_array;
var $protect_data;
// 初期化
function XHTML2Wiki() {
$this->parent_div = array('');
$this->div_level = 0;
$this->level_array = array(0);
$this->protect_data = array();
$this->text = '';
}
// 変換メソッド
function Convert($source) {
$this->body = '';
//
が行末にならない場合の対処
// -文字列~ のような場合の挙動に対応
$source = preg_replace("/
\", "~\n<", $source);
// 1行ずつに分割
$source = explode("\n", $source);
// 一行ずつ取り出し
foreach ($source as $line) {
$this->Div($line);
}
// 構文を結合
$return_body = implode('', $this->body);
// 構文補正
$return_body = preg_replace("/___GUIPD(\d+)___/e", '$this->protect_data["$1"-1]', $return_body);
$return_body = preg_replace("/\n\n\n+/", "\n\n", $return_body);
return $body;
}
// ブロック要素
function Div($line) {
if ($line == '') {
return;
}
if ($this->GetDiv() == 'Table') {
$this->Table($line);
return;
}
// 整形済みテキスト
if (preg_match("/
/", $line, $matches)) {
$this->StartDiv('Pre');
}
else if ($this->GetDiv() == 'Pre') {
if (preg_match("/(.*)<\/pre>/", $line, $matches)) {
$line = $matches[1];
$this->EndDiv();
}
$line = preg_replace("/
/", "\n ", $line);
$line = strip_tags($line);
$this->OutputLine(' ' . $this->DecodeSpecialChars($line));
}
// 見出し
else if (preg_match("/(.*)/", $line, $matches)) {
$this->StartDiv('Heading');
$level = $matches[1];
$line = $matches[3];
$attribute = $matches[2];
if (preg_match("/id=\"(\w+)\"/", $attribute, $matches)) {
$line .= ' [#' . $matches[1] . ']';
}
$this->OutputLine(str_repeat("*", --$level), $line);
$this->EndDiv();
}
// ブロック型プラグイン
else if (preg_match("/]*?)class=\"(plugin|ref)\"(.*?)>(.*)/", $line)) {
$line = preg_replace("/
/", "\n", $line);
$line = strip_tags($line);
$this->OutputLine($this->DecodeSpecialChars($line));
}
// 引用文
else if (preg_match("//", $line)) {
if ($this->GetDiv() != 'Blockquote') {
$this->StartDiv('Blockquote');
}
$this->div_level++;
$this->OutputLine(str_repeat('>', $this->GetLevel()));
}
// リスト
else if (preg_match("/<(o|u|d)l.*?>/", $line, $matches)) {
$element = strtoupper($matches[1]) . 'List';
if ($this->GetDiv() != $element) {
$this->StartDiv($element);
}
$this->div_level++;
}
// テーブル
else if (preg_match("//", $line)) {
$this->StartDiv('Table');
}
// 水平線
else if (preg_match("/^
$/", $line, $matches)) {
if ($matches[2] == 'short_line') {
$this->OutputLine('#hr');
}
else {
$this->OutputLine('----');
}
}
// 改頁
else if (strpos($line,'') !== false) {
$this->OutputLine('#pagebreak');
}
else {
switch ($this->GetDiv()) {
case 'OList':
$this->OList($line);
break;
case 'UList':
$this->UList($line);
break;
case 'DList':
$this->DList($line);
break;
case 'Blockquote':
$this->Blockquote($line);
break;
default:
$this->Paragraph($line);
break;
}
}
}
// 番号付きリスト
function OList($line) {
if (preg_match("/<\/ol>/", $line)) {
$this->div_level--;
if ($this->div_level == 0) {
$this->EndDiv();
if ($this->GetDiv() == '') {
$this->OutputLine();
}
}
}
else if (preg_match("/^()?(.*?)(<\/li>)?$/", $line, $matches)) {
$head = '';
if ($matches[1]) {
$head = str_repeat("+", $this->GetLevel());
}
if (!$matches[1] && isset($matches[3]) && !$matches[3]) {
$this->Paragraph($line);
}
else if ($head || $matches[2]) {
$this->OutputLine($head, $matches[2]);
}
}
}
// 番号なしリスト
function UList($line) {
if (preg_match("/<\/ul>/", $line)) {
$this->div_level--;
if ($this->div_level == 0) {
$this->EndDiv();
if ($this->GetDiv() == '') {
$this->OutputLine();
}
}
}
else if (preg_match("/^( )?(.*?)(<\/li>)?$/", $line, $matches)) {
$head = '';
if ($matches[1]) {
$head = str_repeat("-", $this->GetLevel());
}
if (!$matches[1] && isset($matches[3]) && !$matches[3]) {
$this->Paragraph($line);
}
else if ($head || $matches[2]) {
$this->OutputLine($head, $matches[2]);
}
}
}
// 定義リスト
function DList($line) {
if (preg_match("/<\/dl>/", $line)) {
$this->div_level--;
if ($this->div_level == 0) {
$this->EndDiv();
if ($this->GetDiv() == '') {
$this->OutputLine();
}
}
}
else if (preg_match("/^\s*()?(.*?)(<\/d(t|d)>)?\s*$/", $line, $matches)) {
$text = $matches[3];
if ($matches[2] == 't') {
$this->OutputLine(str_repeat(':', $this->GetLevel()), $text, '|');
}
else if ($text) {
$this->OutputLine('', $text);
}
}
}
// 引用文
function Blockquote($line) {
if (preg_match("/<\/blockquote>/", $line)) {
if ($this->div_level <= 3) {
$this->OutputLine(str_repeat('<', $this->GetLevel()), '');
}
$this->div_level--;
if ($this->div_level == 0) {
$this->EndDiv();
}
}
else if (preg_match("/()?(.*?)(<\/p>)?$/", $line, $matches)) {
if (!$matches[1] && !$matches[3]) {
$this->Paragraph($line);
}
else if ($matches[2]) {
$head = $matches[1] ? str_repeat('>', $this->GetLevel()) : '';
$this->OutputLine($head, $matches[2]);
}
}
}
// テーブル
function Table($line) {
static $cells;
static $text;
static $head, $hspace, $fspace;
static $row, $col;
static $is_cell = false;
static $type = '';
static $delm = '|';
// セルの開始
if (preg_match("/]*?)?>(.*)/", $line, $matches)) {
$is_cell = true;
$cell_type = $matches[1]; // d, h
$attribute = $matches[2];
$text = '';
$line = $matches[3];
$rowspan = 1;
$colspan = 1;
$hspace = 0;
$fspace = 0;
for (; !empty($cells[$row][$col]); $col++);
// セルの連結
if (preg_match("/rowspan=\"(\d+)\"/", $attribute, $matches)) {
$rowspan = $matches[1];
}
if (preg_match("/colspan=\"(\d+)\"/", $attribute, $matches)) {
$colspan = $matches[1];
}
for ($i = 1; $i < $rowspan; $i++) {
for ($j = 0; $j < $colspan; $j++) {
$cells[$row + $i][$col + $j] = '~';
}
}
for ($i = 1; $i < $colspan; $i++) {
$cells[$row][$col++] = '>';
}
// セルの属性
$head = $this->GetTableAttribute($attribute);
// 空白
if (preg_match("/_hspace=\"(\d+)\"/", $attribute, $matches)) {
$hspace = $matches[1];
}
if (preg_match("/_fspace=\"(\d+)\"/", $attribute, $matches)) {
$fspace = $matches[1];
}
// ヘッダセル
$head .= ($cell_type == 'h') ? '~' : '';
}
// セル
if ($is_cell) {
if (preg_match("/(.*)<\/t(d|h)>/", $line, $matches)) {
$text .= $matches[1];
$text = $this->Inline($text);
if (($cell_type == 'h' && $text == '' && $hspace == 0) ||
(preg_match('/^(?:LEFT|CENTER|RIGHT|(BG)?COLOR\([#\w]+\)|SIZE\(\d+\)):/', $text) && $hspace == 0))
{
$head .= ' ';
}
$cells[$row][$col] = $head . str_repeat(' ', $hspace) . $text . str_repeat(' ', $fspace);
$col++;
$is_cell = false;
}
else {
$text .= $line;
}
}
// 行の開始
// UPK
else if (preg_match("//", $line)) {
$col = 1;
$row++;
$delm = preg_match("//", $line) ? '|' : ',';
}
// テーブルの終了
else if (preg_match("/<\/table>/", $line)) {
$cells = null;
$this->EndDiv();
$this->body[] = "\n";
}
// 書式設定行
else if (preg_match("//", $line)) {
if (count($cells)) {
$this->OutputTable($cells, $type);
$cells = array();
$row = 0;
}
$text = '';
while (preg_match("/ (.*)/", $line, $matches)) {
$line = $matches[2];
$text .= '|' . $this->GetTableAttribute($matches[1]);
}
$this->body[] = $text . "|c\n";
}
// ヘッダ・ボディ・フッタの開始
else if (preg_match("//", $line, $matches)) {
$cells = array();
$type = !empty($matches[2]) ? $matches[2] : (!empty($matches[3]) ? $matches[3] : '');
$row = 0;
}
// ヘッダ・ボディ・フッタの終わり
else if (preg_match("/<\/t(head|body|foot)>/", $line)) {
$this->OutputTable($cells, $type, $delm);
$cells = array();
}
}
// テーブルの属性を取得
function GetTableAttribute($attribute) {
$text = '';
$pattern = "/rgb\((\d+),\s(\d+),\s(\d+)\)/ie";
$attribute = preg_replace($pattern, 'sprintf("#%02x%02x%02x", "$1", "$2", "$3")', $attribute);
// 文字サイズ
if (preg_match("/font-size:\s?(\d+)px/i", $attribute, $matches)) {
$text .= 'SIZE(' . $matches[1] . '):';
}
// 背景色
if (preg_match("/background-color:\s?([#0-9a-z]+)/i", $attribute, $matches)) {
$text .= 'BGCOLOR(' . $matches[1] . '):';
}
// 文字色
if (preg_match("/(\"|\s)color:\s?([#0-9a-z]+)/i", $attribute, $matches)) {
$text .= 'COLOR(' . $matches[2] . '):';
}
// 整列
if (preg_match("/align=\"(left|center|right)\"/", $attribute, $matches)) {
$text .= strtoupper($matches[1]) . ':';
}
// 横幅
if (preg_match("/width=\"(\d+)\"/", $attribute, $matches)) {
$text .= $matches[1];
}
return $text;
}
// テーブルを出力
function OutputTable($cells, $type, $delm='|') {
$row = count($cells);
// $col = count($cells[1]);
$col = isset($cells[1]) ? count($cells[1]) : 0;
for ($i = 1; $i <= $row; $i++) {
for ($j = 1; $j <= $col; $j++) {
$this->body[] = $delm . $cells[$i][$j];
}
if ($delm != ',') {
$this->body[] = '|' . $type . "\n";
} else {
$this->body[] = $type . "\n";
}
}
}
// 段落
function Paragraph($line) {
if (preg_match("/<(p|div)(\sstyle=\"text-align:\s*(left|center|right);?\s?\")?>(.*)/", $line, $matches)) {
if ($matches[1] == 'p') {
$this->OutputLine();
}
$line = ($matches[3] ? (strtoupper($matches[3]) . ':') : '') . $matches[4];
}
if (preg_match("/(.*)<\/(p|div)>/", $line, $matches)) {
if ($matches[1]) {
$this->OutputLine('', $matches[1]);
}
if ($matches[2] == 'p') {
$this->OutputLine();
}
}
else if ($line) {
$this->OutputLine('', $line);
}
}
// インライン要素
function Inline($line) {
$line = $this->EncodeSpecialChars($line);
$line = preg_replace("/\n/", "", $line);
// 水平線
if ($this->GetDiv() != 'Heading' && $this->GetDiv() != 'Table') {
$line = preg_replace("/
/", "\n----\n", $line);
$line = preg_replace("/
/", "\n#hr\n", $line);
}
// プラグイン
$pattern = "/]*?class=\"(plugin|ref)\".*?>(.*?);<\/span>/";
$line = preg_replace_callback($pattern, array(&$this, 'InlinePlugin'), $line);
// リンク
$line = preg_replace_callback("/(.*?)<\/a>/", array(&$this, 'Link'), $line);
// アンカー
$line = preg_replace("/<\/a>/", "&aname($1);", $line);
$line = preg_replace("/(.*?)<\/a>/", "&aname($1){" . "$2" . "};", $line);
// 顔文字・注釈・コメント
$line = preg_replace_callback("/\s?
/", array(&$this, 'Image'), $line);
// 太字
$line = preg_replace("/<\/?strong>/", "''", $line);
// 斜体
$line = preg_replace("/<\/?em>/", "'''", $line);
// 下線
$line = preg_replace("/<\/?u>/", "%%%", $line);
// 取消線
$line = preg_replace("/<\/?strike>/", "%%", $line);
// 上付き文字
$line = preg_replace("/(.*?)<\/sup>/", "&sup{"."$1"."};", $line);
// 下付き文字・添え字
$line = preg_replace("/(.*?)<\/sub>/", "&sub{"."$1"."};", $line);
// 文字のサイズ・色
$line = preg_replace_callback("/<(\/)?span(.*?)>/", array(&$this, 'Font'), $line);
// 改行
global $line_break;
if ($this->GetDiv() == "Heading" || $this->GetDiv() == "Table") {
$line = preg_replace("/
/", "&br;", $line);
}
else if ($line_break) {
$line = preg_replace("/
(
)?/e", '("$1" ? "~" : "") . "\n"', $line);
}
else {
$line = preg_replace("/
/", "~\n", $line);
}
// 無駄な改行を削除
$line = preg_replace("/\n\n+/", "\n", $line);
$line = preg_replace("/(^\n|\n$)/", "", $line);
// タグの除去
$line = strip_tags($line);
// スペース
$line = preg_replace("/ /", " ", $line);
// 特殊文字
$line = preg_replace("/"/", '"', $line);
if ($this->GetDiv() == 'Heading' || $this->GetDiv() == 'Table') {
$line = preg_replace("/\n/", '', $line);
$line = preg_replace("/</", "<", $line);
$line = preg_replace("/>/", ">", $line);
}
else {
$line = preg_replace("/\s+$/", '', $line);
$line = preg_replace("/^\s+/m", '', $line);
}
$line = $this->DecodeSpecialChars($line);
return $line;
}
// リンク
function Link($matches) {
$url = $matches[1];
$alias = strip_tags($matches[2]);
return '[[' . (($url == $alias) ? '' : $alias.'>') . $url.']]';
}
// 顔文字・注釈・コメント
function Image($matches) {
$attribute = $matches[1];
if (preg_match("/alt=\"(.*?)\"/", $attribute, $matches)) {
$alt = $matches[1];
// 注釈
if ($alt == 'Note' && preg_match("/title=\"(.+?)\"/", $attribute, $matches)) {
return '((' . $this->DecodeSpecialChars($matches[1]) . '))';
}
// コメント
else if ($alt == 'Comment' && preg_match("/title=\"(.+?)\"/", $attribute, $matches)) {
$comment = $matches[1];
$comment = str_replace("___br___", "\n//", $comment);
$comment = "//" . $this->DecodeSpecialChars($comment);
array_push($this->protect_data, $comment);
return "\n___GUIPD" . count($this->protect_data) . "___\n";
}
// 顔文字
// JO1UPK
// else if (preg_match("/^\[.+\]$/", $alt, $matches)) {
else if (preg_match("/^\[(.+)\]$/", $alt, $matches)) {
return '&' . $matches[1].';';
}
return ' '.$alt.' ';
}
return '';
}
// 文字のサイズ・色
function Font($matches) {
static $foot_array = array();
$attribute = $matches[2];
if (!$matches[1]) {
if (preg_match("/font-size:\s?((\d+)px|[a-z\-]+)/", $attribute, $matches)) {
if ($matches[2]) {
array_unshift($foot_array, '};');
return "&size($matches[2]){";
}
switch ($matches[1]) {
case 'xx-small': $size = '1'; break;
case 'x-small': $size = '2'; break;
case 'small': $size = '3'; break;
case 'medium': $size = '4'; break;
case 'large': $size = '5'; break;
case 'x-large': $size = '6'; break;
case 'xx-large': $size = '7'; break;
}
if ($this->GetDiv() == 'Heading' || $this->GetDiv() == 'Table') {
array_unshift($foot_array, '');
}
else {
array_unshift($foot_array, "\n");
}
return 'SIZE('.$size.'):';
}
$pattern = "/rgb\((\d+),\s(\d+),\s(\d+)\)/e";
$attribute = preg_replace($pattern, 'sprintf("#%02x%02x%02x", "$1", "$2", "$3")', $attribute);
if (preg_match("/background-color:\s?([#0-9a-z]+)/i", $attribute, $matches)) {
$bgcolor = $matches[1];
}
if (preg_match("/[^-]color:\s?([#0-9a-z]+)/i", $attribute, $matches)) {
$color = $matches[1];
}
if (!empty($color) || !empty($bgcolor)) {
array_unshift($foot_array, '};');
return '&color(' . ($color ? $color : '') . ($bgcolor ? (',' . $bgcolor) : '') . '){';
}
return '';
}
else {
return array_shift($foot_array);
}
}
// インライン型プラグイン
function InlinePlugin($matches) {
static $pattern, $replace;
if (!isset($pattern)) {
$rule = array(
"/&/" => "&",
"/%%/" => "%%",
"/''/" => "''",
"/[[/" => "[[",
"/]]/" => "]]",
"/{/" => "{",
"/|/" => "|",
"/}/" => "}"
);
$pattern = array_keys($rule);
$replace = array_values($rule);
}
return preg_replace($pattern, $replace, $matches[2] . ';');
}
// ブロック要素の開始
function StartDiv($element) {
array_unshift($this->parent_div, $element);
array_unshift($this->level_array, $this->div_level);
$this->div_level = 0;
}
// ブロック要素の終了
function EndDiv() {
array_shift($this->parent_div);
$this->div_level = array_shift($this->level_array);
$this->text = '';
}
// 親のブロック要素を取得
function GetDiv() {
return $this->parent_div[0];
}
// 1行出力
function OutputLine($head = '', $line = '', $foot = '') {
if ($line != '') {
$line = $this->Inline($line);
}
$this->body[] = $head . $line . $foot . "\n";
$this->text = '';
}
// 引用などのレベルは3までなので4以上の時は3を返す
function GetLevel() {
return ($this->div_level <= 3) ? $this->div_level : 3;
}
// エンコード
function EncodeSpecialChars($line) {
static $pattern = array("/\%\%/", "/\'\'/", "/\[\[/", "/\]\]/", "/\{/", "/\|/", "/\}/");
static $replace = array("%%", "''", "[[",
"]]", "{", "|", "}");
return preg_replace($pattern, $replace, $line);
}
// 特殊な HTML エンティティを文字に戻す
function DecodeSpecialChars($line) {
static $pattern = array("/&/", "/</", "/>/", "/"/", "/ /","/[/","/]/");
static $replace = array('&', '<', '>', '"', ' ','[',']');
return preg_replace($pattern, $replace, $line);
}
}
?>