簡易 XML ビルダ/パーサ
ブログのデザイン変更に伴い、jQuery で DOM を生成する部分が増えました。引数に渡す HTML ソースを作成するのに、文字列を + 演算子で連結していくと何が何やら…。ソースを見やすくしたくて、簡易的な XML ビルダ を作成してみました。"簡易" ってつけたら何を公開してもいいのか!という声が聞こえてきそうですが、でも実際このブログのあちこちでこのモジュールを活用しています。
一応、xml を渡すとパースもできますが、引用符のネストなんかにうまく対応できていません。誤りを検出するようには作ってないので、少々間違った xml を渡しても適当に解析してしまいます。なんちゃってです。
var jp; if (!jp) jp = {}; if (!jp.raindrop) jp.raindrop = {}; if (!jp.raindrop.frog) jp.raindrop.frog = {}; jp.raindrop.frog.xmlight || (function () { function Element (name) { var _name = name; this.name = function () { return _name; }; this.children = new Elements (); this.attributes = {}; this.attr = function () { if (!arguments.length) return this.attributes; if (arguments.length == 1) return this.attributes[arguments[0]]; this.attributes[arguments[0]] = arguments[1]; return this; } this.wrap = function (name) { var elem = new Element (name); elem.children.append (this); return elem; }; this.toString = function () { var s = '<' + _name; for (var key in this.attributes) s += ' ' + key + '="' + this.attributes[key] + '"'; var c = this.children.toString (); if (c.length) s += '>' + c + '</' + _name + '>'; else s += ' />'; return s; } }; function TextNode (text) { this.toString = function () { return text; }; }; function Elements () { var _inner = []; this.add = function (name) { return this.append (new Element (name)); }; this.append = function (elem) { _inner.push (elem); return elem; }; this.addText = function (text) { return this.append (new TextNode (text)); }; this.remove = function (elem) { var index = -1; for (var i = 0; i < _inner.length; i++) { if (elem == _inner [i]) { index = i; break; } } if (index < 0) return; _inner.splice (index, 1); }; this.insert = function (index, elem) { _inner.splice (index, 0, elem); return elem; }; this.insertText = function (index, text) { return this.insert (index, new TextNode (text)); } this.item = function (index) { return _inner[index]; }; this.wrap = function (name) { var elem = new Element (name); for (var i = 0; i < _inner.length; i ++) elem.children.append (_inner[i]); return elem; }; this.length = function () { return _inner.length; }; this.toString = function () { var s = ""; for (var i = 0; i < _inner.length; i ++) s += _inner[i].toString (); return s; }; } var _parse = function (str) { var elements = new Elements (); _parseElements (str, elements); return elements; }; var _parseElements = function (str, elements) { var regex = /<((?:(\w+):)?(\w+))([^>]*)(?:\/|>(.*)<\/\1)>/g; var match = []; while (match = regex.exec (str)) { var element = elements.add (match[1]); _parseAttributes (match[4], element); if (match.length > 5) _parseElements (match[5], element.children); } }; var _parseAttributes = function (str, element) { var regex = /((?:(\w+):)?(\w+))=(["'])(.*?)(\4)/g; var match = []; while (match = regex.exec (str)) { element.attributes [match[1]] = match[5]; } }; jp.raindrop.frog.xmlight = { create: function (name) { return new Element (name); }, parse: function (str) { var c = new Elements (); _parseElements (str, c); return c; } }; }());
こんな感じ。
$(function () { var div = jp.raindrop.frog.xmlight.create ('div'); div.children.add ('img') .attr ('src', 'foo.jpg') .attr ('alt', 'click me !') .wrap ('a') .attr ('href', 'bar.html') .attr ('title', 'my page'); // body 内に以下の HTML が追加される // <div><a href="bar.html" title="my page"><img src="foo.jpg" alt="click me !" /></a></div> $(document.body).append (div.toString ()); });
トラックバック
- このエントリーにトラックバック:
- http://frog.raindrop.jp/cgi-bin/mt/mt-tb.cgi/2547
コメント