サニタイザ
サニタイザとは、Web(HTML)環境におけるルーチンのひとつである。WikiWikiWebなどのWebシステムにおいては重要なものではあるが、このあたりはユーザと十分な議論と合意形成が必要なため、あまり話題にはのぼらない。
概要[編集]
WikiWikiWebに代表される HTML ベースのシステムは自前のマシンに Tomcat でも載せて JSP と併用すれば簡単に構築できる。これは個人環境においては不自由はない。
これが LAN 環境において協業のために利用されるようになると、「いちいちHTMLで書くのは手間がかかる」ことから WikiWikiWeb が普及した。ところが、「ウィキ のソースコードにHTMLを貼りつけたらどうなるか?」というのが問題になる。「&(アンパサンド)」「<」「>」「行頭のタブや半角スペース」は、HTML の記述と干渉(あるいは競合)してしまう。
このとき、「文字として受けいれていいのか、それとも HTML のコードとしてそのまんま通しちゃっていいのか」が問題になるわけで、そこを切り分けるのがサニタイザである。
「遠慮なく HTML5 のコードをぶっこむ」というひともいれば、「Wiki記法に即して、編集してくれているユーザ」もいる。そのとき、切り分けてくれるのがサニタイザである。
たとえば、
'&'は「&」に、
'<'は「<」に、
'>'は「>」に、
'"'は「"」に、
'''は「'」に、
' 'は「 」に、
'˜'は「˜」に、
'¥'は「¥」に、
'˜'は「˜」に、
'©'は「©」に、
書きかえるのがサニタイザの仕事である。このとき、「HTML のコードは 3 タブ、Java のコードは 4 タブ」とかいったルールでコーディングをしていると見た目が相当鬱陶しいことになるので、
- まずコードを指定の値で detab して、
- それからサニタイズする
という二段構えになる。
ところが、サニタイザの仕様はわかりやすい形で提示されてはいないので、どなたかに交通整理を行なっていただきたいと思っている。[1]
関連項目[編集]
その他[編集]
参考文献[編集]
脚注[編集]
- ↑ 幸いMediaWikiが存外馬鹿なせいで、変に気を使ったりはしない。おかげで仕事がやりやすく、定跡通りのコードを書けばJavaのコードが無事にインデントされた形で表示され、しかもEclipseにコピペすればちゃんと動きそうだ。これでようやくJavaのソースが晒せる。
サンプルコード[編集]
WebFitter.java[編集]
/** * * スクロール表示ができるように改造した。 * http://animaleconomicus.blog106.fc2.com/blog-entry-1359.html に掲載。 * 旧版が Sanitizer.java。 */ import java.awt.BorderLayout; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextArea; public class WebFitter extends JFrame { private static JTextArea textArea; public static void main( String[] args ) { new WebFitter().setVisible(true); } /** * コンストラクタだ。 */ public WebFitter() { this.setSize(400, 350); this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); this.setTitle("WebFitter"); this.addWindowListener( new WindowAdapter() { /** * ウィンドウがアクティブになった。 */ @Override public void windowActivated( WindowEvent evnt ) { String src = ""; try { src = ClipBoardUtility.getTextFromClipBoard(); } catch( UnsupportedFlavorException excp ){ // 文字列以外のデータが入っていた。 excp.printStackTrace(); } catch ( IOException excp ) { // エラーになった。 excp.printStackTrace(); } // ここで Work を呼んでいる // String dst = tools.Work.sanitize(src); String dst = TextConverter.HTML_Sanitize(src); textArea.setText(dst); } /** * ウィンドウがアクティブでなくなった。 */ @Override public void windowDeactivated( WindowEvent e ) { // 現在表示されている内容がクリップされる。 ClipBoardUtility.setTextToClipBoard(textArea.getText()); } } ); /** * キーをタイプすると、その内容が入力される。 * バックスペースと漢字は未対応。 */ this.addKeyListener( new KeyAdapter() { @Override public void keyPressed( KeyEvent evnt ) { String msg = textArea.getText() + evnt.getKeyChar(); textArea.setText(msg); } } ); textArea = new JTextArea(5, 20); textArea.setLineWrap(true); // label.addMouseListener(MyMouseA0); textArea.addMouseListener( new MouseAdapter(){ @Override public void mouseClicked( MouseEvent evnt ){ // ダブルクリックするとクリア // なんか、かぶってる気がするんですが。 if ( evnt.getClickCount() == 2 ){ textArea.setText(""); } } } ); // JFrame である Sanitizer_x に textArea を追加 // ここにスクロールペインが入るはず。t /* スクロールの必要がなければ、 直接 textArea を add することもできる。 this.add(textArea, BorderLayout.CENTER); */ JScrollPane sp = new JScrollPane(textArea); this.add(sp, BorderLayout.CENTER); String tmp = ""; try { tmp = ClipBoardUtility.getTextFromClipBoard(); } catch( IOException excp ) { // 文字列以外のデータが入っていた。 excp.printStackTrace(); } catch( UnsupportedFlavorException excp ){ // 文字列以外のデータが入っていた。 excp.printStackTrace(); } textArea.setText("<pre>\n"+ tmp + "<\n></pre>\n"); } }
TextConverter.java[編集]
/** * HTML 用サニタイザ. * * */ public class TextConverter { public static void main( String[] args ) { } public static String HTML_Sanitize( String src ) { StringBuffer buf = new StringBuffer(); int posx = 0; for (int pos = 0; pos < src.length(); pos += 1 ){ char ch = src.charAt(pos); switch(ch) { case '\t': for (int n = 0; n < (4 - (posx % 4)); n += 1) { buf.append(' '); posx += 1; } break; case '<': buf.append("<"); posx += 1; break; case '>': buf.append(">"); posx += 1; break; case '&': buf.append("&"); posx += 1; break; case '\'': buf.append("'"); posx += 1; break; case '\"': buf.append("""); posx += 1; break; case '\n': buf.append('\n'); posx = 1; break; default: buf.append(ch); posx += 1; break; } } return ("<pre>\n"+ buf.toString() + "</pre>\n" ); } }
ClipBoardUtility.java[編集]
/** * main がないので、テスト用のルーチンがどこにあるのかは用件等。 */ import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import javax.swing.JFrame; public class ClipBoardUtility { /** * クリップボードに入っているテキストの内容を取ってくる。 * 画像とかだったらいかがなものかと思うが。 * @return クリップボードに入っているテキスト * @throws IOException * @throws UnsupportedFlavorException */ public static String getTextFromClipBoard() throws IOException, UnsupportedFlavorException { return getTextFromClipBoard(null); } /** * * @param frame * @return * @throws IOException * @throws UnsupportedFlavorException */ public static String getTextFromClipBoard( JFrame frame ) throws IOException, UnsupportedFlavorException { Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable object = clipboard.getContents(frame); String str = (String)object.getTransferData(DataFlavor.stringFlavor); return str; } /** * クリップボードに指定のテキストをセットする。 * @param str */ public static void setTextToClipBoard( String str ){ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); StringSelection selection = new StringSelection(str); clipboard.setContents(selection, null); } }