Following the discussion at RicSherlock/XHTML, here's a shot at generating a tag from the tag;attrs;tags specification.
NB. tag name;attrs;tags
tag=: 3 : 0
if. 0=L.y do. htsafe ":y return. end.
'e a c'=. y
if. 0=#e do. htsafe ":c return. end.
e assert (<e) e. tagsC,tagsNC
A=. C=. ''
for_i. ,:^:((0<#) *. 1=#@$) a do.
'n v'=. i
n assert (<n) e. a:,attrV,attrNV
if. (<n) e. attrNV do. v=. n end.
A=. A,<' ',n,'="',(htsafe ":v),'"'
end.
for_i. ,:^:((0<#) *. 1=#@$) c do.
C=. C,<tag i
end.
r=. '<',e,;A
if. (0<#C) +. -.(<e) e. tagsNC do.
r,'>',(;C),'</',e,'>'
else. r,' />' end.
)
Cover for tag to handle errors.
buildTag=: 3 : 0
try.
tag y
catch.
13!:12''
end.
)
Utilities
NB. htsafe v replaces `&<>"` with character entities rp=. 2 : '; }. ,(<m) ,. ,.<;._1 n , y' htsafe=: [:'>'rp'>'[:'<'rp'<'[:'"'rp'"' '&'rp'&'
Nouns defining valid tag and attribute names using XHTML as an example.
tagsC=: ;: noun define-.LF NB. elements with closing tags html head title body link p pre blockquote base style span div address a object applet area h1 h2 h3 h4 h5 h6 del ins font basefont tt b i big small strike u xmp code samp em strong q cite kbd var abbr acronym dfn sub sup ul ol li dir menu dl dt dd table caption thead tfoot tbody colgroup col th tr td frameset noframes iframe form button select fieldset legend optgroup option textarea label script noscript ) tagsNC=: ;: noun define-.LF NB. elements with no closing tag img br hr param map isindex meta input ) attrV=: ;: noun define-.LF NB. attributes with value size width height align href face bgcolor text alink vlink border color src alt longdesc span hspace vspace usemap clear classid codebase codetype archive standby start value summary rowspan colspan rows cols char charoff headers scope abbr axis frame rules cellspacing cellpadding name content rel type id class title lang dir style datetime onload onunload onclick ondblclick onmousedown onmouseup onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup cite data link rel rev charset hreflang accesskey tabindex onfocus onblur shape coords media valuetype object scrolling frameborder marginwidth marginheight target for action method enctype onsubmit accept maxlength onselect onchange prompt language onreset ) attrNV=: ;: noun define-.LF NB. attributes with no value checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected )
Structure-forming tag verbs
NB. tag building verbs
elm=: (a: ,~ ;&a:) : ((<@[ ,~ a:;~])`(a: ,~ ];<@[)@.(1=L.@[))
atr=: <@(, ,:^:(1=#@$)@(,.^:(0=#))@(1&{::))`1:`] }
txt=: <@(, ,:^:(1=#@$)@(,.^:(0=#))@(2&{::))`2:`] }
Test provides different possible combinations:
Note 'test' NB. select and Ctrl+E
]t1=. 'td';(_2]\;:'name n1 class c1');<'';'';'test 1'
tag t1
]t2=. 'test <2>'elm'td' NB. text alone
tag t2
]t3=. 'td'elm~(;:'name class');&>1 2
tag t3
]t=. 'tr'elm~t1,S,t2,S,:t3 [ S=. LF elm''
tag t
]t=. 'br'elm~'class';'b"1"'
tag t
]t=. 'input'elm~'checked';''
tag t
]t=. ('id';'zz') atr ('name';'zz') atr (,:~'1'elm'td') txt elm 'tr'
tag t
]e1=. ('td'elm~_2]\;:'NotAnAttrib n1 class c1')txt~'test 1'
buildTag e1
]e2=. 'NotATag'elm~'test <2>' NB. text alone
buildTag e2
]e=. 'tr'elm~t2,S,:t3 [ S=. 'NotATagDeep'elm~LF
buildTag e
tag e
)
... with the following result
]t1=. 'td';(_2]\;:'name n1 class c1');<'';'';'test 1'
+--+----------+----------+
|td|+-----+--+|+++------+|
| ||name |n1|||||test 1||
| |+-----+--+|+++------+|
| ||class|c1|| |
| |+-----+--+| |
+--+----------+----------+
tag t1
<td name="n1" class="c1">test 1</td>
]t2=. 'test <2>'elm'td' NB. text alone
+--++--------+
|td||test <2>|
+--++--------+
tag t2
<td>test <2></td>
]t3=. 'td'elm~(;:'name class');&>1 2
+--+---------++
|td|+-----+-+||
| ||name |1|||
| |+-----+-+||
| ||class|2|||
| |+-----+-+||
+--+---------++
tag t3
<td name="1" class="2"></td>
]t=. 'tr'elm~t1,S,t2,S,:t3 [ S=. LF elm''
+--++--------------------------+
|tr||+--+----------+----------+|
| |||td|+-----+--+|+++------+||
| ||| ||name |n1|||||test 1|||
| ||| |+-----+--+|+++------+||
| ||| ||class|c1|| ||
| ||| |+-----+--+| ||
| ||+--+----------+----------+|
| ||| | | ||
| ||+--+----------+----------+|
| |||td| |test <2> ||
| ||+--+----------+----------+|
| ||| | | ||
| ||+--+----------+----------+|
| |||td|+-----+-+ | ||
| ||| ||name |1| | ||
| ||| |+-----+-+ | ||
| ||| ||class|2| | ||
| ||| |+-----+-+ | ||
| ||+--+----------+----------+|
+--++--------------------------+
tag t
<tr><td name="n1" class="c1">test 1</td>
<td>test <2></td>
<td name="1" class="2"></td></tr>
]t=. 'br'elm~'class';'b"1"'
+--+------------++
|br|+-----+----+||
| ||class|b"1"|||
| |+-----+----+||
+--+------------++
tag t
<br class="b"1"" />
]t=. 'input'elm~'checked';''
+-----+----------++
|input|+-------++||
| ||checked||||
| |+-------++||
+-----+----------++
tag t
<input checked="checked" />
]t=. ('id';'zz') atr ('name';'zz') atr (,:~'1'elm'td') txt elm 'tr'
+--+---------+-------+
|tr|+----+--+|+--++-+|
| ||id |zz|||td||1||
| |+----+--+|+--++-+|
| ||name|zz|||td||1||
| |+----+--+|+--++-+|
+--+---------+-------+
tag t
<tr id="zz" name="zz"><td>1</td><td>1</td></tr>
]e1=. ('td'elm~_2]\;:'NotAnAttrib n1 class c1')txt~'test 1'
+--+----------------+------+
|td|+-----------+--+|test 1|
| ||NotAnAttrib|n1|| |
| |+-----------+--+| |
| ||class |c1|| |
| |+-----------+--+| |
+--+----------------+------+
buildTag e1
|NotAnAttrib: assert
| n assert(<n)e.a:,attrV,attrNV
]e2=. 'NotATag'elm~'test <2>' NB. text alone
+-------++--------+
|NotATag||test <2>|
+-------++--------+
buildTag e2
|NotATag: assert
| e assert(<e)e.tagsC,tagsNC
]e=. 'tr'elm~t1,S,t2,S,:t3 [ S=. 'NotATagDeep'elm~LF
+--++--------------------------------+
|tr||+-----------+---------+--------+|
| |||td | |test <2>||
| ||+-----------+---------+--------+|
| |||NotATagDeep| | ||
| ||+-----------+---------+--------+|
| |||td |+-----+-+| ||
| ||| ||name |1|| ||
| ||| |+-----+-+| ||
| ||| ||class|2|| ||
| ||| |+-----+-+| ||
| ||+-----------+---------+--------+|
+--++--------------------------------+
buildTag e
|NotATagDeep: assert
| e assert(<e)e.tagsC,tagsNC
tag e
|NotATagDeep: assert
| e assert(<e)e.tagsC,tagsNC
Comments
This looks interesting. With some associated nouns that listed valid names for whatever XML schema that you were using (elements with and without closing tags and valid attribute names with and without values), it may well be a good replacement for my current methods! I'll play with it a bit more.
As an aside, given that tag calls itself recursively, would the new M. primitive be appropriate here? This is more a question about M. than a suggestion.
-- RicSherlock 2007-10-29 21:08:38
I'm not sure if editing the code on someone else's wiki page is exactly kosher. If not, please feel free to revert these changes!
I have added name validation checking to the tag verb using XHTML as an example. The error messages could be numeric codes, handled by buildTag.
-- RicSherlock 2007-10-29 22:12:51
Nice improvement. In turn some polish. And a few helper structural verbs.
-- OlegKobchenko 2007-10-30 08:44:15
