Advice sought on creating XHTML from J
I'm trying to create XHTML from J arrays. Using ~system/packages/publish/web.ijs as a base, I've customized it to produce valid xhtml (webxhtml script), for example:
INPUT type 'textarea' nowrap name 'n1' class 'c1' value 'my content here' '' <input type="textarea" nowrap="nowrap" name="n1" class="c1" value="my content here" />
And:
TD name 'n1' class 'c1' 'mycontent' <td name="n1" class="c1">mycontent</td>
And I can create simple tables:
TABLE id 'mytable' LF join TR class 'r1' each ,each/"1 TD class 's1' each 8!:0 i.3 2 <table id="mytable"><tr class="r1"><td class="s1">0</td><td class="s1">1</td></tr> <tr class="r1"><td class="s1">2</td><td class="s1">3</td></tr> <tr class="r1"><td class="s1">4</td><td class="s1">5</td></tr></table>
But I want to be able to apply different tag attributes to the array as well. After some more experimentation I have created "Array" versions of the tag attributes and I can now do this:
]cells=. unbox1 TD nameA 'n1' classA ('s1';'s2';'s3') 8!:0 i.3 2
+-------------------------------+-------------------------------+
|<td name="n1" class="s1">0</td>|<td name="n1" class="s1">1</td>|
+-------------------------------+-------------------------------+
|<td name="n1" class="s2">2</td>|<td name="n1" class="s2">3</td>|
+-------------------------------+-------------------------------+
|<td name="n1" class="s3">4</td>|<td name="n1" class="s3">5</td>|
+-------------------------------+-------------------------------+
TABLE id 'mytable' LF join TR classA ('r1';'r2';'r3'),each/"1 cells
<table id="mytable"><tr class="r1"><td name="n1" class="s1">0</td><td name="n1" class="s1">1</td></tr>
<tr class="r2"><td name="n1" class="s2">2</td><td name="n1" class="s2">3</td></tr>
<tr class="r3"><td name="n1" class="s3">4</td><td name="n1" class="s3">5</td></tr></table>However can't come up with a way of having arrays for more than one attribute in a tag. I get
]cells1=. unbox1 TD nameA ('n1';'n2';'n3') classA ('s1';'s2';'s3') 8!:0 i.3 2
+-------------------------------+-------------------------------+-------------------------------+
|<td name="n1" class="s1">0</td>|<td name="n2" class="s1">0</td>|<td name="n3" class="s1">0</td>|
+-------------------------------+-------------------------------+-------------------------------+
|<td name="n1" class="s1">1</td>|<td name="n2" class="s1">1</td>|<td name="n3" class="s1">1</td>|
+-------------------------------+-------------------------------+-------------------------------+
+-------------------------------+-------------------------------+-------------------------------+
|<td name="n1" class="s2">2</td>|<td name="n2" class="s2">2</td>|<td name="n3" class="s2">2</td>|
+-------------------------------+-------------------------------+-------------------------------+
|<td name="n1" class="s2">3</td>|<td name="n2" class="s2">3</td>|<td name="n3" class="s2">3</td>|
+-------------------------------+-------------------------------+-------------------------------+
+-------------------------------+-------------------------------+-------------------------------+
|<td name="n1" class="s3">4</td>|<td name="n2" class="s3">4</td>|<td name="n3" class="s3">4</td>|
+-------------------------------+-------------------------------+-------------------------------+
|<td name="n1" class="s3">5</td>|<td name="n2" class="s3">5</td>|<td name="n3" class="s3">5</td>|
+-------------------------------+-------------------------------+-------------------------------+When what I want is:
+-------------------------------+-------------------------------+ |<td name="n1" class="s1">0</td>|<td name="n1" class="s1">1</td>| +-------------------------------+-------------------------------+ |<td name="n2" class="s2">2</td>|<td name="n2" class="s2">3</td>| +-------------------------------+-------------------------------+ |<td name="n3" class="s3">4</td>|<td name="n3" class="s3">5</td>| +-------------------------------+-------------------------------+
Definitions of the main verbs of concern are as follows. See the webxhtml script for complete definitions.
TD=: 3 : 0
'<td>',y,'</td>'
:
'<td ',x,'>',y,'</td>'
)
classA=: 2 : 0
('class=' &glue each boxopen v) u each boxopen y
:
(('class=' &glue each boxopen v),each ' ',each boxopen x) u each boxopen y
)
nameA=: 2 : 0
('name=' &glue each boxopen v) u each boxopen y
:
(('name=' &glue each boxopen v),each ' ',each boxopen x) u each boxopen y
)
glue=: , enquote@": NB. enquote just wraps string in double quotesDoes anyone have a solution to this? I'm also interested in any alternative (better?) methods of creating XML from J.
As I noted on the forums, I would achieve this end using
cell=:4 :0 'nm cl'=.x TD name nm class cl y ) ((;:'n1 n2 n3') <@,"0 ;:'s1 s2 s3') cell each 8!:0 i.3 2
As for alternative approaches:
Most xml can be represented as a list of three boxes where:
- The first box must be a string, and contains the element name.
- The second box is either empty or contains a matrix of string pairs -- attribute name and attribute value.
- The third box is either empty, a string, or a list of boxes representing xml elements.
- If the third box contains a string the first and second box must be empty (this represents a text node).
- If the first box is empty, the second box must also be empty.
- If the third box contains a list of three boxes, it should probably have a leading dimension (1) added, so that handling of the singleton case is like handling of the general case.
In other words,
<td name="n1" class="c1">mycontent</td>
could be represented as
'td';(2 2$;:'name n1 class c1');<'';'';'mycontent'
Note that all strings in this structure should have special characters (& < > ") replaced with character entities.
Note also that this structure and constraints do not deal with the doctype header at the top of an xml document, nor with CDATA.
Note also that you might want to relax the constraint that text appear only in text nodes. But, while more compact, this irregular structure seems even more difficult to process than what I proposed, above.
-- Raul Miller 2007-10-28 16:29:01
-- OlegKobchenko 2007-10-29 07:27:34
Generalising Raul's cell above I came up with the following which seems useful:
load 'convert' NB. for verb quote
enclose=: [ , ,~
NB.*buildTag v Builds array of Tags with the desired attributes and content
NB. y is boxed list of tag contents (rank 2 or less)
NB. x is 3-item boxed list of
NB. 1{ Tag name
NB. 2{ boxed list of attribute names
NB. 3{ boxed list of attribute values, Item for each attribute name
NB. (Item can be atom or boxed list of values for each item of y)
buildTag=:4 :0
'tgn attn attv'=. x
attr=. ((' 'enclose each boxopen attn),each quote each boxopen attv)
tgdefs=. ,each/"1 |: (<toupper tgn),attr
".each tgdefs ,each (' ',each quote each y)
)
('tD' ;'name';'n1') buildTag '3'
+--------------------+
|<td name="n1">3</td>|
+--------------------+
('tD' ;('name';'id';'class');< ('n1';'id1';'s3')) buildTag '3'
+----------------------------------------+
|<td name="n1" id="id1" class="s3">3</td>|
+----------------------------------------+
('TD' ;('name';'id';'class');< ((;:'n1 n2 n3') , (;:'id1 id2 id3') ,: ;:'s1 s2 s3')) buildTag 8!:0 i.3 2
+----------------------------------------+----------------------------------------+
|<td name="n1" id="id1" class="s1">0</td>|<td name="n1" id="id1" class="s1">1</td>|
+----------------------------------------+----------------------------------------+
|<td name="n2" id="id2" class="s2">2</td>|<td name="n2" id="id2" class="s2">3</td>|
+----------------------------------------+----------------------------------------+
|<td name="n3" id="id3" class="s3">4</td>|<td name="n3" id="id3" class="s3">5</td>|
+----------------------------------------+----------------------------------------+-- RicSherlock 2007-10-28 23:43:36
