#考えたきっかけ
HTMLを書いたり読んだりするときに<や>がふと邪魔に感じた。
slimという書式があったなと思い出したので、似た書式で書ける変換プログラムを作ってみた。
書式は自分の好みで決めたので、結果的にはslimには少ししか似ていないものになった。
簡単な処理の割に便利なのでJavaScriptに書き換えてnode.jsで動くようにしてみようと思う。
#使い方
この投稿の最後にあるPHPスクリプト(swim.php)をサーバーに置いてから、次のようなファイルを書くとHTMLに変換されて表示される。
index.php
<?php require "swim.php"; ?>
!DOCTYPE html
html lang="ja"
head
meta charset="UTF-8"
title|テストページ
body
h1|テストページ
div
p|このページはテストページです。
結果
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストページ</title>
</head>
<body>
<h1>テストページ</h1>
<div>
<p>このページはテストページです。</p>
</div>
</body>
</html>
#書式
HTMLから<と>と閉じタグを取り除き、テキストの前に|を書く。
タグの階層はインデントで表現する。インデントはスペースでもタブでもいい。ただし、インデントにスペースとタブが混在してはいけない。
いくつか短縮形がある。短縮形を活用すると結構短く書けるようになる。
通常形
div class="abc def"|テキスト
classは.で表現できる。
短縮形
div.abc.def|テキスト
divは省略できる。
さらに短縮形
.abc.def|タイトル
テキストを含まない階層はまとめて書ける。
通常形
li
a href="..."
span|ここをクリック
短縮形
li>a href="...">span|ここをクリック
テキストは|に続けて書く。
一行のテキスト
p|テキスト
複数行のテキスト
p
|これがテキスト。
|続けて書く。
|そのままHTMLに出力されるので、
|小なり記号は<のように書く。
/で始まる行はHTMLには出力されない。
コメント
/ コメント
/?で始まる行はPHPのコードとして実行される。
PHPコード
/? print("OK");
#変換スクリプト
swim.php
<?php
function makeHtml() {
$stack = array();
$in = fopen($_SERVER["SCRIPT_FILENAME"], "r");
fgets($in, 4096);
while (($line = fgets($in, 4096)) !== false) {
$line = rtrim($line);
$name = ltrim($line);
$indent = strlen($line) - strlen($name);
if (substr($name, 0, 1) == "/") {
if (substr($name, 1, 1) == "?") {
eval(substr($name, 2));
}
continue;
}
$text = "";
if (strpos($name, "|") !== false) {
list($name, $text) = explode("|", $name, 2);
}
if ($name == "") {
print($text);
}
elseif (count($stack) == 0) {
$stack[0] = array($indent, $name);
printNodeOpen($stack, $text);
}
elseif ($indent == $stack[0][0]) {
printNodeClose($stack);
$stack[0] = array($indent, $name);
printNodeOpen($stack, $text);
}
elseif ($indent > $stack[0][0]) {
array_unshift($stack, array($indent, $name));
printNodeOpen($stack, $text);
}
else {
while (count($stack) > 0 && $indent <= $stack[0][0]) {
printNodeClose($stack);
array_shift($stack);
}
array_unshift($stack, array($indent, $name));
printNodeOpen($stack, $text);
}
}
while (count($stack) > 0) {
printNodeClose($stack);
array_shift($stack);
}
fclose($in);
}
function printNodeOpen($stack, $text) {
$indentLevel = $stack[0][0];
$tags = explode(">", $stack[0][1]);
$tag = array_pop($tags);
for ($i = 0; $i < count($tags); $i++) {
printNode($indentLevel + $i, $tags[$i], true, "");
}
printNode($indentLevel + count($tags), $tag, true, $text);
if (count($tags) >= 1) {
printNode($indentLevel + count($tags), $tag, false);
for ($i = count($tags) - 1; $i >= 1 ; $i--) {
printNode($indentLevel + $i, $tags[$i], false);
}
}
}
function printNodeClose($stack) {
$indentLevel = $stack[0][0];
list($tag) = explode(">", $stack[0][1], 2);
printNode($indentLevel, $tag, false);
}
function printNode($indentLevel, $tag, $isOpen, $value = "") {
$indent = str_repeat(" ", $indentLevel);
$attr = "";
if (strpos($tag, " ") !== false) {
list($tag, $attr) = explode(" ", $tag, 2);
if ($attr != "") {
$attr = " ".$attr;
}
}
$class = "";
if (strpos($tag, ".") !== false) {
$classList = explode(".", $tag);
$tag = array_shift($classList);
if ($tag == "") {
$tag = "div";
}
if (count($classList) >= 1) {
$class = " class=\"".implode(" ", $classList)."\"";
}
}
$type = "";
if (strpos($tag, "-") !== false) {
list($tag, $type) = explode("-", $tag, 2);
if ($type != "") {
$type = " type=\"".$type."\"";
}
}
if (
$tag == "!DOCTYPE" || $tag == "meta" || $tag == "link" ||
$tag == "img" || $tag == "input"
) {
if ($isOpen) {
print($indent."<".$tag.$type.$class.$attr.">\n");
}
}
elseif ($isOpen) {
print($indent."<".$tag.$type.$class.$attr.">\n");
if ($value != "") {
print($value."\n");
}
}
else {
print($indent."</".$tag.">\n");
}
}
makeHtml();
exit();